@atlaskit/emoji 65.0.0 → 65.2.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 (115) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/cjs/components/common/CachingEmoji.js +84 -151
  3. package/dist/cjs/components/common/Emoji.js +2 -2
  4. package/dist/cjs/components/common/EmojiActions.js +129 -175
  5. package/dist/cjs/components/common/EmojiErrorMessage.js +23 -59
  6. package/dist/cjs/components/common/EmojiPreviewComponent.js +1 -0
  7. package/dist/cjs/components/common/EmojiUploadPicker.js +235 -293
  8. package/dist/cjs/components/common/FileChooser.js +34 -71
  9. package/dist/cjs/components/common/Popup.js +105 -154
  10. package/dist/cjs/components/common/ResourcedEmojiComponent.js +10 -5
  11. package/dist/cjs/components/common/RetryableButton.js +43 -64
  12. package/dist/cjs/components/common/ToneSelector.js +50 -89
  13. package/dist/cjs/components/common/styles.js +14 -16
  14. package/dist/cjs/components/hooks.js +16 -0
  15. package/dist/cjs/components/picker/EmojiPickerCategoryHeading.js +16 -48
  16. package/dist/cjs/components/picker/EmojiPickerComponent.js +496 -508
  17. package/dist/cjs/components/picker/EmojiPickerEmojiRow.js +33 -60
  18. package/dist/cjs/components/picker/EmojiPickerFooter.js +13 -46
  19. package/dist/cjs/components/picker/styles.js +16 -13
  20. package/dist/cjs/components/uploader/EmojiUploadComponent.js +124 -109
  21. package/dist/cjs/hooks/useEmojiContext.js +16 -0
  22. package/dist/cjs/hooks/usePrevious.js +16 -0
  23. package/dist/cjs/index.js +16 -0
  24. package/dist/cjs/util/constants.js +3 -1
  25. package/dist/cjs/version.json +1 -1
  26. package/dist/es2019/components/common/CachingEmoji.js +65 -112
  27. package/dist/es2019/components/common/Emoji.js +2 -2
  28. package/dist/es2019/components/common/EmojiActions.js +124 -150
  29. package/dist/es2019/components/common/EmojiErrorMessage.js +22 -26
  30. package/dist/es2019/components/common/EmojiPreviewComponent.js +1 -0
  31. package/dist/es2019/components/common/EmojiUploadPicker.js +190 -253
  32. package/dist/es2019/components/common/FileChooser.js +37 -40
  33. package/dist/es2019/components/common/Popup.js +89 -109
  34. package/dist/es2019/components/common/ResourcedEmojiComponent.js +5 -4
  35. package/dist/es2019/components/common/RetryableButton.js +43 -34
  36. package/dist/es2019/components/common/ToneSelector.js +46 -59
  37. package/dist/es2019/components/common/styles.js +9 -9
  38. package/dist/es2019/components/hooks.js +8 -0
  39. package/dist/es2019/components/picker/EmojiPickerCategoryHeading.js +13 -17
  40. package/dist/es2019/components/picker/EmojiPickerComponent.js +417 -497
  41. package/dist/es2019/components/picker/EmojiPickerEmojiRow.js +32 -35
  42. package/dist/es2019/components/picker/EmojiPickerFooter.js +11 -19
  43. package/dist/es2019/components/picker/styles.js +16 -14
  44. package/dist/es2019/components/uploader/EmojiUploadComponent.js +81 -91
  45. package/dist/es2019/hooks/useEmojiContext.js +3 -0
  46. package/dist/es2019/hooks/usePrevious.js +8 -0
  47. package/dist/es2019/index.js +4 -1
  48. package/dist/es2019/util/constants.js +1 -0
  49. package/dist/es2019/version.json +1 -1
  50. package/dist/esm/components/common/CachingEmoji.js +86 -156
  51. package/dist/esm/components/common/Emoji.js +2 -2
  52. package/dist/esm/components/common/EmojiActions.js +129 -176
  53. package/dist/esm/components/common/EmojiErrorMessage.js +21 -56
  54. package/dist/esm/components/common/EmojiPreviewComponent.js +1 -0
  55. package/dist/esm/components/common/EmojiUploadPicker.js +233 -299
  56. package/dist/esm/components/common/FileChooser.js +34 -70
  57. package/dist/esm/components/common/Popup.js +104 -155
  58. package/dist/esm/components/common/ResourcedEmojiComponent.js +8 -4
  59. package/dist/esm/components/common/RetryableButton.js +40 -60
  60. package/dist/esm/components/common/ToneSelector.js +50 -87
  61. package/dist/esm/components/common/styles.js +10 -10
  62. package/dist/esm/components/hooks.js +8 -0
  63. package/dist/esm/components/picker/EmojiPickerCategoryHeading.js +14 -43
  64. package/dist/esm/components/picker/EmojiPickerComponent.js +486 -526
  65. package/dist/esm/components/picker/EmojiPickerEmojiRow.js +31 -59
  66. package/dist/esm/components/picker/EmojiPickerFooter.js +14 -47
  67. package/dist/esm/components/picker/styles.js +16 -14
  68. package/dist/esm/components/uploader/EmojiUploadComponent.js +119 -113
  69. package/dist/esm/hooks/useEmojiContext.js +5 -0
  70. package/dist/esm/hooks/usePrevious.js +8 -0
  71. package/dist/esm/index.js +4 -1
  72. package/dist/esm/util/constants.js +1 -0
  73. package/dist/esm/version.json +1 -1
  74. package/dist/types/api/EmojiResource.d.ts +2 -3
  75. package/dist/types/components/common/CachingEmoji.d.ts +3 -13
  76. package/dist/types/components/common/Emoji.d.ts +1 -2
  77. package/dist/types/components/common/EmojiActions.d.ts +6 -17
  78. package/dist/types/components/common/EmojiErrorMessage.d.ts +3 -6
  79. package/dist/types/components/common/EmojiPreviewComponent.d.ts +2 -2
  80. package/dist/types/components/common/EmojiUploadPicker.d.ts +3 -27
  81. package/dist/types/components/common/FileChooser.d.ts +3 -5
  82. package/dist/types/components/common/LoadingEmojiComponent.d.ts +3 -0
  83. package/dist/types/components/common/Popup.d.ts +3 -20
  84. package/dist/types/components/common/ResourcedEmojiComponent.d.ts +23 -11
  85. package/dist/types/components/common/RetryableButton.d.ts +3 -7
  86. package/dist/types/components/common/ToneSelector.d.ts +4 -10
  87. package/dist/types/components/common/setSkinToneAriaLabelText.d.ts +1 -1
  88. package/dist/types/components/common/styles.d.ts +1 -3
  89. package/dist/types/components/hooks.d.ts +1 -0
  90. package/dist/types/components/picker/CategorySelector.d.ts +1 -1
  91. package/dist/types/components/picker/EmojiPicker.d.ts +12 -3
  92. package/dist/types/components/picker/EmojiPickerCategoryHeading.d.ts +3 -4
  93. package/dist/types/components/picker/EmojiPickerComponent.d.ts +14 -76
  94. package/dist/types/components/picker/EmojiPickerEmojiRow.d.ts +3 -4
  95. package/dist/types/components/picker/EmojiPickerFooter.d.ts +3 -5
  96. package/dist/types/components/picker/styles.d.ts +1 -1
  97. package/dist/types/components/typeahead/EmojiTypeAheadComponent.d.ts +18 -0
  98. package/dist/types/components/uploader/EmojiUploadComponent.d.ts +3 -17
  99. package/dist/types/components/uploader/EmojiUploader.d.ts +5 -7
  100. package/dist/types/hooks/useEmojiContext.d.ts +1 -0
  101. package/dist/types/hooks/usePrevious.d.ts +1 -0
  102. package/dist/types/index.d.ts +3 -1
  103. package/dist/types/types.d.ts +2 -1
  104. package/dist/types/util/constants.d.ts +1 -0
  105. package/docs/0-intro.tsx +35 -27
  106. package/docs/1-resourced-emoji.tsx +74 -0
  107. package/docs/2-emoji-picker.tsx +56 -0
  108. package/docs/3-typeahead.tsx +20 -0
  109. package/docs/4-emoji-provider.tsx +98 -0
  110. package/local-config-example.ts +3 -1
  111. package/package.json +19 -6
  112. package/dist/cjs/components/common/EmojiPreview.js +0 -194
  113. package/dist/es2019/components/common/EmojiPreview.js +0 -152
  114. package/dist/esm/components/common/EmojiPreview.js +0 -170
  115. package/dist/types/components/common/EmojiPreview.d.ts +0 -31
