@atlaskit/emoji 70.2.8 → 70.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.
- package/CHANGELOG.md +23 -0
- package/dist/cjs/api/EmojiResource.js +28 -0
- package/dist/cjs/components/i18n.js +28 -28
- package/dist/cjs/util/analytics/analytics.js +1 -1
- package/dist/cjs/util/emojiIdToEmoji.js +74 -0
- package/dist/es2019/api/EmojiResource.js +28 -0
- package/dist/es2019/components/i18n.js +28 -28
- package/dist/es2019/util/analytics/analytics.js +1 -1
- package/dist/es2019/util/emojiIdToEmoji.js +56 -0
- package/dist/esm/api/EmojiResource.js +28 -0
- package/dist/esm/components/i18n.js +28 -28
- package/dist/esm/util/analytics/analytics.js +1 -1
- package/dist/esm/util/emojiIdToEmoji.js +68 -0
- package/dist/types/api/EmojiResource.d.ts +6 -0
- package/dist/types/types.d.ts +11 -0
- package/dist/types/util/emojiIdToEmoji.d.ts +15 -0
- package/dist/types-ts4.5/api/EmojiResource.d.ts +6 -0
- package/dist/types-ts4.5/types.d.ts +11 -0
- package/dist/types-ts4.5/util/emojiIdToEmoji.d.ts +15 -0
- package/emoji-id-to-emoji/package.json +17 -0
- package/package.json +7 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @atlaskit/emoji
|
|
2
2
|
|
|
3
|
+
## 70.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`79ba3fc378726`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/79ba3fc378726) -
|
|
8
|
+
A11y fixes
|
|
9
|
+
- Updated dependencies
|
|
10
|
+
|
|
11
|
+
## 70.3.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- [`77a59d5fe3db0`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/77a59d5fe3db0) -
|
|
16
|
+
Add `getCachedEmojiType` optional method to `EmojiProvider` interface and implement it in
|
|
17
|
+
`EmojiResource` as a synchronous cache read (no network requests). Add `emojiIdToEmoji` shared
|
|
18
|
+
utility for converting hyphen-separated hex emoji IDs to Unicode strings (handles ZWJ sequences,
|
|
19
|
+
skin tone modifiers, flag sequences, keycap sequences, and variation selectors). Register
|
|
20
|
+
`platform_twemoji_removal_unicode_emojis` feature flag.
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- Updated dependencies
|
|
25
|
+
|
|
3
26
|
## 70.2.8
|
|
4
27
|
|
|
5
28
|
### Patch Changes
|
|
@@ -578,6 +578,34 @@ var EmojiResource = exports.EmojiResource = /*#__PURE__*/function (_ref) {
|
|
|
578
578
|
return _this6.findById(id);
|
|
579
579
|
}, undefined);
|
|
580
580
|
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Synchronously reads the emoji type from the local cache for the given emojiId.
|
|
584
|
+
* Returns `undefined` when the emoji is not in the cache or no repository is initialised.
|
|
585
|
+
* This is a pure cache read — no network requests are made.
|
|
586
|
+
*/
|
|
587
|
+
}, {
|
|
588
|
+
key: "getCachedEmojiType",
|
|
589
|
+
value: function getCachedEmojiType(emojiId) {
|
|
590
|
+
if (!this.isRepositoryAvailable(this.emojiRepository)) {
|
|
591
|
+
return undefined;
|
|
592
|
+
}
|
|
593
|
+
var id = emojiId.id,
|
|
594
|
+
shortName = emojiId.shortName;
|
|
595
|
+
if (id) {
|
|
596
|
+
var emoji = this.emojiRepository.findById(id);
|
|
597
|
+
if (emoji) {
|
|
598
|
+
return emoji.type;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
if (shortName) {
|
|
602
|
+
var _result = this.emojiRepository.findByShortName(shortName);
|
|
603
|
+
if (_result && !('then' in _result)) {
|
|
604
|
+
return _result.type;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
return undefined;
|
|
608
|
+
}
|
|
581
609
|
}, {
|
|
582
610
|
key: "findInCategory",
|
|
583
611
|
value: function findInCategory(categoryId) {
|
|
@@ -19,22 +19,22 @@ var messages = exports.messages = (0, _reactIntl.defineMessages)({
|
|
|
19
19
|
deleteEmojiTitle: {
|
|
20
20
|
id: 'fabric.emoji.delete.title',
|
|
21
21
|
defaultMessage: 'Remove emoji',
|
|
22
|
-
description: '
|
|
22
|
+
description: 'Heading text shown at the top of the emoji removal confirmation dialog, prompting the user to confirm removing the selected custom emoji.'
|
|
23
23
|
},
|
|
24
24
|
deleteEmojiDescription: {
|
|
25
25
|
id: 'fabric.emoji.delete.description',
|
|
26
26
|
defaultMessage: 'All existing instances of this emoji will be replaced with {emojiShortName}',
|
|
27
|
-
description: '
|
|
27
|
+
description: 'Body text shown inside the emoji removal confirmation dialog. The placeholder {emojiShortName} will be substituted with the short name (e.g. ":smile:") of the replacement emoji.'
|
|
28
28
|
},
|
|
29
29
|
deleteEmojiLabel: {
|
|
30
30
|
id: 'fabric.emoji.delete.label',
|
|
31
31
|
defaultMessage: 'Remove',
|
|
32
|
-
description: '
|
|
32
|
+
description: 'Label for the primary action button in the emoji removal confirmation dialog that confirms and executes the removal.'
|
|
33
33
|
},
|
|
34
34
|
addCustomEmojiLabel: {
|
|
35
35
|
id: 'fabric.emoji.add.custom.emoji.label',
|
|
36
36
|
defaultMessage: 'Add your own emoji',
|
|
37
|
-
description: '
|
|
37
|
+
description: 'Label for the button in the emoji picker that opens the custom emoji upload panel, allowing users to add their own emoji.'
|
|
38
38
|
},
|
|
39
39
|
emojiPlaceholder: {
|
|
40
40
|
id: 'fabric.emoji.placeholder',
|
|
@@ -49,7 +49,7 @@ var messages = exports.messages = (0, _reactIntl.defineMessages)({
|
|
|
49
49
|
emojiChooseFileTitle: {
|
|
50
50
|
id: 'fabric.emoji.choose.file.title',
|
|
51
51
|
defaultMessage: 'Choose file',
|
|
52
|
-
description: '
|
|
52
|
+
description: 'Label for the file chooser button in the custom emoji upload panel where users select an image file for their emoji.'
|
|
53
53
|
},
|
|
54
54
|
emojiChooseFileScreenReaderDescription: {
|
|
55
55
|
id: 'fabric.emoji.choose.file.screenReaderDescription',
|
|
@@ -74,37 +74,37 @@ var messages = exports.messages = (0, _reactIntl.defineMessages)({
|
|
|
74
74
|
emojiPreviewTitle: {
|
|
75
75
|
id: 'fabric.emoji.preview.title',
|
|
76
76
|
defaultMessage: 'Preview',
|
|
77
|
-
description: '
|
|
77
|
+
description: 'Section heading shown above the emoji preview area in the custom emoji upload panel.'
|
|
78
78
|
},
|
|
79
79
|
emojiPreview: {
|
|
80
80
|
id: 'fabric.emoji.preview',
|
|
81
81
|
defaultMessage: 'Your new emoji {emoji} looks great',
|
|
82
|
-
description: '
|
|
82
|
+
description: 'Success text shown in the emoji preview area after the user uploads a new emoji image. The placeholder {emoji} will be substituted with the rendered emoji image.'
|
|
83
83
|
},
|
|
84
84
|
addEmojiLabel: {
|
|
85
85
|
id: 'fabric.emoji.add.label',
|
|
86
86
|
defaultMessage: 'Add emoji',
|
|
87
|
-
description: '
|
|
87
|
+
description: 'Label for the submit button in the custom emoji upload panel that saves the new emoji to the workspace.'
|
|
88
88
|
},
|
|
89
89
|
retryLabel: {
|
|
90
90
|
id: 'fabric.emoji.retry.label',
|
|
91
91
|
defaultMessage: 'Retry',
|
|
92
|
-
description: '
|
|
92
|
+
description: 'Label for the button in the custom emoji upload panel that retries a previously failed upload attempt.'
|
|
93
93
|
},
|
|
94
94
|
cancelLabel: {
|
|
95
95
|
id: 'fabric.emoji.cancel.label',
|
|
96
96
|
defaultMessage: 'Cancel',
|
|
97
|
-
description: '
|
|
97
|
+
description: 'Label for the cancel button in the custom emoji upload panel that dismisses the panel without saving.'
|
|
98
98
|
},
|
|
99
99
|
searchPlaceholder: {
|
|
100
100
|
id: 'fabric.emoji.search.placeholder',
|
|
101
101
|
defaultMessage: 'Search',
|
|
102
|
-
description: 'Placeholder
|
|
102
|
+
description: 'Placeholder text shown inside the emoji search input field in the emoji picker before the user types a query.'
|
|
103
103
|
},
|
|
104
104
|
searchLabel: {
|
|
105
105
|
id: 'fabric.emoji.search.label',
|
|
106
106
|
defaultMessage: 'Emoji name',
|
|
107
|
-
description: '
|
|
107
|
+
description: 'Accessible label for the emoji name search input field in the emoji picker, used by screen readers.'
|
|
108
108
|
},
|
|
109
109
|
searchResultsStatus: {
|
|
110
110
|
id: 'fabric.emoji.search.status.count',
|
|
@@ -124,67 +124,67 @@ var messages = exports.messages = (0, _reactIntl.defineMessages)({
|
|
|
124
124
|
categoriesSearchResults: {
|
|
125
125
|
id: 'fabric.emoji.categories.search.results',
|
|
126
126
|
defaultMessage: 'Search results',
|
|
127
|
-
description: '
|
|
127
|
+
description: 'Category heading label shown in the emoji picker category bar when displaying results from a search query.'
|
|
128
128
|
},
|
|
129
129
|
frequentCategory: {
|
|
130
130
|
id: 'fabric.emoji.category.frequent',
|
|
131
131
|
defaultMessage: 'Frequent',
|
|
132
|
-
description: '
|
|
132
|
+
description: 'Label for the Frequent category tab in the emoji picker, showing recently used emojis.'
|
|
133
133
|
},
|
|
134
134
|
peopleCategory: {
|
|
135
135
|
id: 'fabric.emoji.category.people',
|
|
136
136
|
defaultMessage: 'People',
|
|
137
|
-
description: '
|
|
137
|
+
description: 'Label for the People category tab in the emoji picker, showing face and person emojis.'
|
|
138
138
|
},
|
|
139
139
|
natureCategory: {
|
|
140
140
|
id: 'fabric.emoji.category.nature',
|
|
141
141
|
defaultMessage: 'Nature',
|
|
142
|
-
description: '
|
|
142
|
+
description: 'Label for the Nature category tab in the emoji picker, showing animal and nature emojis.'
|
|
143
143
|
},
|
|
144
144
|
foodsCategory: {
|
|
145
145
|
id: 'fabric.emoji.category.foods',
|
|
146
146
|
defaultMessage: 'Food & Drink',
|
|
147
|
-
description: '
|
|
147
|
+
description: 'Label for the Food and Drink category tab in the emoji picker.'
|
|
148
148
|
},
|
|
149
149
|
activityCategory: {
|
|
150
150
|
id: 'fabric.emoji.category.activity',
|
|
151
151
|
defaultMessage: 'Activity',
|
|
152
|
-
description: '
|
|
152
|
+
description: 'Label for the Activity category tab in the emoji picker, showing sports and activity emojis.'
|
|
153
153
|
},
|
|
154
154
|
placesCategory: {
|
|
155
155
|
id: 'fabric.emoji.category.places',
|
|
156
156
|
defaultMessage: 'Travel & Places',
|
|
157
|
-
description: '
|
|
157
|
+
description: 'Label for the Travel and Places category tab in the emoji picker, showing location and travel emojis.'
|
|
158
158
|
},
|
|
159
159
|
objectsCategory: {
|
|
160
160
|
id: 'fabric.emoji.category.objects',
|
|
161
161
|
defaultMessage: 'Objects',
|
|
162
|
-
description: '
|
|
162
|
+
description: 'Label for the Objects category tab in the emoji picker, showing everyday object emojis.'
|
|
163
163
|
},
|
|
164
164
|
symbolsCategory: {
|
|
165
165
|
id: 'fabric.emoji.category.symbols',
|
|
166
166
|
defaultMessage: 'Symbols',
|
|
167
|
-
description: '
|
|
167
|
+
description: 'Label for the Symbols category tab in the emoji picker, showing symbol and sign emojis.'
|
|
168
168
|
},
|
|
169
169
|
flagsCategory: {
|
|
170
170
|
id: 'fabric.emoji.category.flags',
|
|
171
171
|
defaultMessage: 'Flags',
|
|
172
|
-
description: '
|
|
172
|
+
description: 'Label for the Flags category tab in the emoji picker, showing country and regional flag emojis.'
|
|
173
173
|
},
|
|
174
174
|
productivityCategory: {
|
|
175
175
|
id: 'fabric.emoji.category.productivity',
|
|
176
176
|
defaultMessage: 'Atlassian & productivity',
|
|
177
|
-
description: '
|
|
177
|
+
description: 'Label for the Atlassian and productivity category tab in the emoji picker, showing Atlassian product and productivity emojis.'
|
|
178
178
|
},
|
|
179
179
|
userUploadsCustomCategory: {
|
|
180
180
|
id: 'fabric.emoji.category.user.uploads',
|
|
181
181
|
defaultMessage: 'Your uploads',
|
|
182
|
-
description: '
|
|
182
|
+
description: 'Label for the Your Uploads category tab in the emoji picker, showing custom emojis uploaded by the current user.'
|
|
183
183
|
},
|
|
184
184
|
allUploadsCustomCategory: {
|
|
185
185
|
id: 'fabric.emoji.category.all.uploads',
|
|
186
186
|
defaultMessage: 'All uploads',
|
|
187
|
-
description: 'All
|
|
187
|
+
description: 'Label for the All Uploads category tab in the emoji picker, showing all custom emojis uploaded across the workspace.'
|
|
188
188
|
},
|
|
189
189
|
deleteEmojiFailed: {
|
|
190
190
|
id: 'fabric.emoji.error.delete.failed',
|
|
@@ -199,12 +199,12 @@ var messages = exports.messages = (0, _reactIntl.defineMessages)({
|
|
|
199
199
|
emojiUploadFailed: {
|
|
200
200
|
id: 'fabric.emoji.error.upload.failed',
|
|
201
201
|
defaultMessage: 'Upload failed',
|
|
202
|
-
description: '
|
|
202
|
+
description: 'Error message shown in the custom emoji upload panel when the image upload fails due to an error.'
|
|
203
203
|
},
|
|
204
204
|
emojiUploadTimeout: {
|
|
205
205
|
id: 'fabric.emoji.error.upload.timeout',
|
|
206
206
|
defaultMessage: 'Upload timed out',
|
|
207
|
-
description: '
|
|
207
|
+
description: 'Error message shown in the custom emoji upload panel when the image upload fails because it timed out.'
|
|
208
208
|
},
|
|
209
209
|
emojiImageTooBig: {
|
|
210
210
|
id: 'fabric.emoji.error.image.too.big',
|
|
@@ -214,7 +214,7 @@ var messages = exports.messages = (0, _reactIntl.defineMessages)({
|
|
|
214
214
|
emojiPickerTitle: {
|
|
215
215
|
id: 'fabric.emoji.picker',
|
|
216
216
|
defaultMessage: 'Emoji picker',
|
|
217
|
-
description: '
|
|
217
|
+
description: 'Accessible aria-label for the emoji picker dialog, used by screen readers to identify the picker.'
|
|
218
218
|
},
|
|
219
219
|
emojiPickerListPanel: {
|
|
220
220
|
id: 'fabric.emoji.pickerlist.tabpanel',
|
|
@@ -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.
|
|
23
|
+
packageVersion: "70.3.0"
|
|
24
24
|
}, attributes)
|
|
25
25
|
};
|
|
26
26
|
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.emojiIdToEmoji = emojiIdToEmoji;
|
|
7
|
+
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
|
+
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
|
+
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; }
|
|
10
|
+
/**
|
|
11
|
+
* Converts an emoji ID (a hyphen-separated string of hex Unicode code points,
|
|
12
|
+
* e.g. `"1f44d"`, `"1f44d-1f3fb"`, `"1f468-200d-1f469-200d-1f467"`) into its
|
|
13
|
+
* corresponding Unicode string.
|
|
14
|
+
*
|
|
15
|
+
* Special handling:
|
|
16
|
+
* - Keycap sequences: U+20E3 (COMBINING ENCLOSING KEYCAP) must be preceded by
|
|
17
|
+
* U+FE0F (VARIATION SELECTOR-16) to form a well-defined keycap emoji.
|
|
18
|
+
* - Text-default emoji (characters whose default presentation is text) must be
|
|
19
|
+
* followed by U+FE0F to force emoji presentation.
|
|
20
|
+
*
|
|
21
|
+
* @returns The Unicode string for the emoji, or `undefined` if the input is
|
|
22
|
+
* invalid (empty string, non-hex segments, or out-of-range code points).
|
|
23
|
+
*/
|
|
24
|
+
function emojiIdToEmoji(id) {
|
|
25
|
+
if (!id) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
var segments = id.split('-');
|
|
29
|
+
var codePoints = [];
|
|
30
|
+
var _iterator = _createForOfIteratorHelper(segments),
|
|
31
|
+
_step;
|
|
32
|
+
try {
|
|
33
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
34
|
+
var segment = _step.value;
|
|
35
|
+
if (!/^[0-9a-fA-F]+$/.test(segment)) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
var _cp = parseInt(segment, 16);
|
|
39
|
+
// Valid Unicode scalar values: 0x0000–0x10FFFF, excluding surrogates 0xD800–0xDFFF
|
|
40
|
+
if (isNaN(_cp) || _cp < 0 || _cp > 0x10ffff || _cp >= 0xd800 && _cp <= 0xdfff) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
codePoints.push(_cp);
|
|
44
|
+
}
|
|
45
|
+
} catch (err) {
|
|
46
|
+
_iterator.e(err);
|
|
47
|
+
} finally {
|
|
48
|
+
_iterator.f();
|
|
49
|
+
}
|
|
50
|
+
if (codePoints.length === 0) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
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
|
+
var processedCodePoints = [];
|
|
59
|
+
for (var i = 0; i < codePoints.length; i++) {
|
|
60
|
+
var cp = codePoints[i];
|
|
61
|
+
var next = codePoints[i + 1];
|
|
62
|
+
processedCodePoints.push(cp);
|
|
63
|
+
|
|
64
|
+
// Insert U+FE0F before U+20E3 if not already present
|
|
65
|
+
if (next === KEYCAP_COMBINING && cp !== VARIATION_SELECTOR_16) {
|
|
66
|
+
processedCodePoints.push(VARIATION_SELECTOR_16);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
return String.fromCodePoint.apply(String, processedCodePoints);
|
|
71
|
+
} catch (_unused) {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -373,6 +373,34 @@ export class EmojiResource extends AbstractResource {
|
|
|
373
373
|
}
|
|
374
374
|
return this.retryIfLoading(() => this.findById(id), undefined);
|
|
375
375
|
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Synchronously reads the emoji type from the local cache for the given emojiId.
|
|
379
|
+
* Returns `undefined` when the emoji is not in the cache or no repository is initialised.
|
|
380
|
+
* This is a pure cache read — no network requests are made.
|
|
381
|
+
*/
|
|
382
|
+
getCachedEmojiType(emojiId) {
|
|
383
|
+
if (!this.isRepositoryAvailable(this.emojiRepository)) {
|
|
384
|
+
return undefined;
|
|
385
|
+
}
|
|
386
|
+
const {
|
|
387
|
+
id,
|
|
388
|
+
shortName
|
|
389
|
+
} = emojiId;
|
|
390
|
+
if (id) {
|
|
391
|
+
const emoji = this.emojiRepository.findById(id);
|
|
392
|
+
if (emoji) {
|
|
393
|
+
return emoji.type;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
if (shortName) {
|
|
397
|
+
const result = this.emojiRepository.findByShortName(shortName);
|
|
398
|
+
if (result && !('then' in result)) {
|
|
399
|
+
return result.type;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
return undefined;
|
|
403
|
+
}
|
|
376
404
|
findInCategory(categoryId) {
|
|
377
405
|
if (this.isLoaded() && this.isRepositoryAvailable(this.emojiRepository)) {
|
|
378
406
|
return Promise.resolve(this.emojiRepository.findInCategory(categoryId));
|
|
@@ -13,22 +13,22 @@ export const messages = defineMessages({
|
|
|
13
13
|
deleteEmojiTitle: {
|
|
14
14
|
id: 'fabric.emoji.delete.title',
|
|
15
15
|
defaultMessage: 'Remove emoji',
|
|
16
|
-
description: '
|
|
16
|
+
description: 'Heading text shown at the top of the emoji removal confirmation dialog, prompting the user to confirm removing the selected custom emoji.'
|
|
17
17
|
},
|
|
18
18
|
deleteEmojiDescription: {
|
|
19
19
|
id: 'fabric.emoji.delete.description',
|
|
20
20
|
defaultMessage: 'All existing instances of this emoji will be replaced with {emojiShortName}',
|
|
21
|
-
description: '
|
|
21
|
+
description: 'Body text shown inside the emoji removal confirmation dialog. The placeholder {emojiShortName} will be substituted with the short name (e.g. ":smile:") of the replacement emoji.'
|
|
22
22
|
},
|
|
23
23
|
deleteEmojiLabel: {
|
|
24
24
|
id: 'fabric.emoji.delete.label',
|
|
25
25
|
defaultMessage: 'Remove',
|
|
26
|
-
description: '
|
|
26
|
+
description: 'Label for the primary action button in the emoji removal confirmation dialog that confirms and executes the removal.'
|
|
27
27
|
},
|
|
28
28
|
addCustomEmojiLabel: {
|
|
29
29
|
id: 'fabric.emoji.add.custom.emoji.label',
|
|
30
30
|
defaultMessage: 'Add your own emoji',
|
|
31
|
-
description: '
|
|
31
|
+
description: 'Label for the button in the emoji picker that opens the custom emoji upload panel, allowing users to add their own emoji.'
|
|
32
32
|
},
|
|
33
33
|
emojiPlaceholder: {
|
|
34
34
|
id: 'fabric.emoji.placeholder',
|
|
@@ -43,7 +43,7 @@ export const messages = defineMessages({
|
|
|
43
43
|
emojiChooseFileTitle: {
|
|
44
44
|
id: 'fabric.emoji.choose.file.title',
|
|
45
45
|
defaultMessage: 'Choose file',
|
|
46
|
-
description: '
|
|
46
|
+
description: 'Label for the file chooser button in the custom emoji upload panel where users select an image file for their emoji.'
|
|
47
47
|
},
|
|
48
48
|
emojiChooseFileScreenReaderDescription: {
|
|
49
49
|
id: 'fabric.emoji.choose.file.screenReaderDescription',
|
|
@@ -68,37 +68,37 @@ export const messages = defineMessages({
|
|
|
68
68
|
emojiPreviewTitle: {
|
|
69
69
|
id: 'fabric.emoji.preview.title',
|
|
70
70
|
defaultMessage: 'Preview',
|
|
71
|
-
description: '
|
|
71
|
+
description: 'Section heading shown above the emoji preview area in the custom emoji upload panel.'
|
|
72
72
|
},
|
|
73
73
|
emojiPreview: {
|
|
74
74
|
id: 'fabric.emoji.preview',
|
|
75
75
|
defaultMessage: 'Your new emoji {emoji} looks great',
|
|
76
|
-
description: '
|
|
76
|
+
description: 'Success text shown in the emoji preview area after the user uploads a new emoji image. The placeholder {emoji} will be substituted with the rendered emoji image.'
|
|
77
77
|
},
|
|
78
78
|
addEmojiLabel: {
|
|
79
79
|
id: 'fabric.emoji.add.label',
|
|
80
80
|
defaultMessage: 'Add emoji',
|
|
81
|
-
description: '
|
|
81
|
+
description: 'Label for the submit button in the custom emoji upload panel that saves the new emoji to the workspace.'
|
|
82
82
|
},
|
|
83
83
|
retryLabel: {
|
|
84
84
|
id: 'fabric.emoji.retry.label',
|
|
85
85
|
defaultMessage: 'Retry',
|
|
86
|
-
description: '
|
|
86
|
+
description: 'Label for the button in the custom emoji upload panel that retries a previously failed upload attempt.'
|
|
87
87
|
},
|
|
88
88
|
cancelLabel: {
|
|
89
89
|
id: 'fabric.emoji.cancel.label',
|
|
90
90
|
defaultMessage: 'Cancel',
|
|
91
|
-
description: '
|
|
91
|
+
description: 'Label for the cancel button in the custom emoji upload panel that dismisses the panel without saving.'
|
|
92
92
|
},
|
|
93
93
|
searchPlaceholder: {
|
|
94
94
|
id: 'fabric.emoji.search.placeholder',
|
|
95
95
|
defaultMessage: 'Search',
|
|
96
|
-
description: 'Placeholder
|
|
96
|
+
description: 'Placeholder text shown inside the emoji search input field in the emoji picker before the user types a query.'
|
|
97
97
|
},
|
|
98
98
|
searchLabel: {
|
|
99
99
|
id: 'fabric.emoji.search.label',
|
|
100
100
|
defaultMessage: 'Emoji name',
|
|
101
|
-
description: '
|
|
101
|
+
description: 'Accessible label for the emoji name search input field in the emoji picker, used by screen readers.'
|
|
102
102
|
},
|
|
103
103
|
searchResultsStatus: {
|
|
104
104
|
id: 'fabric.emoji.search.status.count',
|
|
@@ -118,67 +118,67 @@ export const messages = defineMessages({
|
|
|
118
118
|
categoriesSearchResults: {
|
|
119
119
|
id: 'fabric.emoji.categories.search.results',
|
|
120
120
|
defaultMessage: 'Search results',
|
|
121
|
-
description: '
|
|
121
|
+
description: 'Category heading label shown in the emoji picker category bar when displaying results from a search query.'
|
|
122
122
|
},
|
|
123
123
|
frequentCategory: {
|
|
124
124
|
id: 'fabric.emoji.category.frequent',
|
|
125
125
|
defaultMessage: 'Frequent',
|
|
126
|
-
description: '
|
|
126
|
+
description: 'Label for the Frequent category tab in the emoji picker, showing recently used emojis.'
|
|
127
127
|
},
|
|
128
128
|
peopleCategory: {
|
|
129
129
|
id: 'fabric.emoji.category.people',
|
|
130
130
|
defaultMessage: 'People',
|
|
131
|
-
description: '
|
|
131
|
+
description: 'Label for the People category tab in the emoji picker, showing face and person emojis.'
|
|
132
132
|
},
|
|
133
133
|
natureCategory: {
|
|
134
134
|
id: 'fabric.emoji.category.nature',
|
|
135
135
|
defaultMessage: 'Nature',
|
|
136
|
-
description: '
|
|
136
|
+
description: 'Label for the Nature category tab in the emoji picker, showing animal and nature emojis.'
|
|
137
137
|
},
|
|
138
138
|
foodsCategory: {
|
|
139
139
|
id: 'fabric.emoji.category.foods',
|
|
140
140
|
defaultMessage: 'Food & Drink',
|
|
141
|
-
description: '
|
|
141
|
+
description: 'Label for the Food and Drink category tab in the emoji picker.'
|
|
142
142
|
},
|
|
143
143
|
activityCategory: {
|
|
144
144
|
id: 'fabric.emoji.category.activity',
|
|
145
145
|
defaultMessage: 'Activity',
|
|
146
|
-
description: '
|
|
146
|
+
description: 'Label for the Activity category tab in the emoji picker, showing sports and activity emojis.'
|
|
147
147
|
},
|
|
148
148
|
placesCategory: {
|
|
149
149
|
id: 'fabric.emoji.category.places',
|
|
150
150
|
defaultMessage: 'Travel & Places',
|
|
151
|
-
description: '
|
|
151
|
+
description: 'Label for the Travel and Places category tab in the emoji picker, showing location and travel emojis.'
|
|
152
152
|
},
|
|
153
153
|
objectsCategory: {
|
|
154
154
|
id: 'fabric.emoji.category.objects',
|
|
155
155
|
defaultMessage: 'Objects',
|
|
156
|
-
description: '
|
|
156
|
+
description: 'Label for the Objects category tab in the emoji picker, showing everyday object emojis.'
|
|
157
157
|
},
|
|
158
158
|
symbolsCategory: {
|
|
159
159
|
id: 'fabric.emoji.category.symbols',
|
|
160
160
|
defaultMessage: 'Symbols',
|
|
161
|
-
description: '
|
|
161
|
+
description: 'Label for the Symbols category tab in the emoji picker, showing symbol and sign emojis.'
|
|
162
162
|
},
|
|
163
163
|
flagsCategory: {
|
|
164
164
|
id: 'fabric.emoji.category.flags',
|
|
165
165
|
defaultMessage: 'Flags',
|
|
166
|
-
description: '
|
|
166
|
+
description: 'Label for the Flags category tab in the emoji picker, showing country and regional flag emojis.'
|
|
167
167
|
},
|
|
168
168
|
productivityCategory: {
|
|
169
169
|
id: 'fabric.emoji.category.productivity',
|
|
170
170
|
defaultMessage: 'Atlassian & productivity',
|
|
171
|
-
description: '
|
|
171
|
+
description: 'Label for the Atlassian and productivity category tab in the emoji picker, showing Atlassian product and productivity emojis.'
|
|
172
172
|
},
|
|
173
173
|
userUploadsCustomCategory: {
|
|
174
174
|
id: 'fabric.emoji.category.user.uploads',
|
|
175
175
|
defaultMessage: 'Your uploads',
|
|
176
|
-
description: '
|
|
176
|
+
description: 'Label for the Your Uploads category tab in the emoji picker, showing custom emojis uploaded by the current user.'
|
|
177
177
|
},
|
|
178
178
|
allUploadsCustomCategory: {
|
|
179
179
|
id: 'fabric.emoji.category.all.uploads',
|
|
180
180
|
defaultMessage: 'All uploads',
|
|
181
|
-
description: 'All
|
|
181
|
+
description: 'Label for the All Uploads category tab in the emoji picker, showing all custom emojis uploaded across the workspace.'
|
|
182
182
|
},
|
|
183
183
|
deleteEmojiFailed: {
|
|
184
184
|
id: 'fabric.emoji.error.delete.failed',
|
|
@@ -193,12 +193,12 @@ export const messages = defineMessages({
|
|
|
193
193
|
emojiUploadFailed: {
|
|
194
194
|
id: 'fabric.emoji.error.upload.failed',
|
|
195
195
|
defaultMessage: 'Upload failed',
|
|
196
|
-
description: '
|
|
196
|
+
description: 'Error message shown in the custom emoji upload panel when the image upload fails due to an error.'
|
|
197
197
|
},
|
|
198
198
|
emojiUploadTimeout: {
|
|
199
199
|
id: 'fabric.emoji.error.upload.timeout',
|
|
200
200
|
defaultMessage: 'Upload timed out',
|
|
201
|
-
description: '
|
|
201
|
+
description: 'Error message shown in the custom emoji upload panel when the image upload fails because it timed out.'
|
|
202
202
|
},
|
|
203
203
|
emojiImageTooBig: {
|
|
204
204
|
id: 'fabric.emoji.error.image.too.big',
|
|
@@ -208,7 +208,7 @@ export const messages = defineMessages({
|
|
|
208
208
|
emojiPickerTitle: {
|
|
209
209
|
id: 'fabric.emoji.picker',
|
|
210
210
|
defaultMessage: 'Emoji picker',
|
|
211
|
-
description: '
|
|
211
|
+
description: 'Accessible aria-label for the emoji picker dialog, used by screen readers to identify the picker.'
|
|
212
212
|
},
|
|
213
213
|
emojiPickerListPanel: {
|
|
214
214
|
id: 'fabric.emoji.pickerlist.tabpanel',
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts an emoji ID (a hyphen-separated string of hex Unicode code points,
|
|
3
|
+
* e.g. `"1f44d"`, `"1f44d-1f3fb"`, `"1f468-200d-1f469-200d-1f467"`) into its
|
|
4
|
+
* corresponding Unicode string.
|
|
5
|
+
*
|
|
6
|
+
* Special handling:
|
|
7
|
+
* - Keycap sequences: U+20E3 (COMBINING ENCLOSING KEYCAP) must be preceded by
|
|
8
|
+
* U+FE0F (VARIATION SELECTOR-16) to form a well-defined keycap emoji.
|
|
9
|
+
* - Text-default emoji (characters whose default presentation is text) must be
|
|
10
|
+
* followed by U+FE0F to force emoji presentation.
|
|
11
|
+
*
|
|
12
|
+
* @returns The Unicode string for the emoji, or `undefined` if the input is
|
|
13
|
+
* invalid (empty string, non-hex segments, or out-of-range code points).
|
|
14
|
+
*/
|
|
15
|
+
export function emojiIdToEmoji(id) {
|
|
16
|
+
if (!id) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
const segments = id.split('-');
|
|
20
|
+
const codePoints = [];
|
|
21
|
+
for (const segment of segments) {
|
|
22
|
+
if (!/^[0-9a-fA-F]+$/.test(segment)) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
const cp = parseInt(segment, 16);
|
|
26
|
+
// Valid Unicode scalar values: 0x0000–0x10FFFF, excluding surrogates 0xD800–0xDFFF
|
|
27
|
+
if (isNaN(cp) || cp < 0 || cp > 0x10ffff || cp >= 0xd800 && cp <= 0xdfff) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
codePoints.push(cp);
|
|
31
|
+
}
|
|
32
|
+
if (codePoints.length === 0) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
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
|
+
const processedCodePoints = [];
|
|
41
|
+
for (let i = 0; i < codePoints.length; i++) {
|
|
42
|
+
const cp = codePoints[i];
|
|
43
|
+
const next = codePoints[i + 1];
|
|
44
|
+
processedCodePoints.push(cp);
|
|
45
|
+
|
|
46
|
+
// Insert U+FE0F before U+20E3 if not already present
|
|
47
|
+
if (next === KEYCAP_COMBINING && cp !== VARIATION_SELECTOR_16) {
|
|
48
|
+
processedCodePoints.push(VARIATION_SELECTOR_16);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
return String.fromCodePoint(...processedCodePoints);
|
|
53
|
+
} catch {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -572,6 +572,34 @@ export var EmojiResource = /*#__PURE__*/function (_ref) {
|
|
|
572
572
|
return _this6.findById(id);
|
|
573
573
|
}, undefined);
|
|
574
574
|
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Synchronously reads the emoji type from the local cache for the given emojiId.
|
|
578
|
+
* Returns `undefined` when the emoji is not in the cache or no repository is initialised.
|
|
579
|
+
* This is a pure cache read — no network requests are made.
|
|
580
|
+
*/
|
|
581
|
+
}, {
|
|
582
|
+
key: "getCachedEmojiType",
|
|
583
|
+
value: function getCachedEmojiType(emojiId) {
|
|
584
|
+
if (!this.isRepositoryAvailable(this.emojiRepository)) {
|
|
585
|
+
return undefined;
|
|
586
|
+
}
|
|
587
|
+
var id = emojiId.id,
|
|
588
|
+
shortName = emojiId.shortName;
|
|
589
|
+
if (id) {
|
|
590
|
+
var emoji = this.emojiRepository.findById(id);
|
|
591
|
+
if (emoji) {
|
|
592
|
+
return emoji.type;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
if (shortName) {
|
|
596
|
+
var _result = this.emojiRepository.findByShortName(shortName);
|
|
597
|
+
if (_result && !('then' in _result)) {
|
|
598
|
+
return _result.type;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
return undefined;
|
|
602
|
+
}
|
|
575
603
|
}, {
|
|
576
604
|
key: "findInCategory",
|
|
577
605
|
value: function findInCategory(categoryId) {
|
|
@@ -13,22 +13,22 @@ export var messages = defineMessages({
|
|
|
13
13
|
deleteEmojiTitle: {
|
|
14
14
|
id: 'fabric.emoji.delete.title',
|
|
15
15
|
defaultMessage: 'Remove emoji',
|
|
16
|
-
description: '
|
|
16
|
+
description: 'Heading text shown at the top of the emoji removal confirmation dialog, prompting the user to confirm removing the selected custom emoji.'
|
|
17
17
|
},
|
|
18
18
|
deleteEmojiDescription: {
|
|
19
19
|
id: 'fabric.emoji.delete.description',
|
|
20
20
|
defaultMessage: 'All existing instances of this emoji will be replaced with {emojiShortName}',
|
|
21
|
-
description: '
|
|
21
|
+
description: 'Body text shown inside the emoji removal confirmation dialog. The placeholder {emojiShortName} will be substituted with the short name (e.g. ":smile:") of the replacement emoji.'
|
|
22
22
|
},
|
|
23
23
|
deleteEmojiLabel: {
|
|
24
24
|
id: 'fabric.emoji.delete.label',
|
|
25
25
|
defaultMessage: 'Remove',
|
|
26
|
-
description: '
|
|
26
|
+
description: 'Label for the primary action button in the emoji removal confirmation dialog that confirms and executes the removal.'
|
|
27
27
|
},
|
|
28
28
|
addCustomEmojiLabel: {
|
|
29
29
|
id: 'fabric.emoji.add.custom.emoji.label',
|
|
30
30
|
defaultMessage: 'Add your own emoji',
|
|
31
|
-
description: '
|
|
31
|
+
description: 'Label for the button in the emoji picker that opens the custom emoji upload panel, allowing users to add their own emoji.'
|
|
32
32
|
},
|
|
33
33
|
emojiPlaceholder: {
|
|
34
34
|
id: 'fabric.emoji.placeholder',
|
|
@@ -43,7 +43,7 @@ export var messages = defineMessages({
|
|
|
43
43
|
emojiChooseFileTitle: {
|
|
44
44
|
id: 'fabric.emoji.choose.file.title',
|
|
45
45
|
defaultMessage: 'Choose file',
|
|
46
|
-
description: '
|
|
46
|
+
description: 'Label for the file chooser button in the custom emoji upload panel where users select an image file for their emoji.'
|
|
47
47
|
},
|
|
48
48
|
emojiChooseFileScreenReaderDescription: {
|
|
49
49
|
id: 'fabric.emoji.choose.file.screenReaderDescription',
|
|
@@ -68,37 +68,37 @@ export var messages = defineMessages({
|
|
|
68
68
|
emojiPreviewTitle: {
|
|
69
69
|
id: 'fabric.emoji.preview.title',
|
|
70
70
|
defaultMessage: 'Preview',
|
|
71
|
-
description: '
|
|
71
|
+
description: 'Section heading shown above the emoji preview area in the custom emoji upload panel.'
|
|
72
72
|
},
|
|
73
73
|
emojiPreview: {
|
|
74
74
|
id: 'fabric.emoji.preview',
|
|
75
75
|
defaultMessage: 'Your new emoji {emoji} looks great',
|
|
76
|
-
description: '
|
|
76
|
+
description: 'Success text shown in the emoji preview area after the user uploads a new emoji image. The placeholder {emoji} will be substituted with the rendered emoji image.'
|
|
77
77
|
},
|
|
78
78
|
addEmojiLabel: {
|
|
79
79
|
id: 'fabric.emoji.add.label',
|
|
80
80
|
defaultMessage: 'Add emoji',
|
|
81
|
-
description: '
|
|
81
|
+
description: 'Label for the submit button in the custom emoji upload panel that saves the new emoji to the workspace.'
|
|
82
82
|
},
|
|
83
83
|
retryLabel: {
|
|
84
84
|
id: 'fabric.emoji.retry.label',
|
|
85
85
|
defaultMessage: 'Retry',
|
|
86
|
-
description: '
|
|
86
|
+
description: 'Label for the button in the custom emoji upload panel that retries a previously failed upload attempt.'
|
|
87
87
|
},
|
|
88
88
|
cancelLabel: {
|
|
89
89
|
id: 'fabric.emoji.cancel.label',
|
|
90
90
|
defaultMessage: 'Cancel',
|
|
91
|
-
description: '
|
|
91
|
+
description: 'Label for the cancel button in the custom emoji upload panel that dismisses the panel without saving.'
|
|
92
92
|
},
|
|
93
93
|
searchPlaceholder: {
|
|
94
94
|
id: 'fabric.emoji.search.placeholder',
|
|
95
95
|
defaultMessage: 'Search',
|
|
96
|
-
description: 'Placeholder
|
|
96
|
+
description: 'Placeholder text shown inside the emoji search input field in the emoji picker before the user types a query.'
|
|
97
97
|
},
|
|
98
98
|
searchLabel: {
|
|
99
99
|
id: 'fabric.emoji.search.label',
|
|
100
100
|
defaultMessage: 'Emoji name',
|
|
101
|
-
description: '
|
|
101
|
+
description: 'Accessible label for the emoji name search input field in the emoji picker, used by screen readers.'
|
|
102
102
|
},
|
|
103
103
|
searchResultsStatus: {
|
|
104
104
|
id: 'fabric.emoji.search.status.count',
|
|
@@ -118,67 +118,67 @@ export var messages = defineMessages({
|
|
|
118
118
|
categoriesSearchResults: {
|
|
119
119
|
id: 'fabric.emoji.categories.search.results',
|
|
120
120
|
defaultMessage: 'Search results',
|
|
121
|
-
description: '
|
|
121
|
+
description: 'Category heading label shown in the emoji picker category bar when displaying results from a search query.'
|
|
122
122
|
},
|
|
123
123
|
frequentCategory: {
|
|
124
124
|
id: 'fabric.emoji.category.frequent',
|
|
125
125
|
defaultMessage: 'Frequent',
|
|
126
|
-
description: '
|
|
126
|
+
description: 'Label for the Frequent category tab in the emoji picker, showing recently used emojis.'
|
|
127
127
|
},
|
|
128
128
|
peopleCategory: {
|
|
129
129
|
id: 'fabric.emoji.category.people',
|
|
130
130
|
defaultMessage: 'People',
|
|
131
|
-
description: '
|
|
131
|
+
description: 'Label for the People category tab in the emoji picker, showing face and person emojis.'
|
|
132
132
|
},
|
|
133
133
|
natureCategory: {
|
|
134
134
|
id: 'fabric.emoji.category.nature',
|
|
135
135
|
defaultMessage: 'Nature',
|
|
136
|
-
description: '
|
|
136
|
+
description: 'Label for the Nature category tab in the emoji picker, showing animal and nature emojis.'
|
|
137
137
|
},
|
|
138
138
|
foodsCategory: {
|
|
139
139
|
id: 'fabric.emoji.category.foods',
|
|
140
140
|
defaultMessage: 'Food & Drink',
|
|
141
|
-
description: '
|
|
141
|
+
description: 'Label for the Food and Drink category tab in the emoji picker.'
|
|
142
142
|
},
|
|
143
143
|
activityCategory: {
|
|
144
144
|
id: 'fabric.emoji.category.activity',
|
|
145
145
|
defaultMessage: 'Activity',
|
|
146
|
-
description: '
|
|
146
|
+
description: 'Label for the Activity category tab in the emoji picker, showing sports and activity emojis.'
|
|
147
147
|
},
|
|
148
148
|
placesCategory: {
|
|
149
149
|
id: 'fabric.emoji.category.places',
|
|
150
150
|
defaultMessage: 'Travel & Places',
|
|
151
|
-
description: '
|
|
151
|
+
description: 'Label for the Travel and Places category tab in the emoji picker, showing location and travel emojis.'
|
|
152
152
|
},
|
|
153
153
|
objectsCategory: {
|
|
154
154
|
id: 'fabric.emoji.category.objects',
|
|
155
155
|
defaultMessage: 'Objects',
|
|
156
|
-
description: '
|
|
156
|
+
description: 'Label for the Objects category tab in the emoji picker, showing everyday object emojis.'
|
|
157
157
|
},
|
|
158
158
|
symbolsCategory: {
|
|
159
159
|
id: 'fabric.emoji.category.symbols',
|
|
160
160
|
defaultMessage: 'Symbols',
|
|
161
|
-
description: '
|
|
161
|
+
description: 'Label for the Symbols category tab in the emoji picker, showing symbol and sign emojis.'
|
|
162
162
|
},
|
|
163
163
|
flagsCategory: {
|
|
164
164
|
id: 'fabric.emoji.category.flags',
|
|
165
165
|
defaultMessage: 'Flags',
|
|
166
|
-
description: '
|
|
166
|
+
description: 'Label for the Flags category tab in the emoji picker, showing country and regional flag emojis.'
|
|
167
167
|
},
|
|
168
168
|
productivityCategory: {
|
|
169
169
|
id: 'fabric.emoji.category.productivity',
|
|
170
170
|
defaultMessage: 'Atlassian & productivity',
|
|
171
|
-
description: '
|
|
171
|
+
description: 'Label for the Atlassian and productivity category tab in the emoji picker, showing Atlassian product and productivity emojis.'
|
|
172
172
|
},
|
|
173
173
|
userUploadsCustomCategory: {
|
|
174
174
|
id: 'fabric.emoji.category.user.uploads',
|
|
175
175
|
defaultMessage: 'Your uploads',
|
|
176
|
-
description: '
|
|
176
|
+
description: 'Label for the Your Uploads category tab in the emoji picker, showing custom emojis uploaded by the current user.'
|
|
177
177
|
},
|
|
178
178
|
allUploadsCustomCategory: {
|
|
179
179
|
id: 'fabric.emoji.category.all.uploads',
|
|
180
180
|
defaultMessage: 'All uploads',
|
|
181
|
-
description: 'All
|
|
181
|
+
description: 'Label for the All Uploads category tab in the emoji picker, showing all custom emojis uploaded across the workspace.'
|
|
182
182
|
},
|
|
183
183
|
deleteEmojiFailed: {
|
|
184
184
|
id: 'fabric.emoji.error.delete.failed',
|
|
@@ -193,12 +193,12 @@ export var messages = defineMessages({
|
|
|
193
193
|
emojiUploadFailed: {
|
|
194
194
|
id: 'fabric.emoji.error.upload.failed',
|
|
195
195
|
defaultMessage: 'Upload failed',
|
|
196
|
-
description: '
|
|
196
|
+
description: 'Error message shown in the custom emoji upload panel when the image upload fails due to an error.'
|
|
197
197
|
},
|
|
198
198
|
emojiUploadTimeout: {
|
|
199
199
|
id: 'fabric.emoji.error.upload.timeout',
|
|
200
200
|
defaultMessage: 'Upload timed out',
|
|
201
|
-
description: '
|
|
201
|
+
description: 'Error message shown in the custom emoji upload panel when the image upload fails because it timed out.'
|
|
202
202
|
},
|
|
203
203
|
emojiImageTooBig: {
|
|
204
204
|
id: 'fabric.emoji.error.image.too.big',
|
|
@@ -208,7 +208,7 @@ export var messages = defineMessages({
|
|
|
208
208
|
emojiPickerTitle: {
|
|
209
209
|
id: 'fabric.emoji.picker',
|
|
210
210
|
defaultMessage: 'Emoji picker',
|
|
211
|
-
description: '
|
|
211
|
+
description: 'Accessible aria-label for the emoji picker dialog, used by screen readers to identify the picker.'
|
|
212
212
|
},
|
|
213
213
|
emojiPickerListPanel: {
|
|
214
214
|
id: 'fabric.emoji.pickerlist.tabpanel',
|
|
@@ -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.
|
|
17
|
+
packageVersion: "70.3.0"
|
|
18
18
|
}, attributes)
|
|
19
19
|
};
|
|
20
20
|
};
|
|
@@ -0,0 +1,68 @@
|
|
|
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
|
+
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
|
+
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
|
+
/**
|
|
5
|
+
* Converts an emoji ID (a hyphen-separated string of hex Unicode code points,
|
|
6
|
+
* e.g. `"1f44d"`, `"1f44d-1f3fb"`, `"1f468-200d-1f469-200d-1f467"`) into its
|
|
7
|
+
* corresponding Unicode string.
|
|
8
|
+
*
|
|
9
|
+
* Special handling:
|
|
10
|
+
* - Keycap sequences: U+20E3 (COMBINING ENCLOSING KEYCAP) must be preceded by
|
|
11
|
+
* U+FE0F (VARIATION SELECTOR-16) to form a well-defined keycap emoji.
|
|
12
|
+
* - Text-default emoji (characters whose default presentation is text) must be
|
|
13
|
+
* followed by U+FE0F to force emoji presentation.
|
|
14
|
+
*
|
|
15
|
+
* @returns The Unicode string for the emoji, or `undefined` if the input is
|
|
16
|
+
* invalid (empty string, non-hex segments, or out-of-range code points).
|
|
17
|
+
*/
|
|
18
|
+
export function emojiIdToEmoji(id) {
|
|
19
|
+
if (!id) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
var segments = id.split('-');
|
|
23
|
+
var codePoints = [];
|
|
24
|
+
var _iterator = _createForOfIteratorHelper(segments),
|
|
25
|
+
_step;
|
|
26
|
+
try {
|
|
27
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
28
|
+
var segment = _step.value;
|
|
29
|
+
if (!/^[0-9a-fA-F]+$/.test(segment)) {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
var _cp = parseInt(segment, 16);
|
|
33
|
+
// Valid Unicode scalar values: 0x0000–0x10FFFF, excluding surrogates 0xD800–0xDFFF
|
|
34
|
+
if (isNaN(_cp) || _cp < 0 || _cp > 0x10ffff || _cp >= 0xd800 && _cp <= 0xdfff) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
codePoints.push(_cp);
|
|
38
|
+
}
|
|
39
|
+
} catch (err) {
|
|
40
|
+
_iterator.e(err);
|
|
41
|
+
} finally {
|
|
42
|
+
_iterator.f();
|
|
43
|
+
}
|
|
44
|
+
if (codePoints.length === 0) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
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
|
+
var processedCodePoints = [];
|
|
53
|
+
for (var i = 0; i < codePoints.length; i++) {
|
|
54
|
+
var cp = codePoints[i];
|
|
55
|
+
var next = codePoints[i + 1];
|
|
56
|
+
processedCodePoints.push(cp);
|
|
57
|
+
|
|
58
|
+
// Insert U+FE0F before U+20E3 if not already present
|
|
59
|
+
if (next === KEYCAP_COMBINING && cp !== VARIATION_SELECTOR_16) {
|
|
60
|
+
processedCodePoints.push(VARIATION_SELECTOR_16);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
return String.fromCodePoint.apply(String, processedCodePoints);
|
|
65
|
+
} catch (_unused) {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -127,6 +127,12 @@ export declare class EmojiResource extends AbstractResource<string, EmojiSearchR
|
|
|
127
127
|
findByShortName(shortName: string): OptionalEmojiDescription | Promise<OptionalEmojiDescription>;
|
|
128
128
|
findByEmojiId(emojiId: EmojiId): OptionalEmojiDescription | Promise<OptionalEmojiDescription>;
|
|
129
129
|
findById(id: string): OptionalEmojiDescription | Promise<OptionalEmojiDescription>;
|
|
130
|
+
/**
|
|
131
|
+
* Synchronously reads the emoji type from the local cache for the given emojiId.
|
|
132
|
+
* Returns `undefined` when the emoji is not in the cache or no repository is initialised.
|
|
133
|
+
* This is a pure cache read — no network requests are made.
|
|
134
|
+
*/
|
|
135
|
+
getCachedEmojiType(emojiId: EmojiId): string | undefined;
|
|
130
136
|
findInCategory(categoryId: CategoryId): Promise<EmojiDescription[]>;
|
|
131
137
|
getAsciiMap(): Promise<Map<string, EmojiDescription>>;
|
|
132
138
|
getFrequentlyUsed(options?: SearchOptions): Promise<EmojiDescription[]>;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -81,6 +81,17 @@ export interface EmojiProvider extends Provider<string, EmojiSearchResult, any,
|
|
|
81
81
|
* Returns a constructed URL to fetch emoji media asset if 'optimisticImageApi' config has been provided
|
|
82
82
|
*/
|
|
83
83
|
getOptimisticImageURL(emojiId: EmojiId): string | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* Synchronously reads the emoji type (e.g. 'STANDARD', 'SITE', 'ATLASSIAN') from the
|
|
86
|
+
* local cache for the given emojiId, without making any network requests.
|
|
87
|
+
*
|
|
88
|
+
* Returns `undefined` when the emoji is not yet in the cache or no repository has been
|
|
89
|
+
* initialised. This is an optional method — callers must fall back gracefully when it is
|
|
90
|
+
* absent (e.g. in mock or legacy providers).
|
|
91
|
+
*
|
|
92
|
+
* Optional.
|
|
93
|
+
*/
|
|
94
|
+
getCachedEmojiType?(emojiId: EmojiId): string | undefined;
|
|
84
95
|
/**
|
|
85
96
|
* Used by the picker and typeahead to obtain a skin tone preference
|
|
86
97
|
* if the user has previously selected one via the Tone Selector
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts an emoji ID (a hyphen-separated string of hex Unicode code points,
|
|
3
|
+
* e.g. `"1f44d"`, `"1f44d-1f3fb"`, `"1f468-200d-1f469-200d-1f467"`) into its
|
|
4
|
+
* corresponding Unicode string.
|
|
5
|
+
*
|
|
6
|
+
* Special handling:
|
|
7
|
+
* - Keycap sequences: U+20E3 (COMBINING ENCLOSING KEYCAP) must be preceded by
|
|
8
|
+
* U+FE0F (VARIATION SELECTOR-16) to form a well-defined keycap emoji.
|
|
9
|
+
* - Text-default emoji (characters whose default presentation is text) must be
|
|
10
|
+
* followed by U+FE0F to force emoji presentation.
|
|
11
|
+
*
|
|
12
|
+
* @returns The Unicode string for the emoji, or `undefined` if the input is
|
|
13
|
+
* invalid (empty string, non-hex segments, or out-of-range code points).
|
|
14
|
+
*/
|
|
15
|
+
export declare function emojiIdToEmoji(id: string): string | undefined;
|
|
@@ -127,6 +127,12 @@ export declare class EmojiResource extends AbstractResource<string, EmojiSearchR
|
|
|
127
127
|
findByShortName(shortName: string): OptionalEmojiDescription | Promise<OptionalEmojiDescription>;
|
|
128
128
|
findByEmojiId(emojiId: EmojiId): OptionalEmojiDescription | Promise<OptionalEmojiDescription>;
|
|
129
129
|
findById(id: string): OptionalEmojiDescription | Promise<OptionalEmojiDescription>;
|
|
130
|
+
/**
|
|
131
|
+
* Synchronously reads the emoji type from the local cache for the given emojiId.
|
|
132
|
+
* Returns `undefined` when the emoji is not in the cache or no repository is initialised.
|
|
133
|
+
* This is a pure cache read — no network requests are made.
|
|
134
|
+
*/
|
|
135
|
+
getCachedEmojiType(emojiId: EmojiId): string | undefined;
|
|
130
136
|
findInCategory(categoryId: CategoryId): Promise<EmojiDescription[]>;
|
|
131
137
|
getAsciiMap(): Promise<Map<string, EmojiDescription>>;
|
|
132
138
|
getFrequentlyUsed(options?: SearchOptions): Promise<EmojiDescription[]>;
|
|
@@ -81,6 +81,17 @@ export interface EmojiProvider extends Provider<string, EmojiSearchResult, any,
|
|
|
81
81
|
* Returns a constructed URL to fetch emoji media asset if 'optimisticImageApi' config has been provided
|
|
82
82
|
*/
|
|
83
83
|
getOptimisticImageURL(emojiId: EmojiId): string | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* Synchronously reads the emoji type (e.g. 'STANDARD', 'SITE', 'ATLASSIAN') from the
|
|
86
|
+
* local cache for the given emojiId, without making any network requests.
|
|
87
|
+
*
|
|
88
|
+
* Returns `undefined` when the emoji is not yet in the cache or no repository has been
|
|
89
|
+
* initialised. This is an optional method — callers must fall back gracefully when it is
|
|
90
|
+
* absent (e.g. in mock or legacy providers).
|
|
91
|
+
*
|
|
92
|
+
* Optional.
|
|
93
|
+
*/
|
|
94
|
+
getCachedEmojiType?(emojiId: EmojiId): string | undefined;
|
|
84
95
|
/**
|
|
85
96
|
* Used by the picker and typeahead to obtain a skin tone preference
|
|
86
97
|
* if the user has previously selected one via the Tone Selector
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts an emoji ID (a hyphen-separated string of hex Unicode code points,
|
|
3
|
+
* e.g. `"1f44d"`, `"1f44d-1f3fb"`, `"1f468-200d-1f469-200d-1f467"`) into its
|
|
4
|
+
* corresponding Unicode string.
|
|
5
|
+
*
|
|
6
|
+
* Special handling:
|
|
7
|
+
* - Keycap sequences: U+20E3 (COMBINING ENCLOSING KEYCAP) must be preceded by
|
|
8
|
+
* U+FE0F (VARIATION SELECTOR-16) to form a well-defined keycap emoji.
|
|
9
|
+
* - Text-default emoji (characters whose default presentation is text) must be
|
|
10
|
+
* followed by U+FE0F to force emoji presentation.
|
|
11
|
+
*
|
|
12
|
+
* @returns The Unicode string for the emoji, or `undefined` if the input is
|
|
13
|
+
* invalid (empty string, non-hex segments, or out-of-range code points).
|
|
14
|
+
*/
|
|
15
|
+
export declare function emojiIdToEmoji(id: string): string | undefined;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@atlaskit/emoji/emoji-id-to-emoji",
|
|
3
|
+
"main": "../dist/cjs/util/emojiIdToEmoji.js",
|
|
4
|
+
"module": "../dist/esm/util/emojiIdToEmoji.js",
|
|
5
|
+
"module:es2019": "../dist/es2019/util/emojiIdToEmoji.js",
|
|
6
|
+
"sideEffects": [
|
|
7
|
+
"*.compiled.css"
|
|
8
|
+
],
|
|
9
|
+
"types": "../dist/types/util/emojiIdToEmoji.d.ts",
|
|
10
|
+
"typesVersions": {
|
|
11
|
+
">=4.5 <5.9": {
|
|
12
|
+
"*": [
|
|
13
|
+
"../dist/types-ts4.5/util/emojiIdToEmoji.d.ts"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/emoji",
|
|
3
|
-
"version": "70.
|
|
3
|
+
"version": "70.3.1",
|
|
4
4
|
"description": "Fabric emoji React components",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
"@atlaskit/primitives": "^19.0.0",
|
|
50
50
|
"@atlaskit/spinner": "^19.1.0",
|
|
51
51
|
"@atlaskit/textfield": "^8.3.0",
|
|
52
|
-
"@atlaskit/tmp-editor-statsig": "^74.
|
|
52
|
+
"@atlaskit/tmp-editor-statsig": "^74.8.0",
|
|
53
53
|
"@atlaskit/tokens": "^13.0.0",
|
|
54
|
-
"@atlaskit/tooltip": "^
|
|
54
|
+
"@atlaskit/tooltip": "^22.0.0",
|
|
55
55
|
"@atlaskit/ufo": "^0.4.0",
|
|
56
56
|
"@atlaskit/util-service-support": "^6.3.0",
|
|
57
|
-
"@atlaskit/visually-hidden": "^3.
|
|
57
|
+
"@atlaskit/visually-hidden": "^3.1.0",
|
|
58
58
|
"@babel/runtime": "^7.0.0",
|
|
59
59
|
"@compiled/react": "^0.20.0",
|
|
60
60
|
"@tanstack/react-virtual": "3.0.0-beta.60",
|
|
@@ -116,6 +116,9 @@
|
|
|
116
116
|
}
|
|
117
117
|
},
|
|
118
118
|
"platform-feature-flags": {
|
|
119
|
+
"platform_twemoji_removal_unicode_emojis": {
|
|
120
|
+
"type": "boolean"
|
|
121
|
+
},
|
|
119
122
|
"platform_index_emoji_just_in_time": {
|
|
120
123
|
"type": "boolean"
|
|
121
124
|
},
|