emoji-picker-react 4.22.1 → 4.22.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,7 @@ The most popular fully customizable emoji picker for React.
4
4
 
5
5
  [![npm downloads](https://img.shields.io/npm/dm/emoji-picker-react.svg)](https://www.npmjs.com/package/emoji-picker-react)
6
6
 
7
- **[Live Demo](https://ealush.com/emoji-picker-react)** | **[Report a Bug](https://github.com/ealush/emoji-picker-react/issues)**
7
+ **[Live Demo](https://ealush.com/emoji-picker-react)** | **[Report a Bug](https://github.com/ealush/emoji-picker-react/issues)** | **[Sponsor](https://github.com/sponsors/ealush)**
8
8
 
9
9
  ![image](https://github.com/ealush/emoji-picker-react/assets/11255103/48901306-e7fd-49cd-8f1e-9b214083a61d)
10
10
 
@@ -110,6 +110,10 @@ On older versions only, the workaround was adding this to your HTML:
110
110
  </script>
111
111
  ```
112
112
 
113
+ ## Support Emoji Picker React
114
+
115
+ Emoji Picker React is independently maintained. If your team relies on it, you can help fund ongoing maintenance and releases through [GitHub Sponsors](https://github.com/sponsors/ealush). Organizations can also support the project through [Tidelift](https://tidelift.com/subscription/pkg/npm-emoji-picker-react).
116
+
113
117
  ## More from the maintainer
114
118
 
115
119
  Building complex forms? Check out [**Vest**](https://vestjs.dev) — a validation framework for stateful, async, and dependent validation.
@@ -179,27 +179,54 @@ function compareConfig(prev, next) {
179
179
  var _prev$customEmojis, _next$customEmojis;
180
180
  var prevCustomEmojis = (_prev$customEmojis = prev.customEmojis) != null ? _prev$customEmojis : [];
181
181
  var nextCustomEmojis = (_next$customEmojis = next.customEmojis) != null ? _next$customEmojis : [];
182
- return prev.open === next.open && prev.emojiVersion === next.emojiVersion && prev.reactionsDefaultOpen === next.reactionsDefaultOpen && prev.searchPlaceHolder === next.searchPlaceHolder && prev.searchPlaceholder === next.searchPlaceholder && prev.searchClearButtonLabel === next.searchClearButtonLabel && prev.defaultSkinTone === next.defaultSkinTone && prev.skinTonesDisabled === next.skinTonesDisabled && prev.autoFocusSearch === next.autoFocusSearch && prev.emojiStyle === next.emojiStyle && prev.theme === next.theme && prev.suggestedEmojisMode === next.suggestedEmojisMode && prev.lazyLoadEmojis === next.lazyLoadEmojis && prev.className === next.className && prev.height === next.height && prev.width === next.width && prev.style === next.style && prev.searchDisabled === next.searchDisabled && prev.skinTonePickerLocation === next.skinTonePickerLocation && prevCustomEmojis.length === nextCustomEmojis.length && customEmojisKey(prevCustomEmojis) === customEmojisKey(nextCustomEmojis) && categoriesKey(prev.categories) === categoriesKey(next.categories) && prev.emojiData === next.emojiData;
182
+ return prev.open === next.open && prev.emojiVersion === next.emojiVersion && prev.reactionsDefaultOpen === next.reactionsDefaultOpen && prev.searchPlaceHolder === next.searchPlaceHolder && prev.searchPlaceholder === next.searchPlaceholder && prev.searchClearButtonLabel === next.searchClearButtonLabel && prev.defaultSkinTone === next.defaultSkinTone && prev.skinTonesDisabled === next.skinTonesDisabled && prev.autoFocusSearch === next.autoFocusSearch && prev.emojiStyle === next.emojiStyle && prev.theme === next.theme && prev.suggestedEmojisMode === next.suggestedEmojisMode && prev.lazyLoadEmojis === next.lazyLoadEmojis && prev.className === next.className && prev.height === next.height && prev.width === next.width && prev.style === next.style && prev.searchDisabled === next.searchDisabled && prev.skinTonePickerLocation === next.skinTonePickerLocation && prevCustomEmojis.length === nextCustomEmojis.length && customEmojisEqual(prevCustomEmojis, nextCustomEmojis) && categoriesEqual(prev.categories, next.categories) && prev.emojiData === next.emojiData;
183
183
  }
184
184
  /**
185
- * Content identity for custom emojis. Length alone misses regroups and
186
- * swaps, which would leave merged categories, search, and sections stale.
185
+ * Structural content equality for custom emojis. Length alone misses
186
+ * regroups and swaps, which would leave merged categories, search, and
187
+ * sections stale. Fields are compared element-wise (never serialized
188
+ * with delimiters) so user-controlled values cannot collide.
187
189
  */
188
- function customEmojisKey(customEmojis) {
189
- return customEmojis.map(function (emoji) {
190
- var _emoji$group;
191
- return emoji.id + ":" + ((_emoji$group = emoji.group) != null ? _emoji$group : '') + ":" + emoji.names.join(',') + ":" + emoji.imgUrl;
192
- }).join('|');
190
+ function customEmojisEqual(prev, next) {
191
+ if (prev.length !== next.length) {
192
+ return false;
193
+ }
194
+ return prev.every(function (emoji, index) {
195
+ var _emoji$group, _other$group;
196
+ var other = next[index];
197
+ return emoji.id === other.id && ((_emoji$group = emoji.group) != null ? _emoji$group : '') === ((_other$group = other.group) != null ? _other$group : '') && emoji.imgUrl === other.imgUrl && emoji.names.length === other.names.length && emoji.names.every(function (name, nameIndex) {
198
+ return name === other.names[nameIndex];
199
+ });
200
+ });
193
201
  }
194
202
  /**
195
- * Content identity for the categories input. Order, labels, icons, and
196
- * group selection all flow into the merged configuration.
203
+ * Structural content equality for the categories input. Order, labels,
204
+ * group selection, and icon identity all flow into the merged
205
+ * configuration. Icons compare by reference: swapping one icon element
206
+ * for another must rebuild, while a stable reference stays cheap.
197
207
  */
198
- function categoriesKey(categories) {
199
- return (categories != null ? categories : []).map(function (entry) {
200
- var _entry$group;
201
- return typeof entry === 'string' ? entry : entry.category + ":" + entry.name + ":" + ((_entry$group = entry.group) != null ? _entry$group : '') + ":" + (entry.icon ? '1' : '');
202
- }).join('|');
208
+ function categoriesEqual(prev, next) {
209
+ var prevEntries = prev != null ? prev : [];
210
+ var nextEntries = next != null ? next : [];
211
+ if (prevEntries.length !== nextEntries.length) {
212
+ return false;
213
+ }
214
+ return prevEntries.every(function (entry, index) {
215
+ return categoryEntriesEqual(entry, nextEntries[index]);
216
+ });
217
+ }
218
+ /**
219
+ * One categories entry compared structurally. Icons compare by reference:
220
+ * swapping one icon element for another rebuilds, a stable reference stays
221
+ * cheap. Delimited serialization is avoided so user-controlled values
222
+ * cannot collide.
223
+ */
224
+ function categoryEntriesEqual(entry, other) {
225
+ var _entry$group, _other$group2;
226
+ if (typeof entry === 'string' || typeof other === 'string') {
227
+ return entry === other;
228
+ }
229
+ return entry.category === other.category && entry.name === other.name && ((_entry$group = entry.group) != null ? _entry$group : '') === ((_other$group2 = other.group) != null ? _other$group2 : '') && entry.icon === other.icon;
203
230
  }
204
231
 
205
232
  var DEFAULT_REACTIONS = ['1f44d', '2764-fe0f', '1f603', '1f622', '1f64f', '1f44e', '1f621'];
@@ -30534,7 +30561,7 @@ function categoryNameFromDom($category) {
30534
30561
  function useActiveCategoryScrollDetection(_ref) {
30535
30562
  var setActiveCategory = _ref.setActiveCategory,
30536
30563
  setVisibleCategories = _ref.setVisibleCategories,
30537
- categoryIdentitiesKey = _ref.categoryIdentitiesKey;
30564
+ categories = _ref.categories;
30538
30565
  var BodyRef = useBodyRef();
30539
30566
  React.useEffect(function () {
30540
30567
  var visibleCategories = new Map();
@@ -30586,7 +30613,7 @@ function useActiveCategoryScrollDetection(_ref) {
30586
30613
  return function () {
30587
30614
  observer.disconnect();
30588
30615
  };
30589
- }, [BodyRef, categoryIdentitiesKey, setActiveCategory, setVisibleCategories]);
30616
+ }, [BodyRef, categories, setActiveCategory, setVisibleCategories]);
30590
30617
  }
30591
30618
 
30592
30619
  function useScrollCategoryIntoView() {
@@ -30980,16 +31007,12 @@ function CategoryNavigation() {
30980
31007
  var _usePickerDataContext = usePickerDataContext(),
30981
31008
  customGroups = _usePickerDataContext.customGroups,
30982
31009
  emojiData = _usePickerDataContext.emojiData;
30983
- // Rendered section identities. Passed to the scroll-detection hook so
30984
- // added/removed sections are (re-)subscribed; stable across renders
30985
- // unless the effective category list changes.
30986
- var categoryIdentitiesKey = categoriesConfig.map(function (entry) {
30987
- return categoryIdFromCategoryConfig(entry);
30988
- }).join('|');
31010
+ // The observer re-subscribes when the merged categories reference
31011
+ // changes (sections added/removed); the reference is stable otherwise.
30989
31012
  useActiveCategoryScrollDetection({
30990
31013
  setActiveCategory: setActiveCategory,
30991
31014
  setVisibleCategories: setVisibleCategories,
30992
- categoryIdentitiesKey: categoryIdentitiesKey
31015
+ categories: categoriesConfig
30993
31016
  });
30994
31017
  var visibleCategories = categoriesConfig.filter(function (categoryConfig) {
30995
31018
  if (isCustomCategory(categoryConfig) && hideCustomCategory) {