@@ -1,23 +1,15 @@
1
- import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
- import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
3
- import _createClass from "@babel/runtime/helpers/createClass";
4
- import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
5
- import _inherits from "@babel/runtime/helpers/inherits";
6
- import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
7
- import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
8
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
3
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
9
4
 
10
5
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
11
6
 
12
7
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
13
8
 
14
- function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
15
-
16
- function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
17
-
18
9
  /** @jsx jsx */
19
10
  import { jsx } from '@emotion/core';
20
- import { PureComponent } from 'react';
11
+ import { useCallback, useEffect, useMemo, useRef, useState, createRef, memo } from 'react';
12
+ import { unstable_batchedUpdates as batchedUpdates } from 'react-dom';
21
13
  import { FormattedMessage } from 'react-intl-next';
22
14
  import { getEmojiVariation } from '../../api/EmojiRepository';
23
15
  import { supportsUploadFeature } from '../../api/EmojiResource';
@@ -35,397 +27,497 @@ import EmojiPickerList from './EmojiPickerList';
35
27
  import { createAndFireEventInElementsChannel, categoryClickedEvent, closedPickerEvent, deleteBeginEvent, deleteCancelEvent, deleteConfirmEvent, openedPickerEvent, pickerClickedEvent, pickerSearchedEvent, selectedFileEvent, uploadBeginButton, uploadCancelButton, uploadConfirmButton, toneSelectorClosedEvent, ufoExperiences } from '../../util/analytics';
36
28
  import { emojiPicker } from './styles';
37
29
  import LegacyEmojiContextProvider from '../../context/LegacyEmojiContextProvider';
30
+ import { useDidMount } from '../hooks';
38
31
  var FREQUENTLY_USED_MAX = 16;
39
32
 
