@atlaskit/emoji 71.0.0 → 71.1.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.
Files changed (60) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/afm-cc/tsconfig.json +3 -0
  3. package/afm-products/tsconfig.json +3 -0
  4. package/dist/cjs/components/common/Emoji.js +141 -5
  5. package/dist/cjs/components/common/EmojiActions.compiled.css +8 -0
  6. package/dist/cjs/components/common/EmojiActions.js +69 -3
  7. package/dist/cjs/components/common/Popup.js +20 -5
  8. package/dist/cjs/components/common/ProductivityColorSelector.compiled.css +59 -0
  9. package/dist/cjs/components/common/ProductivityColorSelector.js +112 -0
  10. package/dist/cjs/components/common/ResourcedEmojiComponent.js +4 -1
  11. package/dist/cjs/components/common/TonePreviewButton.js +4 -2
  12. package/dist/cjs/components/i18n.js +10 -0
  13. package/dist/cjs/components/picker/EmojiPickerComponent.js +51 -36
  14. package/dist/cjs/components/picker/EmojiPickerList.js +36 -14
  15. package/dist/cjs/components/picker/VirtualList.js +4 -5
  16. package/dist/cjs/util/analytics/analytics.js +1 -1
  17. package/dist/cjs/util/hidden-emojis.js +33 -0
  18. package/dist/cjs/util/productivity-colors.js +51 -0
  19. package/dist/es2019/components/common/Emoji.js +115 -5
  20. package/dist/es2019/components/common/EmojiActions.compiled.css +8 -0
  21. package/dist/es2019/components/common/EmojiActions.js +67 -3
  22. package/dist/es2019/components/common/Popup.js +19 -5
  23. package/dist/es2019/components/common/ProductivityColorSelector.compiled.css +59 -0
  24. package/dist/es2019/components/common/ProductivityColorSelector.js +98 -0
  25. package/dist/es2019/components/common/ResourcedEmojiComponent.js +3 -1
  26. package/dist/es2019/components/common/TonePreviewButton.js +3 -2
  27. package/dist/es2019/components/i18n.js +10 -0
  28. package/dist/es2019/components/picker/EmojiPickerComponent.js +26 -14
  29. package/dist/es2019/components/picker/EmojiPickerList.js +32 -14
  30. package/dist/es2019/components/picker/VirtualList.js +4 -5
  31. package/dist/es2019/util/analytics/analytics.js +1 -1
  32. package/dist/es2019/util/hidden-emojis.js +25 -0
  33. package/dist/es2019/util/productivity-colors.js +37 -0
  34. package/dist/esm/components/common/Emoji.js +142 -6
  35. package/dist/esm/components/common/EmojiActions.compiled.css +8 -0
  36. package/dist/esm/components/common/EmojiActions.js +70 -4
  37. package/dist/esm/components/common/Popup.js +20 -5
  38. package/dist/esm/components/common/ProductivityColorSelector.compiled.css +59 -0
  39. package/dist/esm/components/common/ProductivityColorSelector.js +103 -0
  40. package/dist/esm/components/common/ResourcedEmojiComponent.js +4 -1
  41. package/dist/esm/components/common/TonePreviewButton.js +4 -2
  42. package/dist/esm/components/i18n.js +10 -0
  43. package/dist/esm/components/picker/EmojiPickerComponent.js +51 -36
  44. package/dist/esm/components/picker/EmojiPickerList.js +36 -14
  45. package/dist/esm/components/picker/VirtualList.js +4 -5
  46. package/dist/esm/util/analytics/analytics.js +1 -1
  47. package/dist/esm/util/hidden-emojis.js +27 -0
  48. package/dist/esm/util/productivity-colors.js +45 -0
  49. package/dist/types/components/common/Emoji.d.ts +5 -0
  50. package/dist/types/components/common/EmojiActions.d.ts +6 -0
  51. package/dist/types/components/common/Popup.d.ts +1 -0
  52. package/dist/types/components/common/ProductivityColorSelector.d.ts +17 -0
  53. package/dist/types/components/common/ResourcedEmojiComponent.d.ts +6 -1
  54. package/dist/types/components/common/TonePreviewButton.d.ts +1 -0
  55. package/dist/types/components/i18n.d.ts +10 -0
  56. package/dist/types/components/picker/EmojiPickerList.d.ts +3 -0
  57. package/dist/types/types.d.ts +7 -0
  58. package/dist/types/util/hidden-emojis.d.ts +3 -0
  59. package/dist/types/util/productivity-colors.d.ts +8 -0
  60. package/package.json +3 -2
