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