40
- var EmojiPickerComponent = /*#__PURE__*/function (_PureComponent) {
41
- _inherits(EmojiPickerComponent, _PureComponent);
42
-
43
- var _super = _createSuper(EmojiPickerComponent);
33
+ var EmojiPickerComponent = function EmojiPickerComponent(_ref) {
34
+ var emojiProvider = _ref.emojiProvider,
35
+ onSelection = _ref.onSelection,
36
+ onPickerRef = _ref.onPickerRef,
37
+ hideToneSelector = _ref.hideToneSelector,
38
+ createAnalyticsEvent = _ref.createAnalyticsEvent;
39
+
40
+ var _useState = useState([]),
41
+ _useState2 = _slicedToArray(_useState, 2),
42
+ filteredEmojis = _useState2[0],
43
+ setFilteredEmojis = _useState2[1];
44
+
45
+ var _useState3 = useState([]),
46
+ _useState4 = _slicedToArray(_useState3, 2),
47
+ searchEmojis = _useState4[0],
48
+ setSearchEmojis = _useState4[1];
49
+
50
+ var _useState5 = useState([]),
51
+ _useState6 = _slicedToArray(_useState5, 2),
52
+ frequentlyUsedEmojis = _useState6[0],
53
+ setFrequentlyUsedEmojis = _useState6[1];
54
+
55
+ var _useState7 = useState(''),
56
+ _useState8 = _slicedToArray(_useState7, 2),
57
+ query = _useState8[0],
58
+ setQuery = _useState8[1];
59
+
60
+ var _useState9 = useState([]),
61
+ _useState10 = _slicedToArray(_useState9, 2),
62
+ dynamicCategories = _useState10[0],
63
+ setDynamicCategories = _useState10[1];
64
+
65
+ var _useState11 = useState(!hideToneSelector ? emojiProvider.getSelectedTone() : undefined),
66
+ _useState12 = _slicedToArray(_useState11, 2),
67
+ selectedTone = _useState12[0],
68
+ setSelectedTone = _useState12[1];
69
+
70
+ var _useState13 = useState(true),
71
+ _useState14 = _slicedToArray(_useState13, 2),
72
+ loading = _useState14[0],
73
+ setLoading = _useState14[1];
74
+
75
+ var _useState15 = useState(false),
76
+ _useState16 = _slicedToArray(_useState15, 2),
77
+ uploadSupported = _useState16[0],
78
+ setUploadSupported = _useState16[1];
79
+
80
+ var _useState17 = useState(false),
81
+ _useState18 = _slicedToArray(_useState17, 2),
82
+ uploading = _useState18[0],
83
+ setUploading = _useState18[1];
84
+
85
+ var _useState19 = useState(),
86
+ _useState20 = _slicedToArray(_useState19, 2),
87
+ selectedEmoji = _useState20[0],
88
+ setSelectedEmoji = _useState20[1];
89
+
90
+ var _useState21 = useState(null),
91
+ _useState22 = _slicedToArray(_useState21, 2),
92
+ activeCategory = _useState22[0],
93
+ setActiveCategory = _useState22[1];
94
+
95
+ var _useState23 = useState(false),
96
+ _useState24 = _slicedToArray(_useState23, 2),
97
+ disableCategories = _useState24[0],
98
+ setDisableCategories = _useState24[1];
99
+
100
+ var _useState25 = useState(),
101
+ _useState26 = _slicedToArray(_useState25, 2),
102
+ uploadErrorMessage = _useState26[0],
103
+ setUploadErrorMessage = _useState26[1];
104
+
105
+ var _useState27 = useState(),
106
+ _useState28 = _slicedToArray(_useState27, 2),
107
+ emojiToDelete = _useState28[0],
108
+ setEmojiToDelete = _useState28[1];
109
+
110
+ var _useState29 = useState(),
111
+ _useState30 = _slicedToArray(_useState29, 2),
112
+ toneEmoji = _useState30[0],
113
+ setToneEmoji = _useState30[1];
114
+
115
+ var emojiPickerList = useMemo(function () {
116
+ return /*#__PURE__*/createRef();
117
+ }, []);
118
+ var openTime = useRef(0);
119
+ var isMounting = useRef(true);
120
+ var didMount = useDidMount();
121
+ var updateAfterDidMount = useRef(true);
122
+ var previousEmojiProvider = useRef(emojiProvider);
123
+ var currentUser = useMemo(function () {
124
+ return emojiProvider.getCurrentUser();
125
+ }, [emojiProvider]);
126
+ var fireAnalytics = useCallback(function (analyticsEvent) {
127
+ if (createAnalyticsEvent) {
128
+ createAndFireEventInElementsChannel(analyticsEvent)(createAnalyticsEvent);
129
+ }
130
+ }, [createAnalyticsEvent]);
131
+ var onEmojiActive = useCallback(function (emojiId, emoji) {
132
+ if (!selectedEmoji || selectedEmoji.id !== (emojiId === null || emojiId === void 0 ? void 0 : emojiId.id)) {
133
+ setSelectedEmoji(emoji);
134
+ }
135
+ }, [selectedEmoji]);
136
+ var onCategoryActivated = useCallback(function (category) {
137
+ if (activeCategory !== category) {
138
+ setActiveCategory(category);
139
+ }
140
+ }, [activeCategory]);
141
+
142
+ var calculateElapsedTime = function calculateElapsedTime() {
143
+ return Date.now() - openTime.current;
144
+ };
145
+
146
+ var onUploadSupported = useCallback(function (supported) {
147
+ setUploadSupported(supported);
148
+ }, []);
149
+ var onDynamicCategoryChange = useCallback(function (categories) {
150
+ setDynamicCategories(categories);
151
+ }, []);
152
+ var onUploadCancelled = useCallback(function () {
153
+ batchedUpdates(function () {
154
+ setUploading(false);
155
+ setUploadErrorMessage(undefined);
156
+ });
157
+ fireAnalytics(uploadCancelButton());
158
+ }, [fireAnalytics]);
159
+ var getDynamicCategories = useCallback(function () {
160
+ if (!emojiProvider.calculateDynamicCategories) {
161
+ return Promise.resolve([]);
162
+ }
44
163
 
45
- function EmojiPickerComponent(props) {
46
- var _this;
164
+ return emojiProvider.calculateDynamicCategories();
165
+ }, [emojiProvider]);
166
+ /**
167
+ * Calculate and set the new state of the component in response to the list of emoji changing for some reason (a search has returned
168
+ * or the frequently used emoji have updated.)
169
+ */
170
+
171
+ var setStateAfterEmojiChange = useCallback(function (_ref2) {
172
+ var searchQuery = _ref2.searchQuery,
173
+ emojiToRender = _ref2.emojiToRender,
174
+ searchEmoji = _ref2.searchEmoji,
175
+ frequentEmoji = _ref2.frequentEmoji;
176
+ // Only enable categories for full emoji list (non-search)
177
+ var disableCategories = !!searchQuery;
178
+
179
+ if (!disableCategories && emojiToRender && emojiToRender.length !== filteredEmojis.length) {
180
+ getDynamicCategories().then(function (categories) {
181
+ onDynamicCategoryChange(categories);
182
+ });
183
+ }
47
184
 
48
- _classCallCheck(this, EmojiPickerComponent);
185
+ if (emojiToRender && !containsEmojiId(emojiToRender, selectedEmoji)) {
186
+ batchedUpdates(function () {
187
+ setSelectedEmoji(undefined); // Only enable categories for full emoji list (non-search)
49
188
 
50
- _this = _super.call(this, props);
189
+ setActiveCategory(null);
190
+ });
191
+ }
51
192
 
52
- _defineProperty(_assertThisInitialized(_this), "onEmojiActive", function (_emojiId, emoji) {
53
- if (_this.state.selectedEmoji !== emoji) {
54
- _this.setState({
55
- selectedEmoji: emoji
56
- });
193
+ batchedUpdates(function () {
194
+ if (emojiToRender) {
195
+ setFilteredEmojis(emojiToRender);
57
196
  }
58
- });
59
197
 
60
- _defineProperty(_assertThisInitialized(_this), "onCategoryActivated", function (category) {
61
- if (_this.state.activeCategory !== category) {
62
- _this.setState({
63
- activeCategory: category
64
- });
198
+ if (searchEmoji) {
199
+ setSearchEmojis(searchEmoji);
65
200
  }
66
- });
67
201
 
68
- _defineProperty(_assertThisInitialized(_this), "onCategorySelected", function (categoryId) {
69
- var emojiProvider = _this.props.emojiProvider;
70
-
71
- if (!categoryId) {
72
- return;
202
+ if (frequentEmoji) {
203
+ setFrequentlyUsedEmojis(frequentEmoji);
73
204
  }
74
205
 
75
- emojiProvider.findInCategory(categoryId).then(function (emojisInCategory) {
76
- var disableCategories = _this.state.disableCategories;
77
-
78
- if (!disableCategories) {
79
- var selectedEmoji;
80
-
81
- if (emojisInCategory && emojisInCategory.length > 0) {
82
- selectedEmoji = getEmojiVariation(emojisInCategory[0], {
83
- skinTone: _this.state.selectedTone
84
- });
85
- }
86
-
87
- var emojiPickerList = _this.refs.emojiPickerList;
88
-
89
- if (emojiPickerList) {
90
- emojiPickerList.reveal(categoryId);
91
- }
92
-
93
- _this.setState({
94
- activeCategory: categoryId,
95
- selectedEmoji: selectedEmoji
96
- });
97
-
98
- _this.fireAnalytics(categoryClickedEvent({
99
- category: categoryId
100
- }));
101
- }
102
- });
103
- });
104
-
105
- _defineProperty(_assertThisInitialized(_this), "onFileChooserClicked", function () {
106
- _this.fireAnalytics(selectedFileEvent());
206
+ setLoading(false);
207
+ setDisableCategories(disableCategories);
107
208
  });
108
-
109
- _defineProperty(_assertThisInitialized(_this), "fireAnalytics", function (analyticsEvent) {
110
- var createAnalyticsEvent = _this.props.createAnalyticsEvent;
111
-
112
- if (createAnalyticsEvent) {
113
- createAndFireEventInElementsChannel(analyticsEvent)(createAnalyticsEvent);
114
- }
209
+ }, [filteredEmojis.length, getDynamicCategories, onDynamicCategoryChange, selectedEmoji]);
210
+ var onFrequentEmojiResult = useCallback(function (frequentEmoji) {
211
+ // change the category of each of the featured emoji
212
+ var recategorised = frequentEmoji.map(function (emoji) {
213
+ var clone = JSON.parse(JSON.stringify(emoji));
214
+ clone.category = frequentCategory;
215
+ return clone;
115
216
  });
116
-
117
- _defineProperty(_assertThisInitialized(_this), "calculateElapsedTime", function () {
118
- return Date.now() - _this.openTime;
119
- });
120
-
121
- _defineProperty(_assertThisInitialized(_this), "onUploadSupported", function (supported) {
122
- _this.setState({
123
- uploadSupported: supported
124
- });
217
+ setStateAfterEmojiChange({
218
+ frequentEmoji: recategorised
125
219
  });
220
+ }, [setStateAfterEmojiChange]);
221
+ var onSearchResult = useCallback(function (searchResults) {
222
+ var frequentlyUsedEmoji = frequentlyUsedEmojis || [];
223
+ var searchQuery = searchResults.query || '';
224
+ /**
225
+ * If there is no user search in the EmojiPicker then it should display all emoji received from the EmojiRepository and should
226
+ * also include a special category of most frequently used emoji (if there are any). This method decides if we are in this 'no search'
227
+ * state and appends the frequent emoji if necessary.
228
+ */
126
229
 
127
- _defineProperty(_assertThisInitialized(_this), "onSearch", function (query) {
128
- var options = {
129
- skinTone: _this.state.selectedTone
130
- };
230
+ var emojiToRender;
131
231
 
132
- if (query !== _this.state.query) {
133
- ufoExperiences['emoji-searched'].start();
134
- ufoExperiences['emoji-searched'].addMetadata({
135
- queryLength: query.length,
136
- source: 'picker'
137
- });
138
- }
232
+ if (!frequentlyUsedEmoji.length || query) {
233
+ emojiToRender = searchResults.emojis;
234
+ } else {
235
+ emojiToRender = [].concat(_toConsumableArray(searchResults.emojis), _toConsumableArray(frequentlyUsedEmoji));
236
+ }
139
237
 
140
- _this.updateEmojis(query, options);
238
+ setStateAfterEmojiChange({
239
+ searchQuery: searchQuery,
240
+ emojiToRender: emojiToRender,
241
+ searchEmoji: searchResults.emojis
141
242
  });
142
-
143
- _defineProperty(_assertThisInitialized(_this), "onSearchResult", function (searchResults) {
144
- var frequentlyUsedEmoji = _this.state.frequentlyUsedEmojis || [];
145
- var searchQuery = searchResults.query || '';
146
-
147
- var emojiToRender = _this.buildQuerySpecificEmojiList(searchQuery, searchResults.emojis, frequentlyUsedEmoji);
148
-
149
- if (searchQuery !== _this.state.query) {
150
- _this.fireAnalytics(pickerSearchedEvent({
151
- queryLength: searchQuery.length,
152
- numMatches: emojiToRender.length
153
- }));
154
-
155
- ufoExperiences['emoji-searched'].success({
156
- metadata: {
157
- emojisLength: emojiToRender.length
158
- }
159
- });
243
+ }, [frequentlyUsedEmojis, query, setStateAfterEmojiChange]);
244
+ var onProviderChange = useMemo(function () {
245
+ return {
246
+ result: onSearchResult
247
+ };
248
+ }, [onSearchResult]);
249
+ /**
250
+ * Updates the emoji displayed by the picker. If there is no query specified then we expect to retrieve all emoji for display,
251
+ * by category, in the picker. This differs from when there is a query in which case we expect to receive a sorted result matching
252
+ * the search.
253
+ */
254
+
255
+ var updateEmojis = useCallback(function (query, options) {
256
+ // if the query is empty then we want the emoji to be in service defined order, unless specified otherwise
257
+ // and we want emoji for the 'frequently used' category to be refreshed as well.
258
+ if (!query) {
259
+ if (!options) {
260
+ options = {};
160
261
  }
161
262
 
162
- _this.setStateAfterEmojiChange(searchQuery, emojiToRender, searchResults.emojis, frequentlyUsedEmoji);
163
- });
263
+ if (!options.sort) {
264
+ options.sort = SearchSort.None;
265
+ } // take a copy of search options so that the frequently used can be limited to 16 without affecting the full emoji query
164
266
 
165
- _defineProperty(_assertThisInitialized(_this), "onFrequentEmojiResult", function (frequentEmoji) {
166
- var _this$state = _this.state,
167
- query = _this$state.query,
168
- searchEmojis = _this$state.searchEmojis; // change the category of each of the featured emoji
169
267
 
170
- var recategorised = frequentEmoji.map(function (emoji) {
171
- var clone = JSON.parse(JSON.stringify(emoji));
172
- clone.category = frequentCategory;
173
- return clone;
268
+ var frequentOptions = _objectSpread(_objectSpread({}, options), {}, {
269
+ sort: SearchSort.None,
270
+ limit: FREQUENTLY_USED_MAX
174
271
  });
175
272
 
176
- var emojiToRender = _this.buildQuerySpecificEmojiList(query, searchEmojis, recategorised);
177
-
178
- _this.setStateAfterEmojiChange(query, emojiToRender, searchEmojis, recategorised);
179
- });
180
-
181
- _defineProperty(_assertThisInitialized(_this), "onDynamicCategoryChange", function (categories) {
182
- _this.setState({
183
- dynamicCategories: categories
184
- });
185
- });
273
+ emojiProvider.getFrequentlyUsed(frequentOptions).then(onFrequentEmojiResult);
274
+ }
186
275
 
187
- _defineProperty(_assertThisInitialized(_this), "onProviderChange", {
188
- result: _this.onSearchResult
276
+ emojiProvider.filter(query, options);
277
+ }, [emojiProvider, onFrequentEmojiResult]);
278
+ var onToneSelected = useCallback(function (toneValue) {
279
+ emojiProvider.setSelectedTone(toneValue);
280
+ updateEmojis(query, {
281
+ skinTone: toneValue
189
282
  });
283
+ setSelectedTone(toneValue);
284
+ }, [emojiProvider, query, updateEmojis]);
285
+ var onToneSelectorCancelled = useCallback(function () {
286
+ fireAnalytics(toneSelectorClosedEvent());
287
+ }, [fireAnalytics]);
288
+ var onSelectWrapper = useCallback(function (emojiId, emoji, event) {
289
+ if (onSelection) {
290
+ onSelection(emojiId, emoji, event);
291
+ fireAnalytics(pickerClickedEvent({
292
+ duration: calculateElapsedTime(),
293
+ emojiId: (emojiId === null || emojiId === void 0 ? void 0 : emojiId.id) || '',
294
+ category: emoji && emoji.category || '',
295
+ type: emoji && emoji.type || '',
296
+ queryLength: query && query.length || 0
297
+ }));
298
+ }
299
+ }, [fireAnalytics, onSelection, query]);
300
+ var onCategorySelected = useCallback(function (categoryId) {
301
+ if (!categoryId) {
302
+ return;
303
+ }
190
304
 
191
- _defineProperty(_assertThisInitialized(_this), "onToneSelected", function (toneValue) {
192
- _this.setState({
193
- selectedTone: toneValue
194
- });
195
-
196
- _this.props.emojiProvider.setSelectedTone(toneValue);
197
-
198
- var _this$state$query = _this.state.query,
199
- query = _this$state$query === void 0 ? '' : _this$state$query;
200
-
201
- _this.updateEmojis(query, {
202
- skinTone: toneValue
203
- });
204
- });
305
+ emojiProvider.findInCategory(categoryId).then(function (emojisInCategory) {
306
+ if (!disableCategories) {
307
+ var newSelectedEmoji;
205
308
 
206
- _defineProperty(_assertThisInitialized(_this), "onToneSelectorCancelled", function () {
207
- _this.fireAnalytics(toneSelectorClosedEvent());
208
- });
209
-
210
- _defineProperty(_assertThisInitialized(_this), "updateEmojis", function (query, options) {
211
- // if the query is empty then we want the emoji to be in service defined order, unless specified otherwise
212
- // and we want emoji for the 'frequently used' category to be refreshed as well.
213
- if (!query) {
214
- if (!options) {
215
- options = {};
309
+ if (emojisInCategory && emojisInCategory.length > 0) {
310
+ newSelectedEmoji = getEmojiVariation(emojisInCategory[0], {
311
+ skinTone: selectedTone
312
+ });
216
313
  }
217
314
 
218
- if (!options.sort) {
219
- options.sort = SearchSort.None;
220
- } // take a copy of search options so that the frequently used can be limited to 16 without affecting the full emoji query
221
-
315
+ if (emojiPickerList.current) {
316
+ emojiPickerList.current.reveal(categoryId);
317
+ }
222
318
 
223
- var frequentOptions = _objectSpread(_objectSpread({}, options), {}, {
224
- sort: SearchSort.None,
225
- limit: FREQUENTLY_USED_MAX
319
+ batchedUpdates(function () {
320
+ setActiveCategory(categoryId);
321
+ setSelectedEmoji(newSelectedEmoji);
226
322
  });
227
-
228
- _this.props.emojiProvider.getFrequentlyUsed(frequentOptions).then(_this.onFrequentEmojiResult);
323
+ fireAnalytics(categoryClickedEvent({
324
+ category: categoryId
325
+ }));
229
326
  }
230
-
231
- _this.props.emojiProvider.filter(query, options);
232
327
  });
233
-
234
- _defineProperty(_assertThisInitialized(_this), "onOpenUpload", function () {
235
- // Prime upload token so it's ready when the user adds
236
- var emojiProvider = _this.props.emojiProvider;
237
-
238
- if (supportsUploadFeature(emojiProvider)) {
239
- emojiProvider.prepareForUpload();
328
+ }, [disableCategories, emojiPickerList, emojiProvider, fireAnalytics, selectedTone]);
329
+ var recordUsageOnSelection = useMemo(function () {
330
+ return createRecordSelectionDefault(emojiProvider, onSelectWrapper, function (analytic) {
331
+ return fireAnalytics(analytic('picker'));
332
+ });
333
+ }, [emojiProvider, fireAnalytics, onSelectWrapper]);
334
+ var formattedErrorMessage = useMemo(function () {
335
+ return uploadErrorMessage ? jsx(FormattedMessage, uploadErrorMessage) : null;
336
+ }, [uploadErrorMessage]);
337
+ var emojiContextValue = useMemo(function () {
338
+ return {
339
+ emoji: {
340
+ emojiProvider: emojiProvider
240
341
  }
342
+ };
343
+ }, [emojiProvider]);
344
+ var onFileChooserClicked = useCallback(function () {
345
+ fireAnalytics(selectedFileEvent());
346
+ }, [fireAnalytics]);
347
+ var onSearch = useCallback(function (searchQuery) {
348
+ var options = {
349
+ skinTone: selectedTone
350
+ };
241
351
 
242
- _this.setState({
243
- uploadErrorMessage: undefined,
244
- uploading: true
352
+ if (query) {
353
+ ufoExperiences['emoji-searched'].start();
354
+ ufoExperiences['emoji-searched'].addMetadata({
355
+ queryLength: query.length,
356
+ source: 'picker'
245
357
  });
358
+ }
246
359
 
247
- _this.fireAnalytics(uploadBeginButton());
248
- });
249
-
250
- _defineProperty(_assertThisInitialized(_this), "onUploadEmoji", function (upload, retry) {
251
- var emojiProvider = _this.props.emojiProvider;
252
-
253
- _this.fireAnalytics(uploadConfirmButton({
254
- retry: retry
255
- }));
256
-
257
- var errorSetter = function errorSetter(message) {
258
- _this.setState({
259
- uploadErrorMessage: message
260
- });
261
- };
262
-
263
- var onSuccess = function onSuccess(emojiDescription) {
264
- _this.setState({
265
- activeCategory: customCategory,
266
- selectedEmoji: emojiDescription,
267
- uploading: false
268
- }); // this.loadEmoji(emojiProvider, emojiDescription);
269
-
270
-
271
- _this.scrollToEndOfList();
272
- };
273
-
274
- uploadEmoji(upload, emojiProvider, errorSetter, onSuccess, _this.fireAnalytics, retry);
275
- });
360
+ if (searchQuery !== query) {
361
+ setQuery(searchQuery);
362
+ }
276
363
 
277
- _defineProperty(_assertThisInitialized(_this), "onTriggerDelete", function (_emojiId, emoji) {
278
- _this.fireAnalytics(deleteBeginEvent({
279
- emojiId: _emojiId.id
280
- }));
364
+ updateEmojis(query, options);
365
+ }, [query, selectedTone, updateEmojis]);
366
+ var onOpenUpload = useCallback(function () {
367
+ // Prime upload token so it's ready when the user adds
368
+ if (supportsUploadFeature(emojiProvider)) {
369
+ emojiProvider.prepareForUpload();
370
+ }
281
371
 
282
- _this.setState({
283
- emojiToDelete: emoji
284
- });
372
+ batchedUpdates(function () {
373
+ setUploadErrorMessage(undefined);
374
+ setUploading(true);
285
375
  });
376
+ fireAnalytics(uploadBeginButton());
377
+ }, [emojiProvider, fireAnalytics]);
378
+ var scrollToEndOfList = useCallback(function () {
379
+ if (typeof window === 'undefined') {
380
+ return;
381
+ }
286
382
 
287
- _defineProperty(_assertThisInitialized(_this), "onCloseDelete", function () {
288
- var emojiToDelete = _this.state.emojiToDelete;
383
+ if (emojiPickerList.current) {
384
+ // Wait a tick to ensure repaint and updated height for picker list
385
+ window.setTimeout(function () {
386
+ var _emojiPickerList$curr;
289
387
 
290
- _this.fireAnalytics(deleteCancelEvent({
291
- emojiId: emojiToDelete && emojiToDelete.id
292
- }));
388
+ (_emojiPickerList$curr = emojiPickerList.current) === null || _emojiPickerList$curr === void 0 ? void 0 : _emojiPickerList$curr.scrollToBottom();
389
+ }, 0);
390
+ }
391
+ }, [emojiPickerList]);
392
+ var onUploadEmoji = useCallback(function (upload, retry) {
393
+ fireAnalytics(uploadConfirmButton({
394
+ retry: retry
395
+ }));
396
+
397
+ var errorSetter = function errorSetter(message) {
398
+ setUploadErrorMessage(message);
399
+ };
293
400
 
294
- _this.setState({
295
- emojiToDelete: undefined
401
+ var onSuccess = function onSuccess(emojiDescription) {
402
+ batchedUpdates(function () {
403
+ setActiveCategory(customCategory);
404
+ setSelectedEmoji(emojiDescription);
405
+ setUploading(false);
296
406
  });
297
- });
298
-
299
- _defineProperty(_assertThisInitialized(_this), "onDeleteEmoji", function (emoji) {
300
- var _this$state2 = _this.state,
301
- emojiToDelete = _this$state2.emojiToDelete,
302
- query = _this$state2.query,
303
- selectedTone = _this$state2.selectedTone;
407
+ scrollToEndOfList();
408
+ };
304
409
 
305
- _this.fireAnalytics(deleteConfirmEvent({
306
- emojiId: emojiToDelete && emojiToDelete.id
410
+ uploadEmoji(upload, emojiProvider, errorSetter, onSuccess, fireAnalytics, retry);
411
+ }, [emojiProvider, fireAnalytics, scrollToEndOfList]);
412
+ var onTriggerDelete = useCallback(function (_emojiId, emoji) {
413
+ if (_emojiId) {
414
+ fireAnalytics(deleteBeginEvent({
415
+ emojiId: _emojiId.id
307
416
  }));
308
-
309
- return _this.props.emojiProvider.deleteSiteEmoji(emoji).then(function (success) {
310
- if (success) {
311
- _this.updateEmojis(query, {
312
- skinTone: selectedTone
313
- });
314
- }
315
-
316
- return success;
317
- });
318
- });
319
-
320
- _defineProperty(_assertThisInitialized(_this), "scrollToEndOfList", function () {
321
- var emojiPickerList = _this.refs.emojiPickerList;
322
-
323
- if (typeof window === 'undefined') {
324
- return;
325
- }
326
-
327
- if (emojiPickerList) {
328
- // Wait a tick to ensure repaint and updated height for picker list
329
- window.setTimeout(function () {
330
- emojiPickerList.scrollToBottom();
331
- }, 0);
417
+ setEmojiToDelete(emoji);
418
+ }
419
+ }, [fireAnalytics]);
420
+ var onCloseDelete = useCallback(function () {
421
+ fireAnalytics(deleteCancelEvent({
422
+ emojiId: emojiToDelete && emojiToDelete.id
423
+ }));
424
+ setEmojiToDelete(undefined);
425
+ }, [emojiToDelete, fireAnalytics]);
426
+ var onDeleteEmoji = useCallback(function (emoji) {
427
+ fireAnalytics(deleteConfirmEvent({
428
+ emojiId: emojiToDelete && emojiToDelete.id
429
+ }));
430
+ return emojiProvider.deleteSiteEmoji(emoji).then(function (success) {
431
+ if (success) {
432
+ updateEmojis(query, {
433
+ skinTone: selectedTone
434
+ });
332
435
  }
333
- });
334
-
335
- _defineProperty(_assertThisInitialized(_this), "onUploadCancelled", function () {
336
- _this.setState({
337
- uploading: false,
338
- uploadErrorMessage: undefined
339
- });
340
-
341
- _this.fireAnalytics(uploadCancelButton());
342
- });
343
436
 
344
- _defineProperty(_assertThisInitialized(_this), "handlePickerRef", function (ref) {
345
- if (_this.props.onPickerRef) {
346
- _this.props.onPickerRef(ref);
347
- }
437
+ return success;
348
438
  });
439
+ }, [emojiProvider, emojiToDelete, fireAnalytics, query, selectedTone, updateEmojis]);
440
+ var onComponentDidMount = useCallback(function () {
441
+ emojiProvider.subscribe(onProviderChange);
442
+ onSearch(query);
349
443
 
350
- _defineProperty(_assertThisInitialized(_this), "onSelectWrapper", function (emojiId, emoji, event) {
351
- var onSelection = _this.props.onSelection;
352
- var query = _this.state.query;
444
+ if (supportsUploadFeature(emojiProvider)) {
445
+ emojiProvider.isUploadSupported().then(onUploadSupported);
446
+ }
353
447
 
354
- if (onSelection) {
355
- onSelection(emojiId, emoji, event);
448
+ if (!hideToneSelector) {
449
+ var _toneEmoji = getToneEmoji(emojiProvider);
356
450
 
357
- _this.fireAnalytics(pickerClickedEvent({
358
- duration: _this.calculateElapsedTime(),
359
- emojiId: emojiId.id || '',
360
- category: emoji && emoji.category || '',
361
- type: emoji && emoji.type || '',
362
- queryLength: query && query.length || 0
363
- }));
451
+ if (isPromise(_toneEmoji)) {
452
+ _toneEmoji.then(function (emoji) {
453
+ return setToneEmoji(emoji);
454
+ });
455
+ } else if (_toneEmoji === undefined || isEmojiDescription(_toneEmoji)) {
456
+ setToneEmoji(_toneEmoji);
364
457
  }
365
- });
366
-
367
- var _emojiProvider = props.emojiProvider,
368
- hideToneSelector = props.hideToneSelector;
369
- _this.state = {
370
- filteredEmojis: [],
371
- searchEmojis: [],
372
- frequentlyUsedEmojis: [],
373
- query: '',
374
- dynamicCategories: [],
375
- selectedTone: !hideToneSelector ? _emojiProvider.getSelectedTone() : undefined,
376
- loading: true,
377
- uploadSupported: false,
378
- uploading: false
379
- };
380
- _this.openTime = 0;
381
- return _this;
458
+ }
459
+ }, [emojiProvider, hideToneSelector, onProviderChange, onSearch, onUploadSupported, query]);
460
+
461
+ if (isMounting.current) {
462
+ // componentWillMount equivalent
463
+ ufoExperiences['emoji-picker-opened'].success();
464
+ openTime.current = Date.now();
465
+ fireAnalytics(openedPickerEvent());
466
+ isMounting.current = false;
382
467
  }
383
468
 
384
- _createClass(EmojiPickerComponent, [{
385
- key: "UNSAFE_componentWillMount",
386
- value: function UNSAFE_componentWillMount() {
387
- ufoExperiences['emoji-picker-opened'].success();
388
- this.openTime = Date.now();
389
- this.fireAnalytics(openedPickerEvent());
469
+ useEffect(function () {
470
+ // componentDidMount logic
471
+ if (didMount && updateAfterDidMount.current) {
472
+ onComponentDidMount();
473
+ updateAfterDidMount.current = false;
474
+ }
475
+ }, [didMount, onComponentDidMount]);
476
+ useEffect(function () {
477
+ previousEmojiProvider.current.unsubscribe(onProviderChange);
478
+ previousEmojiProvider.current = emojiProvider;
479
+ emojiProvider.subscribe(onProviderChange);
480
+
481
+ if (supportsUploadFeature(emojiProvider)) {
482
+ emojiProvider.isUploadSupported().then(onUploadSupported);
390
483
  }
391
- }, {
392
- key: "componentDidMount",
393
- value: function componentDidMount() {
394
- var _this2 = this;
395
-
396
- var _this$props = this.props,
397
- emojiProvider = _this$props.emojiProvider,
398
- hideToneSelector = _this$props.hideToneSelector;
399
- emojiProvider.subscribe(this.onProviderChange);
400
- this.onSearch(this.state.query);
401
-
402
- if (supportsUploadFeature(emojiProvider)) {
403
- emojiProvider.isUploadSupported().then(this.onUploadSupported);
404
- }
405
-
406
- if (!hideToneSelector) {
407
- var toneEmoji = getToneEmoji(emojiProvider);
408
484
 
409
- if (isPromise(toneEmoji)) {
410
- toneEmoji.then(function (emoji) {
411
- return _this2.setState({
412
- toneEmoji: emoji
413
- });
414
- });
415
- } else if (toneEmoji === undefined || isEmojiDescription(toneEmoji)) {
416
- this.setState({
417
- toneEmoji: toneEmoji
418
- });
419
- }
485
+ return function () {
486
+ emojiProvider.unsubscribe(onProviderChange);
487
+ };
488
+ }, [emojiProvider, onProviderChange, onUploadSupported]);
489
+ useEffect(function () {
490
+ // We changed provider which means we subscribed to filter results for a new subscriber.
491
+ // So we refresh the emoji display with onSearch and we do it here, after the new props have
492
+ // been set since onSearch leads to filter being called on the current emojiProvider.
493
+ // (Calling onSearch in a '...Will...' lifecycle method would lead to filter being called on
494
+ // an emojiProvider we have already unsubscribed from)
495
+ onSearch(query);
496
+ }, [emojiProvider, onSearch, query]);
497
+ useEffect(function () {
498
+ // Fire analytics event whenever query changes
499
+ fireAnalytics(pickerSearchedEvent({
500
+ queryLength: query.length,
501
+ numMatches: filteredEmojis.length
502
+ }));
503
+ ufoExperiences['emoji-searched'].success({
504
+ metadata: {
505
+ emojisLength: filteredEmojis.length
420
506
  }
507
+ });
508
+ }, [filteredEmojis.length, fireAnalytics, query]);
509
+ useEffect(function () {
510
+ if (!frequentlyUsedEmojis.length || query) {
511
+ setFilteredEmojis(searchEmojis);
512
+ } else {
513
+ setFilteredEmojis([].concat(_toConsumableArray(searchEmojis), _toConsumableArray(frequentlyUsedEmojis)));
421
514
  }
422
- }, {
423
- key: "componentWillUnmount",
424
- value: function componentWillUnmount() {
425
- var emojiProvider = this.props.emojiProvider;
426
- emojiProvider.unsubscribe(this.onProviderChange);
427
- this.fireAnalytics(closedPickerEvent({
428
- duration: this.calculateElapsedTime()
515
+ }, [frequentlyUsedEmojis, query, searchEmojis]);
516
+ useEffect(function () {
517
+ // Fire analytics on component unmount
518
+ return function () {
519
+ fireAnalytics(closedPickerEvent({
520
+ duration: calculateElapsedTime()
429
521
  }));
430
522
  ufoExperiences['emoji-picker-opened'].abort({
431
523
  metadata: {
@@ -439,187 +531,55 @@ var EmojiPickerComponent = /*#__PURE__*/function (_PureComponent) {
439
531
  reason: 'unmount'
440
532
  }
441
533
  });
442
- }
443
- }, {
444
- key: "UNSAFE_componentWillReceiveProps",
445
- value: function UNSAFE_componentWillReceiveProps(nextProps) {
446
- var prevEmojiProvider = this.props.emojiProvider;
447
- var nextEmojiProvider = nextProps.emojiProvider;
448
-
449
- if (prevEmojiProvider !== nextEmojiProvider) {
450
- if (supportsUploadFeature(nextEmojiProvider)) {
451
- nextEmojiProvider.isUploadSupported().then(this.onUploadSupported);
452
- }
453
- }
454
- }
455
- }, {
456
- key: "componentDidUpdate",
457
- value: function componentDidUpdate(prevProps) {
458
- var prevEmojiProvider = prevProps.emojiProvider;
459
- var currentEmojiProvider = this.props.emojiProvider;
460
-
461
- if (prevEmojiProvider !== currentEmojiProvider) {
462
- prevEmojiProvider.unsubscribe(this.onProviderChange);
463
- currentEmojiProvider.subscribe(this.onProviderChange); // We changed provider which means we subscribed to filter results for a new subscriber.
464
- // So we refresh the emoji display with onSearch and we do it here, after the new props have
465
- // been set since onSearch leads to filter being called on the current emojiProvider.
466
- // (Calling onSearch in a '...Will...' lifecycle method would lead to filter being called on
467
- // an emojiProvider we have already unsubscribed from)
468
-
469
- this.onSearch(this.state.query);
470
- }
471
- }
472
- }, {
473
- key: "buildQuerySpecificEmojiList",
474
- value:
475
- /**
476
- * If there is no user search in the EmojiPicker then it should display all emoji received from the EmojiRepository and should
477
- * also include a special category of most frequently used emoji (if there are any). This method decides if we are in this 'no search'
478
- * state and appends the frequent emoji if necessary.
479
- *
480
- * @param searchEmoji the emoji last received from the EmojiRepository after a search (may be empty)
481
- * @param frequentEmoji the frequently used emoji last received from the EmojiRepository (may be empty)
482
- */
483
- function buildQuerySpecificEmojiList(query, searchEmoji, frequentEmoji) {
484
- // If there are no frequent emoji, or if there was a search query then we want to take the search result exactly as is.
485
- if (!frequentEmoji.length || query) {
486
- return searchEmoji;
487
- }
488
-
489
- return [].concat(_toConsumableArray(searchEmoji), _toConsumableArray(frequentEmoji));
490
- }
491
- /**
492
- * Calculate and set the new state of the component in response to the list of emoji changing for some reason (a search has returned
493
- * or the frequently used emoji have updated.)
494
- */
495
-
496
- }, {
497
- key: "setStateAfterEmojiChange",
498
- value: function setStateAfterEmojiChange(query, emojiToRender, searchEmoji, frequentEmoji) {
499
- var _this3 = this;
500
-
501
- var filteredEmojis = this.state.filteredEmojis; // Only enable categories for full emoji list (non-search)
502
-
503
- var disableCategories = !!query;
504
-
505
- if (!disableCategories && emojiToRender.length !== filteredEmojis.length) {
506
- this.getDynamicCategories().then(function (categories) {
507
- _this3.onDynamicCategoryChange(categories);
508
- });
509
- }
510
-
511
- var selectedEmoji;
512
- var activeCategory;
513
-
514
- if (containsEmojiId(emojiToRender, this.state.selectedEmoji)) {
515
- // Keep existing emoji selected if still in results
516
- selectedEmoji = this.state.selectedEmoji;
517
- activeCategory = this.state.activeCategory;
518
- } else {
519
- selectedEmoji = undefined; // Only enable categories for full emoji list (non-search)
520
-
521
- activeCategory = undefined;
522
- }
523
-
524
- this.setState({
525
- filteredEmojis: emojiToRender,
526
- searchEmojis: searchEmoji,
527
- frequentlyUsedEmojis: frequentEmoji,
528
- selectedEmoji: selectedEmoji,
529
- activeCategory: activeCategory,
530
- disableCategories: disableCategories,
531
- query: query,
532
- loading: false
533
- });
534
- }
535
- }, {
536
- key: "getDynamicCategories",
537
- value: function getDynamicCategories() {
538
- if (!this.props.emojiProvider.calculateDynamicCategories) {
539
- return Promise.resolve([]);
540
- }
541
-
542
- return this.props.emojiProvider.calculateDynamicCategories();
543
- }
544
- }, {
545
- key: "render",
546
- value: function render() {
547
- var _this4 = this;
548
-
549
- var emojiProvider = this.props.emojiProvider;
550
- var _this$state3 = this.state,
551
- activeCategory = _this$state3.activeCategory,
552
- disableCategories = _this$state3.disableCategories,
553
- dynamicCategories = _this$state3.dynamicCategories,
554
- filteredEmojis = _this$state3.filteredEmojis,
555
- loading = _this$state3.loading,
556
- query = _this$state3.query,
557
- selectedEmoji = _this$state3.selectedEmoji,
558
- selectedTone = _this$state3.selectedTone,
559
- toneEmoji = _this$state3.toneEmoji,
560
- emojiToDelete = _this$state3.emojiToDelete,
561
- uploading = _this$state3.uploading,
562
- uploadErrorMessage = _this$state3.uploadErrorMessage,
563
- uploadSupported = _this$state3.uploadSupported;
564
- var recordUsageOnSelection = createRecordSelectionDefault(emojiProvider, this.onSelectWrapper, function (analytic) {
565
- return _this4.fireAnalytics(analytic('picker'));
566
- });
567
- var formattedErrorMessage = uploadErrorMessage ? jsx(FormattedMessage, uploadErrorMessage) : null;
568
- var emojiContextValue = {
569
- emoji: {
570
- emojiProvider: this.props.emojiProvider
571
- }
572
- };
573
- var picker = jsx(LegacyEmojiContextProvider, {
574
- emojiContextValue: emojiContextValue
575
- }, jsx("div", {
576
- css: emojiPicker,
577
- ref: this.handlePickerRef,
578
- "data-emoji-picker-container": true
579
- }, jsx(CategorySelector, {
580
- activeCategoryId: activeCategory,
581
- dynamicCategories: dynamicCategories,
582
- disableCategories: disableCategories,
583
- onCategorySelected: this.onCategorySelected
584
- }), jsx(EmojiPickerList, {
585
- emojis: filteredEmojis,
586
- currentUser: emojiProvider.getCurrentUser(),
587
- onEmojiSelected: recordUsageOnSelection,
588
- onEmojiActive: this.onEmojiActive,
589
- onEmojiDelete: this.onTriggerDelete,
590
- onCategoryActivated: this.onCategoryActivated,
591
- onSearch: this.onSearch,
592
- query: query,
593
- selectedTone: selectedTone,
594
- loading: loading,
595
- ref: "emojiPickerList",
596
- initialUploadName: query,
597
- onToneSelected: this.onToneSelected,
598
- onToneSelectorCancelled: this.onToneSelectorCancelled,
599
- toneEmoji: toneEmoji,
600
- uploading: uploading,
601
- emojiToDelete: emojiToDelete,
602
- uploadErrorMessage: formattedErrorMessage,
603
- uploadEnabled: uploadSupported && !uploading,
604
- onUploadEmoji: this.onUploadEmoji,
605
- onUploadCancelled: this.onUploadCancelled,
606
- onDeleteEmoji: this.onDeleteEmoji,
607
- onCloseDelete: this.onCloseDelete,
608
- onFileChooserClicked: this.onFileChooserClicked,
609
- onOpenUpload: this.onOpenUpload
610
- }), jsx(EmojiPickerFooter, {
611
- selectedEmoji: selectedEmoji,
612
- isUploading: uploading
613
- })));
614
- return picker;
615
- }
616
- }]);
617
-
618
- return EmojiPickerComponent;
619
- }(PureComponent);
620
-
621
- _defineProperty(EmojiPickerComponent, "defaultProps", {
622
- onSelection: function onSelection() {}
623
- });
624
-
625
- export { EmojiPickerComponent as default };
534
+ };
535
+ }, [fireAnalytics]);
536
+ useEffect(function () {
537
+ // Unsubscribe emojiProvider on component unmount
538
+ return function () {
539
+ emojiProvider.unsubscribe(onProviderChange);
540
+ };
541
+ }, [emojiProvider, onProviderChange]);
542
+ var showPreview = selectedEmoji && !uploading;
543
+ return jsx(LegacyEmojiContextProvider, {
544
+ emojiContextValue: emojiContextValue
545
+ }, jsx("div", {
546
+ css: emojiPicker(showPreview),
547
+ ref: onPickerRef,
548
+ "data-emoji-picker-container": true
549
+ }, jsx(CategorySelector, {
550
+ activeCategoryId: activeCategory,
551
+ dynamicCategories: dynamicCategories,
552
+ disableCategories: disableCategories,
553
+ onCategorySelected: onCategorySelected
554
+ }), jsx(EmojiPickerList, {
555
+ emojis: filteredEmojis,
556
+ currentUser: currentUser,
557
+ onEmojiSelected: recordUsageOnSelection,
558
+ onEmojiActive: onEmojiActive,
559
+ onEmojiDelete: onTriggerDelete,
560
+ onCategoryActivated: onCategoryActivated,
561
+ onSearch: onSearch,
562
+ query: query,
563
+ selectedTone: selectedTone,
564
+ loading: loading,
565
+ ref: emojiPickerList,
566
+ initialUploadName: query,
567
+ onToneSelected: onToneSelected,
568
+ onToneSelectorCancelled: onToneSelectorCancelled,
569
+ toneEmoji: toneEmoji,
570
+ uploading: uploading,
571
+ emojiToDelete: emojiToDelete,
572
+ uploadErrorMessage: formattedErrorMessage,
573
+ uploadEnabled: uploadSupported && !uploading,
574
+ onUploadEmoji: onUploadEmoji,
575
+ onUploadCancelled: onUploadCancelled,
576
+ onDeleteEmoji: onDeleteEmoji,
577
+ onCloseDelete: onCloseDelete,
578
+ onFileChooserClicked: onFileChooserClicked,
579
+ onOpenUpload: onOpenUpload
580
+ }), showPreview && jsx(EmojiPickerFooter, {
581
+ selectedEmoji: selectedEmoji
582
+ })));
583
+ };
584
+
585
+ export default /*#__PURE__*/memo(EmojiPickerComponent);