@@ -26,6 +26,8 @@ import { createAndFireEventInElementsChannel, categoryClickedEvent, closedPicker
26
26
  import { useEmoji } from '../../hooks/useEmoji';
27
27
  import { useIsMounted } from '../../hooks/useIsMounted';
28
28
  import { messages } from '../i18n';
29
+ import { defaultProductivityColor } from '../../util/productivity-colors';
30
+ import { filterHiddenEmojis } from '../../util/hidden-emojis';
29
31
  const emojiPickerBoxShadow = "var(--ds-shadow-overlay, 0px 8px 12px #1E1F2126, 0px 0px 1px #1E1F214f)";
30
32
  const emojiPickerHeight = 295;
31
33
  const emojiPickerHeightWithPreview = 349; // emojiPickerHeight + emojiPickerPreviewHeight;
@@ -78,12 +80,14 @@ const EmojiPickerComponent = ({
78
80
  emojiProvider,
79
81
  isUploadSupported
80
82
  } = useEmoji();
83
+ const isTeamojiExperimentEnabled = FeatureGates.getExperimentValue('platform_teamoji_26_refresh_emoji_picker', 'isEnabled', false);
81
84
  const [filteredEmojis, setFilteredEmojis] = useState([]);
82
85
  const [searchEmojis, setSearchEmojis] = useState([]);
83
86
  const [frequentlyUsedEmojis, setFrequentlyUsedEmojis] = useState([]);
84
87
  const [query, setQuery] = useState('');
85
88
  const [dynamicCategories, setDynamicCategories] = useState([]);
86
89
  const [selectedTone, setSelectedTone] = useState(!hideToneSelector ? emojiProvider.getSelectedTone() : undefined);
90
+ const [selectedProductivityColor, setSelectedProductivityColor] = useState(defaultProductivityColor);
87
91
  const [loading, setLoading] = useState(true);
88
92
  const [uploading, setUploading] = useState(false);
89
93
  const [selectedEmoji, setSelectedEmoji] = useState();
@@ -100,11 +104,11 @@ const EmojiPickerComponent = ({
100
104
  const isProgrammaticScroll = useRef(false);
101
105
  const pickerRef = useRef(null);
102
106
  const setPickerRef = useCallback(el => {
103
- if (FeatureGates.getExperimentValue('platform_teamoji_26_refresh_emoji_picker', 'isEnabled', false)) {
107
+ if (isTeamojiExperimentEnabled) {
104
108
  pickerRef.current = el;
105
109
  }
106
110
  onPickerRef === null || onPickerRef === void 0 ? void 0 : onPickerRef(el);
107
- }, [onPickerRef]);
111
+ }, [isTeamojiExperimentEnabled, onPickerRef]);
108
112
  const currentUser = useMemo(() => {
109
113
  return emojiProvider.getCurrentUser();
110
114
  }, [emojiProvider]);
@@ -206,7 +210,8 @@ const EmojiPickerComponent = ({
206
210
  }, [filteredEmojis.length, getDynamicCategories, onDynamicCategoryChange, selectedEmoji]);
207
211
  const onFrequentEmojiResult = useCallback(frequentEmoji => {
208
212
  // change the category of each of the featured emoji
209
- const recategorised = frequentEmoji.map(emoji => {
213
+ const visibleFrequentEmoji = isTeamojiExperimentEnabled ? filterHiddenEmojis(frequentEmoji) : frequentEmoji;
214
+ const recategorised = visibleFrequentEmoji.map(emoji => {
210
215
  const clone = JSON.parse(JSON.stringify(emoji));
211
216
  clone.category = frequentCategory;
212
217
  return clone;
@@ -214,10 +219,11 @@ const EmojiPickerComponent = ({
214
219
  setStateAfterEmojiChange({
215
220
  frequentEmoji: recategorised
216
221
  });
217
- }, [setStateAfterEmojiChange]);
222
+ }, [isTeamojiExperimentEnabled, setStateAfterEmojiChange]);
218
223
  const onSearchResult = useCallback(searchResults => {
219
224
  const frequentlyUsedEmoji = frequentlyUsedEmojis || [];
220
225
  const searchQuery = searchResults.query || '';
226
+ const visibleSearchEmojis = isTeamojiExperimentEnabled ? filterHiddenEmojis(searchResults.emojis) : searchResults.emojis;
221
227
 
222
228
  /**
223
229
  * If there is no user search in the EmojiPicker then it should display all emoji received from the EmojiRepository and should
@@ -226,20 +232,20 @@ const EmojiPickerComponent = ({
226
232
  */
227
233
  let emojiToRender;
228
234
  if (!frequentlyUsedEmoji.length || query) {
229
- emojiToRender = searchResults.emojis;
235
+ emojiToRender = visibleSearchEmojis;
230
236
  } else {
231
- emojiToRender = [...searchResults.emojis, ...frequentlyUsedEmoji];
237
+ emojiToRender = [...visibleSearchEmojis, ...frequentlyUsedEmoji];
232
238
  }
233
239
  setStateAfterEmojiChange({
234
240
  searchQuery,
235
241
  emojiToRender,
236
- searchEmoji: searchResults.emojis
242
+ searchEmoji: visibleSearchEmojis
237
243
  });
238
244
  fireAnalytics(pickerSearchedEvent({
239
245
  queryLength: searchQuery.length,
240
- numMatches: searchResults.emojis.length
246
+ numMatches: visibleSearchEmojis.length
241
247
  }));
242
- }, [frequentlyUsedEmojis, query, setStateAfterEmojiChange, fireAnalytics]);
248
+ }, [frequentlyUsedEmojis, isTeamojiExperimentEnabled, query, setStateAfterEmojiChange, fireAnalytics]);
243
249
  const onProviderChange = useMemo(() => {
244
250
  return {
245
251
  result: onSearchResult
@@ -282,6 +288,9 @@ const EmojiPickerComponent = ({
282
288
  const onToneSelectorCancelled = useCallback(() => {
283
289
  fireAnalytics(toneSelectorClosedEvent());
284
290
  }, [fireAnalytics]);
291
+ const onProductivityColorSelected = useCallback(color => {
292
+ setSelectedProductivityColor(color);
293
+ }, []);
285
294
  const onSelectWrapper = useCallback((emojiId, emoji, event) => {
286
295
  if (onSelection) {
287
296
  onSelection(emojiId, emoji, event);
@@ -312,17 +321,18 @@ const EmojiPickerComponent = ({
312
321
  emojiProvider.findInCategory(categoryId).then(emojisInCategory => {
313
322
  if (!disableCategories) {
314
323
  let newSelectedEmoji;
315
- if (emojisInCategory && emojisInCategory.length > 0) {
316
- newSelectedEmoji = getEmojiVariation(emojisInCategory[0], {
324
+ const visibleEmojisInCategory = isTeamojiExperimentEnabled ? filterHiddenEmojis(emojisInCategory || []) : emojisInCategory || [];
325
+ if (visibleEmojisInCategory.length > 0) {
326
+ newSelectedEmoji = getEmojiVariation(visibleEmojisInCategory[0], {
317
327
  skinTone: selectedTone
318
328
  });
319
329
  }
320
330
  if (emojiPickerList.current) {
321
- if (FeatureGates.getExperimentValue('platform_teamoji_26_refresh_emoji_picker', 'isEnabled', false)) {
331
+ if (isTeamojiExperimentEnabled) {
322
332
  isProgrammaticScroll.current = true;
323
333
  }
324
334
  emojiPickerList.current.reveal(categoryId);
325
- if (FeatureGates.getExperimentValue('platform_teamoji_26_refresh_emoji_picker', 'isEnabled', false)) {
335
+ if (isTeamojiExperimentEnabled) {
326
336
  // Clear the flag after the scroll animation has settled.
327
337
  setTimeout(() => {
328
338
  isProgrammaticScroll.current = false;
@@ -338,7 +348,7 @@ const EmojiPickerComponent = ({
338
348
  }));
339
349
  }
340
350
  });
341
- }, [disableCategories, emojiPickerList, emojiProvider, fireAnalytics, selectedTone, uploading, emojiToDelete]);
351
+ }, [disableCategories, emojiPickerList, emojiProvider, fireAnalytics, isTeamojiExperimentEnabled, selectedTone, uploading, emojiToDelete]);
342
352
  const recordUsageOnSelection = useMemo(() => createRecordSelectionDefault(emojiProvider, onSelectWrapper, analytic => fireAnalytics(analytic(SearchSourceTypes.PICKER))), [emojiProvider, fireAnalytics, onSelectWrapper]);
343
353
  const formattedErrorMessage = useMemo(() => uploadErrorMessage ? /*#__PURE__*/React.createElement(FormattedMessage, uploadErrorMessage) : null, [uploadErrorMessage]);
344
354
  const onFileChooserClicked = useCallback(() => {
@@ -580,11 +590,13 @@ const EmojiPickerComponent = ({
580
590
  onSearch: onSearch,
581
591
  query: query,
582
592
  selectedTone: selectedTone,
593
+ selectedProductivityColor: isTeamojiExperimentEnabled ? selectedProductivityColor : undefined,
583
594
  loading: loading,
584
595
  ref: emojiPickerList,
585
596
  initialUploadName: query,
586
597
  onToneSelected: onToneSelected,
587
598
  onToneSelectorCancelled: onToneSelectorCancelled,
599
+ onProductivityColorSelected: isTeamojiExperimentEnabled ? onProductivityColorSelected : undefined,
588
600
  toneEmoji: toneEmoji,
589
601
  uploading: uploading,
590
602
  emojiToDelete: emojiToDelete,
@@ -2,6 +2,8 @@ import { useIntl } from 'react-intl';
2
2
  import React, { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
3
3
  import FeatureGates from '@atlaskit/feature-gate-js-client';
4
4
  import { customCategory, defaultEmojiPickerSize, frequentCategory, searchCategory, userCustomTitle, yourUploadsCategory } from '../../util/constants';
5
+ import { filterProductivityEmojisByColor, getProductivityColorPreviewEmojis } from '../../util/productivity-colors';
6
+ import { filterHiddenEmojis } from '../../util/hidden-emojis';
5
7
  import { CategoryDescriptionMap, CategoryDescriptionMapNew } from './categories';
6
8
  import CategoryTracker from './CategoryTracker';
7
9
  import { sizes } from './EmojiPickerSizes';
@@ -62,7 +64,9 @@ export const EmojiPickerVirtualListInternal = /*#__PURE__*/React.forwardRef((pro
62
64
  onCloseDelete,
63
65
  onFileChooserClicked,
64
66
  onOpenUpload,
65
- activeCategoryId
67
+ onProductivityColorSelected,
68
+ activeCategoryId,
69
+ selectedProductivityColor
66
70
  } = props;
67
71
  const {
68
72
  formatMessage
@@ -74,6 +78,8 @@ export const EmojiPickerVirtualListInternal = /*#__PURE__*/React.forwardRef((pro
74
78
  const categoryTracker = useMemo(() => new CategoryTracker(), []);
75
79
  const [categoriesChanged, setCategoriesChanged] = useState(false);
76
80
  const isTeamojiExperimentEnabled = FeatureGates.getExperimentValue(teamojiRefreshExperimentName, 'isEnabled', false);
81
+ const visibleEmojis = useMemo(() => isTeamojiExperimentEnabled ? filterHiddenEmojis(emojis) : emojis, [emojis, isTeamojiExperimentEnabled]);
82
+ const productivityColorPreviewEmojis = useMemo(() => isTeamojiExperimentEnabled ? getProductivityColorPreviewEmojis(visibleEmojis) : {}, [isTeamojiExperimentEnabled, visibleEmojis]);
77
83
  const addToCategoryMap = useCallback((categoryToGroupMap, emoji, category) => {
78
84
  if (!categoryToGroupMap[category]) {
79
85
  const categoryDefinition = isTeamojiExperimentEnabled ? CategoryDescriptionMapNew[category] : CategoryDescriptionMap[category];
@@ -150,16 +156,23 @@ export const EmojiPickerVirtualListInternal = /*#__PURE__*/React.forwardRef((pro
150
156
  const buildEmojiGroupedByCategory = useCallback((emojis, currentUser) => {
151
157
  const categoryToGroupMap = emojis.reduce(groupByCategory(currentUser), {});
152
158
  setAllEmojiGroups(Object.keys(categoryToGroupMap).map(key => categoryToGroupMap[key]).map(group => {
153
- if (group.category !== frequentCategory) {
159
+ if (isTeamojiExperimentEnabled && selectedProductivityColor) {
154
160
  var _group$subcategories;
155
- group.emojis.sort(byOrder);
161
+ group.emojis = filterProductivityEmojisByColor(group.emojis, selectedProductivityColor);
156
162
  (_group$subcategories = group.subcategories) === null || _group$subcategories === void 0 ? void 0 : _group$subcategories.forEach(subcategory => {
163
+ subcategory.emojis = filterProductivityEmojisByColor(subcategory.emojis, selectedProductivityColor);
164
+ });
165
+ }
166
+ if (group.category !== frequentCategory) {
167
+ var _group$subcategories2;
168
+ group.emojis.sort(byOrder);
169
+ (_group$subcategories2 = group.subcategories) === null || _group$subcategories2 === void 0 ? void 0 : _group$subcategories2.forEach(subcategory => {
157
170
  subcategory.emojis.sort(byOrder);
158
171
  });
159
172
  }
160
173
  return group;
161
174
  }).sort(byOrder));
162
- }, [groupByCategory]);
175
+ }, [groupByCategory, isTeamojiExperimentEnabled, selectedProductivityColor]);
163
176
  const buildEmojiRows = useCallback((items, category, title, emojis, showDelete) => {
164
177
  let remainingEmojis = emojis;
165
178
  while (remainingEmojis.length > 0) {
@@ -179,9 +192,9 @@ export const EmojiPickerVirtualListInternal = /*#__PURE__*/React.forwardRef((pro
179
192
  }
180
193
  }, [isTeamojiExperimentEnabled, onEmojiActive, onEmojiDelete, onEmojiLeave, onEmojiSelected]);
181
194
  const buildVirtualItemFromGroup = useCallback(group => {
182
- var _group$subcategories2;
195
+ var _group$subcategories3;
183
196
  const items = [];
184
- const hasAtlassianSubcategories = isTeamojiExperimentEnabled && group.category === atlassianCategory && !!((_group$subcategories2 = group.subcategories) !== null && _group$subcategories2 !== void 0 && _group$subcategories2.length);
197
+ const hasAtlassianSubcategories = isTeamojiExperimentEnabled && group.category === atlassianCategory && !!((_group$subcategories3 = group.subcategories) !== null && _group$subcategories3 !== void 0 && _group$subcategories3.length);
185
198
  if (!hasAtlassianSubcategories) {
186
199
  items.push(new CategoryHeadingItem({
187
200
  id: group.category,
@@ -226,7 +239,7 @@ export const EmojiPickerVirtualListInternal = /*#__PURE__*/React.forwardRef((pro
226
239
  } else {
227
240
  if (query) {
228
241
  const search = isTeamojiExperimentEnabled ? CategoryDescriptionMapNew.SEARCH : CategoryDescriptionMap.SEARCH;
229
- if (emojis.length === 0 && isTeamojiExperimentEnabled) {
242
+ if (visibleEmojis.length === 0 && isTeamojiExperimentEnabled) {
230
243
  // Show a "No results" category heading, then a no-results illustration below it
231
244
  items.push(new CategoryHeadingItem({
232
245
  id: searchCategory,
@@ -242,7 +255,7 @@ export const EmojiPickerVirtualListInternal = /*#__PURE__*/React.forwardRef((pro
242
255
  items = [...items, ...buildVirtualItemFromGroup({
243
256
  category: searchCategory,
244
257
  title: search.name,
245
- emojis,
258
+ emojis: visibleEmojis,
246
259
  order: search.order
247
260
  })];
248
261
  }
@@ -270,7 +283,7 @@ export const EmojiPickerVirtualListInternal = /*#__PURE__*/React.forwardRef((pro
270
283
  }
271
284
  }
272
285
  // eslint-disable-next-line react-hooks/exhaustive-deps
273
- }, [allEmojiGroups, buildVirtualItemFromGroup, emojis, formatMessage, isTeamojiExperimentEnabled, loading, onOpenUpload, query, uploadEnabled]);
286
+ }, [allEmojiGroups, buildVirtualItemFromGroup, formatMessage, isTeamojiExperimentEnabled, loading, onOpenUpload, query, uploadEnabled, visibleEmojis]);
274
287
  const findCategoryToActivate = row => {
275
288
  let category = null;
276
289
  if (row instanceof CategoryHeadingItem) {
@@ -364,9 +377,9 @@ export const EmojiPickerVirtualListInternal = /*#__PURE__*/React.forwardRef((pro
364
377
  });
365
378
  useEffect(() => {
366
379
  if (!query) {
367
- buildEmojiGroupedByCategory(emojis, currentUser);
380
+ buildEmojiGroupedByCategory(visibleEmojis, currentUser);
368
381
  }
369
- }, [emojis, selectedTone, loading, query, currentUser, buildEmojiGroupedByCategory]);
382
+ }, [visibleEmojis, selectedTone, selectedProductivityColor, loading, query, currentUser, buildEmojiGroupedByCategory]);
370
383
  useEffect(() => {
371
384
  buildVirtualItems();
372
385
  }, [allEmojiGroups, buildVirtualItems]);
@@ -375,16 +388,17 @@ export const EmojiPickerVirtualListInternal = /*#__PURE__*/React.forwardRef((pro
375
388
  onRowsRendered({
376
389
  startIndex: 0
377
390
  });
391
+ setCategoriesChanged(false);
378
392
  }
379
393
  // eslint-disable-next-line react-hooks/exhaustive-deps
380
394
  }, [virtualItems, categoriesChanged]);
381
395
  const virtualListHeight = useMemo(() => {
382
- if (query && emojis.length === 0 && isTeamojiExperimentEnabled) {
396
+ if (query && visibleEmojis.length === 0 && isTeamojiExperimentEnabled) {
383
397
  // No-results state: expand the list height to fit heading + illustration without scrolling
384
398
  return sizes.categoryHeadingHeight + sizes.noResultsHeight + emojiPickerHeightOffset(size);
385
399
  }
386
400
  return isTeamojiExperimentEnabled ? sizes.listHeightNew + emojiPickerHeightOffset(size) : sizes.listHeight + emojiPickerHeightOffset(size);
387
- }, [size, query, emojis.length, isTeamojiExperimentEnabled]);
401
+ }, [size, query, visibleEmojis.length, isTeamojiExperimentEnabled]);
388
402
  return /*#__PURE__*/React.createElement(EmojiPickerTabPanel, {
389
403
  showSearchResults: !!query
390
404
  }, /*#__PURE__*/React.createElement(EmojiActions, {
@@ -392,6 +406,9 @@ export const EmojiPickerVirtualListInternal = /*#__PURE__*/React.forwardRef((pro
392
406
  onToneSelected: onToneSelected,
393
407
  onToneSelectorCancelled: onToneSelectorCancelled,
394
408
  toneEmoji: toneEmoji,
409
+ activeCategoryId: isTeamojiExperimentEnabled ? activeCategoryId : undefined,
410
+ productivityColorPreviewEmojis: isTeamojiExperimentEnabled ? productivityColorPreviewEmojis : undefined,
411
+ selectedProductivityColor: isTeamojiExperimentEnabled ? selectedProductivityColor : undefined,
395
412
  uploading: uploading,
396
413
  uploadEnabled: uploadEnabled,
397
414
  emojiToDelete: emojiToDelete,
@@ -403,9 +420,10 @@ export const EmojiPickerVirtualListInternal = /*#__PURE__*/React.forwardRef((pro
403
420
  onDeleteEmoji: onDeleteEmoji,
404
421
  onFileChooserClicked: onFileChooserClicked,
405
422
  onOpenUpload: onOpenUpload,
423
+ onProductivityColorSelected: isTeamojiExperimentEnabled ? onProductivityColorSelected : undefined,
406
424
  query: query,
407
425
  onChange: onSearch,
408
- resultsCount: emojis.length
426
+ resultsCount: visibleEmojis.length
409
427
  }), /*#__PURE__*/React.createElement(EmojiPickerListContextProvider, {
410
428
  initialEmojisFocus: {
411
429
  rowIndex: 1,
@@ -5,6 +5,7 @@ import { ax, ix } from "@compiled/react/runtime";
5
5
  import React, { useCallback, useImperativeHandle } from 'react';
6
6
  import { useVirtualizer } from '@tanstack/react-virtual';
7
7
  import { fg } from '@atlaskit/platform-feature-flags';
8
+ import FeatureGates from '@atlaskit/feature-gate-js-client';
8
9
  import { useEmojiPickerListContext } from '../../hooks/useEmojiPickerListContext';
9
10
  import { EMOJIPICKERLIST_KEYBOARD_KEYS_SUPPORTED, EMOJI_LIST_COLUMNS, EMOJI_LIST_PAGE_COUNT, KeyboardNavigationDirection, KeyboardKeys } from '../../util/constants';
10
11
  const virtualList = null;
@@ -55,13 +56,11 @@ export const VirtualList = /*#__PURE__*/React.forwardRef((props, ref) => {
55
56
  const elemBottom = elementRect.bottom;
56
57
  const parentTop = parentRect.top;
57
58
  const parentBottom = parentRect.bottom;
58
-
59
- // Only completely visible elements return true:
60
- const isVisible = elemTop >= parentTop && elemBottom <= parentBottom;
59
+ const isVisible = FeatureGates.getExperimentValue('platform_teamoji_26_refresh_emoji_picker', 'isEnabled', false) ? elemTop >= parentTop && elemBottom <= parentBottom : elemBottom > parentTop && elemTop < parentBottom;
61
60
  return isVisible;
62
61
  };
63
62
  const getFirstVisibleListElementIndex = useCallback(() => {
64
- var _parentRef$current, _parentRef$current$fi;
63
+ var _parentRef$current, _parentRef$current$fi, _virtualList$;
65
64
  const virtualList = rowVirtualizer.getVirtualItems();
66
65
  const renderedElements = (_parentRef$current = parentRef.current) === null || _parentRef$current === void 0 ? void 0 : (_parentRef$current$fi = _parentRef$current.firstChild) === null || _parentRef$current$fi === void 0 ? void 0 : _parentRef$current$fi.childNodes;
67
66
  if (virtualList.length === 0 || !renderedElements || renderedElements.length === 0) {
@@ -74,7 +73,7 @@ export const VirtualList = /*#__PURE__*/React.forwardRef((props, ref) => {
74
73
  var _virtualList$firstVis;
75
74
  return ((_virtualList$firstVis = virtualList[firstVisibleIndex]) === null || _virtualList$firstVis === void 0 ? void 0 : _virtualList$firstVis.index) || 0;
76
75
  }
77
- return 0;
76
+ return FeatureGates.getExperimentValue('platform_teamoji_26_refresh_emoji_picker', 'isEnabled', false) ? ((_virtualList$ = virtualList[0]) === null || _virtualList$ === void 0 ? void 0 : _virtualList$.index) || 0 : 0;
78
77
  }, [rowVirtualizer]);
79
78
 
80
79
  /**
@@ -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.17.10",
12
+ packageVersion: "71.0.1",
13
13
  ...attributes
14
14
  }
15
15
  });
@@ -0,0 +1,25 @@
1
+ const hasHiddenTag = tags => {
2
+ var _tags$includes;
3
+ return (_tags$includes = tags === null || tags === void 0 ? void 0 : tags.includes('hidden')) !== null && _tags$includes !== void 0 ? _tags$includes : false;
4
+ };
5
+ const hasHiddenMetadataTag = emoji => {
6
+ const emojiWithMetadata = emoji;
7
+ const {
8
+ metadata
9
+ } = emojiWithMetadata;
10
+ if (typeof metadata === 'string') {
11
+ return metadata === 'hidden';
12
+ }
13
+ if (Array.isArray(metadata)) {
14
+ return hasHiddenTag(metadata);
15
+ }
16
+ return hasHiddenTag(metadata === null || metadata === void 0 ? void 0 : metadata.tags) || hasHiddenTag(emojiWithMetadata.tags);
17
+ };
18
+ export const isHiddenEmoji = emoji => {
19
+ const emojiWithMetadata = emoji;
20
+ if (emojiWithMetadata.hidden) {
21
+ return true;
22
+ }
23
+ return hasHiddenMetadataTag(emoji);
24
+ };
25
+ export const filterHiddenEmojis = emojis => emojis.filter(emoji => !isHiddenEmoji(emoji));
@@ -0,0 +1,37 @@
1
+ export const productivityColors = ['gray', 'magenta', 'purple', 'blue', 'teal', 'green', 'lime', 'yellow', 'orange', 'red'];
2
+ const productivityColorSet = new Set(productivityColors);
3
+ const zeroSquareVariantParent = '0_zero_square_blue';
4
+ export const defaultProductivityColor = 'blue';
5
+ const getProductivityVariant = emoji => {
6
+ if (emoji.type !== 'ATLASSIAN' || !emoji.color || !productivityColorSet.has(emoji.color)) {
7
+ return undefined;
8
+ }
9
+ return {
10
+ color: emoji.color
11
+ };
12
+ };
13
+ export const getProductivityColor = emoji => {
14
+ var _getProductivityVaria;
15
+ return (_getProductivityVaria = getProductivityVariant(emoji)) === null || _getProductivityVaria === void 0 ? void 0 : _getProductivityVaria.color;
16
+ };
17
+ export const isProductivityNumberEmoji = emoji => getProductivityColor(emoji) !== undefined;
18
+ export const filterProductivityEmojisByColor = (emojis, selectedColor) => {
19
+ return emojis.filter(emoji => {
20
+ const variant = getProductivityVariant(emoji);
21
+ return !variant || variant.color === selectedColor;
22
+ });
23
+ };
24
+ const isZeroSquareProductivityEmoji = emoji => {
25
+ var _emoji$variantChildre, _emoji$keywords, _emoji$variantChildre2;
26
+ return emoji.variantParent === zeroSquareVariantParent || ((_emoji$variantChildre = emoji.variantChildren) === null || _emoji$variantChildre === void 0 ? void 0 : _emoji$variantChildre.some(variantChild => variantChild.includes('0_zero_square_'))) || !!(emoji.variantBase && (_emoji$keywords = emoji.keywords) !== null && _emoji$keywords !== void 0 && _emoji$keywords.includes('0') && (_emoji$variantChildre2 = emoji.variantChildren) !== null && _emoji$variantChildre2 !== void 0 && _emoji$variantChildre2.some(variantChild => variantChild.includes('_square_')));
27
+ };
28
+ export const getProductivityColorPreviewEmojis = emojis => emojis.reduce((previewEmojis, emoji) => {
29
+ const color = getProductivityColor(emoji);
30
+ if (!color) {
31
+ return previewEmojis;
32
+ }
33
+ if (isZeroSquareProductivityEmoji(emoji) || !previewEmojis[color]) {
34
+ previewEmojis[color] = emoji;
35
+ }
36
+ return previewEmojis;
37
+ }, {});
@@ -1,14 +1,16 @@
1
1
  /* Emoji.tsx generated by @compiled/babel-plugin v0.39.1 */
2
2
  import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
3
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
4
+ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
4
5
  import _extends from "@babel/runtime/helpers/extends";
5
6
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
6
- var _excluded = ["emoji", "fitToHeight", "selected", "selectOnHover", "className", "showTooltip", "showDelete", "shouldBeInteractive", "tabIndex", "onSelected", "onMouseMove", "onFocus", "onDelete", "onLoadError", "onLoadSuccess", "disableLazyLoad", "autoWidth", "children", "type", "editorEmoji"];
7
+ var _excluded = ["emoji", "fitToHeight", "selected", "selectOnHover", "className", "showTooltip", "showDelete", "shouldBeInteractive", "tabIndex", "onSelected", "onMouseMove", "onFocus", "onDelete", "onLoadError", "onLoadSuccess", "disableLazyLoad", "autoWidth", "children", "type", "editorEmoji", "renderUnicodeEmojiAsImage"];
7
8
  import "./Emoji.compiled.css";
8
9
  import { ax, ix } from "@compiled/react/runtime";
10
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
9
11
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
10
12
  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) { _defineProperty(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; }
11
- import React, { useEffect, useCallback, useContext, useMemo, forwardRef } from 'react';
13
+ import React, { useEffect, useCallback, useContext, useMemo, useState, forwardRef } from 'react';
12
14
  import { IntlContext } from 'react-intl';
13
15
  import Tooltip from '@atlaskit/tooltip';
14
16
  import { shouldUseAltRepresentation } from '../../api/EmojiUtils';
@@ -27,6 +29,8 @@ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
27
29
  import { getDocument } from '@atlaskit/browser-apis';
28
30
  import { fg } from '@atlaskit/platform-feature-flags';
29
31
  import { messages } from '../i18n';
32
+ import { isSSR } from '../../util/is-ssr';
33
+ import EmojiPlaceholder from './EmojiPlaceholder';
30
34
  var emojiSpriteContainer = null;
31
35
  var emojiImageContainer = null;
32
36
 
@@ -142,15 +146,145 @@ export var SpriteEmoji = function SpriteEmoji(props) {
142
146
  }))
143
147
  );
144
148
  };
145
- export var UnicodeEmoji = function UnicodeEmoji(props) {
149
+ var unicodeEmojiCanvasSize = 128;
150
+ var unicodeEmojiCanvasFontSize = 124;
151
+ var unicodeEmojiCanvasTopPadding = 8;
152
+ var renderUnicodeEmojiToImagePath = /*#__PURE__*/function () {
153
+ var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(unicodeEmoji) {
154
+ var OffscreenCanvasCtor, canvas, context, blob;
155
+ return _regeneratorRuntime.wrap(function (_context) {
156
+ while (1) switch (_context.prev = _context.next) {
157
+ case 0:
158
+ OffscreenCanvasCtor = globalThis['OffscreenCanvas'];
159
+ if (!(isSSR() || !OffscreenCanvasCtor || typeof URL === 'undefined')) {
160
+ _context.next = 1;
161
+ break;
162
+ }
163
+ return _context.abrupt("return", undefined);
164
+ case 1:
165
+ canvas = new OffscreenCanvasCtor(unicodeEmojiCanvasSize, unicodeEmojiCanvasSize);
166
+ context = canvas.getContext('2d');
167
+ if (context) {
168
+ _context.next = 2;
169
+ break;
170
+ }
171
+ return _context.abrupt("return", undefined);
172
+ case 2:
173
+ context.clearRect(0, 0, unicodeEmojiCanvasSize, unicodeEmojiCanvasSize);
174
+ context.textAlign = 'center';
175
+ context.textBaseline = 'middle';
176
+ context.font = "".concat(unicodeEmojiCanvasFontSize, "px sans-serif");
177
+ context.fillText(unicodeEmoji, unicodeEmojiCanvasSize / 2, unicodeEmojiCanvasSize / 2 + unicodeEmojiCanvasTopPadding);
178
+ _context.next = 3;
179
+ return canvas.convertToBlob({
180
+ type: 'image/png'
181
+ });
182
+ case 3:
183
+ blob = _context.sent;
184
+ return _context.abrupt("return", URL.createObjectURL(blob));
185
+ case 4:
186
+ case "end":
187
+ return _context.stop();
188
+ }
189
+ }, _callee);
190
+ }));
191
+ return function renderUnicodeEmojiToImagePath(_x) {
192
+ return _ref.apply(this, arguments);
193
+ };
194
+ }();
195
+ var useUnicodeEmojiImage = function useUnicodeEmojiImage(unicodeEmoji) {
196
+ var _useState = useState({
197
+ status: 'loading'
198
+ }),
199
+ _useState2 = _slicedToArray(_useState, 2),
200
+ state = _useState2[0],
201
+ setState = _useState2[1];
202
+ useEffect(function () {
203
+ var cancelled = false;
204
+ var imagePathToRevoke;
205
+ setState({
206
+ status: 'loading',
207
+ unicodeEmoji: unicodeEmoji
208
+ });
209
+ void renderUnicodeEmojiToImagePath(unicodeEmoji).then(function (imagePath) {
210
+ if (cancelled) {
211
+ if (imagePath) {
212
+ URL.revokeObjectURL(imagePath);
213
+ }
214
+ return;
215
+ }
216
+ imagePathToRevoke = imagePath;
217
+ setState(imagePath ? {
218
+ status: 'ready',
219
+ unicodeEmoji: unicodeEmoji,
220
+ imagePath: imagePath
221
+ } : {
222
+ status: 'failed',
223
+ unicodeEmoji: unicodeEmoji
224
+ });
225
+ }).catch(function () {
226
+ if (!cancelled) {
227
+ setState({
228
+ status: 'failed',
229
+ unicodeEmoji: unicodeEmoji
230
+ });
231
+ }
232
+ });
233
+ return function () {
234
+ cancelled = true;
235
+ if (imagePathToRevoke) {
236
+ URL.revokeObjectURL(imagePathToRevoke);
237
+ }
238
+ };
239
+ }, [unicodeEmoji]);
240
+ return state;
241
+ };
242
+ var UnicodeEmojiImage = function UnicodeEmojiImage(props) {
146
243
  var emoji = props.emoji,
147
244
  fitToHeight = props.fitToHeight,
245
+ showTooltip = props.showTooltip;
246
+ var emojiText = emoji.representation.unicodeEmoji;
247
+ var unicodeEmojiImage = useUnicodeEmojiImage(emojiText);
248
+ var hasCurrentEmojiImage = unicodeEmojiImage.unicodeEmoji === emojiText;
249
+ if (isSSR() || !hasCurrentEmojiImage || unicodeEmojiImage.status === 'loading') {
250
+ return /*#__PURE__*/React.createElement(EmojiPlaceholder, {
251
+ shortName: emoji.shortName,
252
+ showTooltip: showTooltip,
253
+ size: fitToHeight,
254
+ loading: true
255
+ });
256
+ }
257
+ if (unicodeEmojiImage.status === 'ready') {
258
+ return /*#__PURE__*/React.createElement(ImageEmoji, _extends({}, props, {
259
+ emoji: _objectSpread(_objectSpread({}, emoji), {}, {
260
+ representation: {
261
+ imagePath: unicodeEmojiImage.imagePath,
262
+ width: unicodeEmojiCanvasSize,
263
+ height: unicodeEmojiCanvasSize
264
+ }
265
+ })
266
+ }));
267
+ }
268
+ return /*#__PURE__*/React.createElement(EmojiPlaceholder, {
269
+ shortName: emoji.shortName,
270
+ showTooltip: showTooltip,
271
+ size: fitToHeight
272
+ });
273
+ };
274
+ export var UnicodeEmoji = function UnicodeEmoji(props) {
275
+ var _props$fitToHeight;
276
+ var emoji = props.emoji,
148
277
  selected = props.selected,
149
278
  selectOnHover = props.selectOnHover,
150
- className = props.className;
279
+ className = props.className,
280
+ _props$renderUnicodeE = props.renderUnicodeEmojiAsImage,
281
+ renderUnicodeEmojiAsImage = _props$renderUnicodeE === void 0 ? true : _props$renderUnicodeE;
282
+ if (renderUnicodeEmojiAsImage) {
283
+ return /*#__PURE__*/React.createElement(UnicodeEmojiImage, props);
284
+ }
151
285
  var classes = "".concat(emojiNodeStyles, " ").concat(selected ? commonSelectedStyles : '', " ").concat(selectOnHover ? selectOnHoverStyles : '', " ").concat(className ? className : '');
152
286
  var emojiText = emoji.representation.unicodeEmoji;
153
- var size = fitToHeight !== null && fitToHeight !== void 0 ? fitToHeight : defaultEmojiHeight;
287
+ var size = (_props$fitToHeight = props.fitToHeight) !== null && _props$fitToHeight !== void 0 ? _props$fitToHeight : defaultEmojiHeight;
154
288
  var style = {
155
289
  display: 'inline-block',
156
290
  // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
@@ -332,6 +466,7 @@ export var ImageEmoji = function ImageEmoji(props) {
332
466
  );
333
467
  };
334
468
  export var EmojiNodeWrapper = /*#__PURE__*/forwardRef(function (props, ref) {
469
+ var _emoji$name;
335
470
  var emoji = props.emoji,
336
471
  fitToHeight = props.fitToHeight,
337
472
  selected = props.selected,
@@ -353,10 +488,11 @@ export var EmojiNodeWrapper = /*#__PURE__*/forwardRef(function (props, ref) {
353
488
  children = props.children,
354
489
  type = props.type,
355
490
  editorEmoji = props.editorEmoji,
491
+ renderUnicodeEmojiAsImage = props.renderUnicodeEmojiAsImage,
356
492
  other = _objectWithoutProperties(props, _excluded);
357
493
  var intl = useContext(IntlContext);
358
494
  var ariaLabel = intl && fg('platform_change_emoji_button_label') ? intl.formatMessage(messages.changeEmojiShortnameButtonLabel, {
359
- shortName: emoji.shortName
495
+ shortName: (_emoji$name = emoji.name) !== null && _emoji$name !== void 0 ? _emoji$name : emoji.shortName
360
496
  }) : editorEmoji ? undefined : emoji.shortName;
361
497
  return /*#__PURE__*/React.createElement("span", _extends({
362
498
  role: editorEmoji ? undefined : shouldBeInteractive ? 'button' : ariaLabel ? 'img' : 'presentation',
@@ -1,9 +1,13 @@
1
1
 
2
+ ._19itia51{border:var(--ds-border-width,1px) solid var(--ds-border,#0b120e24)}
3
+ ._2rkofajl{border-radius:var(--ds-radius-small,3px)}
2
4
  ._n7zl1uh4{border-bottom:var(--ds-border-width-selected,2px) solid var(--ds-border,#0b120e24)}._16jlidpf{flex-grow:0}
3
5
  ._16jlkb7n{flex-grow:1}
6
+ ._16qs130s{box-shadow:var(--ds-shadow-overlay,0 8px 9pt #1e1f2126,0 0 1px #1e1f214f)}
4
7
  ._16qsjgpa{box-shadow:0 1px 1px 0 var(--ds-border,#0b120e24)}
5
8
  ._18u019bv{margin-left:10px}
6
9
  ._18u0r5cr{margin-left:var(--ds-space-negative-050,-4px)}
10
+ ._19bv12x7{padding-left:var(--ds-space-075,6px)}
7
11
  ._19bvidpf{padding-left:0}
8
12
  ._1bahesu3{justify-content:flex-end}
9
13
  ._1e0c1txw{display:flex}
@@ -12,10 +16,14 @@
12
16
  ._1wpz1h6o{align-self:center}
13
17
  ._2hwx1i6y{margin-right:var(--ds-space-negative-025,-2px)}
14
18
  ._4cvr1h6o{align-items:center}
19
+ ._bfhk1bhr{background-color:var(--ds-surface-overlay,#fff)}
20
+ ._ca0q12x7{padding-top:var(--ds-space-075,6px)}
15
21
  ._ca0q1skh{padding-top:11px}
16
22
  ._i0dl1wug{flex-basis:auto}
17
23
  ._i0dlf1ug{flex-basis:0%}
24
+ ._n3td12x7{padding-bottom:var(--ds-space-075,6px)}
18
25
  ._n3td1crf{padding-bottom:9pt}
19
26
  ._otyr19bv{margin-bottom:10px}
20
27
  ._p12f3sup{max-width:285px}
28
+ ._u5f312x7{padding-right:var(--ds-space-075,6px)}
21
29
  ._u5f319bv{padding-right:10px}