emoji-picker-react 4.21.1 → 4.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -172,7 +172,27 @@ function compareConfig(prev, next) {
172
172
  var _prev$customEmojis, _next$customEmojis;
173
173
  var prevCustomEmojis = (_prev$customEmojis = prev.customEmojis) != null ? _prev$customEmojis : [];
174
174
  var nextCustomEmojis = (_next$customEmojis = next.customEmojis) != null ? _next$customEmojis : [];
175
- 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 && prev.emojiData === next.emojiData;
175
+ 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;
176
+ }
177
+ /**
178
+ * Content identity for custom emojis. Length alone misses regroups and
179
+ * swaps, which would leave merged categories, search, and sections stale.
180
+ */
181
+ function customEmojisKey(customEmojis) {
182
+ return customEmojis.map(function (emoji) {
183
+ var _emoji$group;
184
+ return emoji.id + ":" + ((_emoji$group = emoji.group) != null ? _emoji$group : '') + ":" + emoji.names.join(',') + ":" + emoji.imgUrl;
185
+ }).join('|');
186
+ }
187
+ /**
188
+ * Content identity for the categories input. Order, labels, icons, and
189
+ * group selection all flow into the merged configuration.
190
+ */
191
+ function categoriesKey(categories) {
192
+ return (categories != null ? categories : []).map(function (entry) {
193
+ var _entry$group;
194
+ return typeof entry === 'string' ? entry : entry.category + ":" + entry.name + ":" + ((_entry$group = entry.group) != null ? _entry$group : '') + ":" + (entry.icon ? '1' : '');
195
+ }).join('|');
176
196
  }
177
197
 
178
198
  var DEFAULT_REACTIONS = ['1f44d', '2764-fe0f', '1f603', '1f622', '1f64f', '1f44e', '1f621'];
@@ -321,6 +341,34 @@ var SuggestedRecent = {
321
341
  name: 'Recently Used',
322
342
  category: Categories.SUGGESTED
323
343
  };
344
+ /**
345
+ * Stable identity for a category entry. Custom groups are namespaced so
346
+ * duplicate `{ category: CUSTOM }` configs no longer collide in React
347
+ * keys, scroll targets, and active-tab detection.
348
+ */
349
+ function categoryIdFromCategoryConfig(categoryConfig) {
350
+ var category = categoryFromCategoryConfig(categoryConfig);
351
+ if (isCustomGroupConfig(categoryConfig)) {
352
+ return category + ":" + categoryConfig.group;
353
+ }
354
+ return category;
355
+ }
356
+ function isCustomGroupConfig(categoryConfig) {
357
+ if (categoryConfig.category !== Categories.CUSTOM) {
358
+ return false;
359
+ }
360
+ var group = categoryConfig.group;
361
+ return typeof group === 'string' && group.length > 0;
362
+ }
363
+ /**
364
+ * The `CustomEmoji` group rendered by a category entry, if any.
365
+ */
366
+ function customGroupFromCategoryConfig(categoryConfig) {
367
+ if (isCustomGroupConfig(categoryConfig)) {
368
+ return categoryConfig.group;
369
+ }
370
+ return undefined;
371
+ }
324
372
  var configByCategory = (_configByCategory = {}, _configByCategory[Categories.SUGGESTED] = {
325
373
  category: Categories.SUGGESTED,
326
374
  name: 'Frequently Used'
@@ -363,14 +411,17 @@ function categoryFromCategoryConfig(category) {
363
411
  function categoryNameFromCategoryConfig(category) {
364
412
  return category.name;
365
413
  }
366
- function mergeCategoriesConfig(userCategoriesConfig, modifiers, emojiData) {
367
- var _userCategoriesConfig;
414
+ function mergeCategoriesConfig(userCategoriesConfig, modifiers, emojiData, customEmojis) {
415
+ var _userCategoriesConfig, _userCategoriesConfig2;
368
416
  if (userCategoriesConfig === void 0) {
369
417
  userCategoriesConfig = [];
370
418
  }
371
419
  if (modifiers === void 0) {
372
420
  modifiers = {};
373
421
  }
422
+ if (customEmojis === void 0) {
423
+ customEmojis = [];
424
+ }
374
425
  var extra = function () {
375
426
  // 1. Start with localized categories from emojiData
376
427
  var fromData = emojiData != null && emojiData.categories ? Object.fromEntries(Object.entries(emojiData.categories).filter(function (_ref) {
@@ -389,15 +440,50 @@ function mergeCategoriesConfig(userCategoriesConfig, modifiers, emojiData) {
389
440
  return fromData;
390
441
  }();
391
442
  var base = baseCategoriesConfig(extra);
392
- if (!((_userCategoriesConfig = userCategoriesConfig) != null && _userCategoriesConfig.length)) {
393
- return base;
394
- }
395
- return userCategoriesConfig.map(function (category) {
443
+ var explicit = (_userCategoriesConfig = userCategoriesConfig) != null && _userCategoriesConfig.length ? userCategoriesConfig.map(mapUserEntry) : base;
444
+ // Groups without a `categories` entry get an appended section so their
445
+ // emojis always render somewhere — unless the user opted out of customs
446
+ // entirely by listing `categories` without CUSTOM. `categories` remains
447
+ // the override for order, display name, and icon.
448
+ // https://github.com/ealush/emoji-picker-react/issues/510
449
+ var customInPlay = !((_userCategoriesConfig2 = userCategoriesConfig) != null && _userCategoriesConfig2.length) || userCategoriesConfig.some(function (entry) {
450
+ return entry === Categories.CUSTOM || typeof entry !== 'string' && entry.category === Categories.CUSTOM;
451
+ });
452
+ var listedGroups = new Set(explicit.map(function (entry) {
453
+ return customGroupFromCategoryConfig(entry);
454
+ }).filter(function (group) {
455
+ return !!group;
456
+ }));
457
+ var appended = !customInPlay ? [] : Array.from(new Set(customEmojis.map(function (emoji) {
458
+ return emoji.group;
459
+ }).filter(function (group) {
460
+ return !!group;
461
+ }))).filter(function (group) {
462
+ return !listedGroups.has(group);
463
+ }).map(function (group) {
464
+ return {
465
+ category: Categories.CUSTOM,
466
+ name: group,
467
+ group: group
468
+ };
469
+ });
470
+ // Collapse duplicate entries (same identity twice renders the same
471
+ // section twice under one React key); first occurrence wins.
472
+ var seen = new Set();
473
+ return explicit.concat(appended).filter(function (entry) {
474
+ var id = categoryIdFromCategoryConfig(entry);
475
+ if (seen.has(id)) {
476
+ return false;
477
+ }
478
+ seen.add(id);
479
+ return true;
480
+ });
481
+ function mapUserEntry(category) {
396
482
  if (typeof category === 'string') {
397
483
  return getBaseConfigByCategory(category, extra[category]);
398
484
  }
399
485
  return _extends({}, getBaseConfigByCategory(category.category, extra[category.category]), category);
400
- });
486
+ }
401
487
  }
402
488
  function getBaseConfigByCategory(category, modifier) {
403
489
  if (modifier === void 0) {
@@ -428,7 +514,7 @@ function mergeConfig(userConfig) {
428
514
  var config = Object.assign(base, userConfig);
429
515
  var categories = mergeCategoriesConfig(userConfig.categories, {
430
516
  suggestionMode: config.suggestedEmojisMode
431
- }, userConfig.emojiData);
517
+ }, userConfig.emojiData, userConfig.customEmojis);
432
518
  config.hiddenEmojis.forEach(function (emoji) {
433
519
  config.unicodeToHide.add(emoji);
434
520
  });
@@ -490,7 +576,6 @@ function PickerConfigProvider(_ref) {
490
576
  }, children);
491
577
  }
492
578
  function useSetConfig(config) {
493
- var _config$customEmojis;
494
579
  var _React$useState = useState(function () {
495
580
  return mergeConfig(config);
496
581
  }),
@@ -503,7 +588,11 @@ function useSetConfig(config) {
503
588
  setMergedConfig(mergeConfig(config));
504
589
  // not gonna...
505
590
  // eslint-disable-next-line react-hooks/exhaustive-deps
506
- }, [(_config$customEmojis = config.customEmojis) == null ? void 0 : _config$customEmojis.length, config.open, config.emojiVersion, config.reactionsDefaultOpen, config.searchPlaceHolder, config.searchPlaceholder, config.searchClearButtonLabel, config.defaultSkinTone, config.skinTonesDisabled, config.autoFocusSearch, config.emojiStyle, config.theme, config.suggestedEmojisMode, config.lazyLoadEmojis, config.className, config.height, config.width, config.searchDisabled, config.skinTonePickerLocation, config.allowExpandReactions, config.emojiData]);
591
+ }, [
592
+ // New references rebuild merged categories and data even at equal
593
+ // length; compareConfig above still gates no-op updates so inline
594
+ // literals don't loop.
595
+ config.categories, config.customEmojis, config.open, config.emojiVersion, config.reactionsDefaultOpen, config.searchPlaceHolder, config.searchPlaceholder, config.searchClearButtonLabel, config.defaultSkinTone, config.skinTonesDisabled, config.autoFocusSearch, config.emojiStyle, config.theme, config.suggestedEmojisMode, config.lazyLoadEmojis, config.className, config.height, config.width, config.searchDisabled, config.skinTonePickerLocation, config.allowExpandReactions, config.emojiData]);
507
596
  return mergedConfig;
508
597
  }
509
598
  function usePickerConfig() {
@@ -26860,8 +26949,9 @@ function useIsMounted() {
26860
26949
  var PickerDataContext = /*#__PURE__*/React__default.createContext({
26861
26950
  emojiData: {},
26862
26951
  allEmojis: [],
26863
- allEmojisByUnified: {},
26864
- searchIndex: {},
26952
+ allEmojisByUnified: /*#__PURE__*/Object.create(null),
26953
+ searchIndex: /*#__PURE__*/Object.create(null),
26954
+ customGroups: /*#__PURE__*/Object.create(null),
26865
26955
  emojiByUnified: emojiByUnified,
26866
26956
  activeVariationFromUnified: function activeVariationFromUnified() {
26867
26957
  return null;
@@ -26876,13 +26966,28 @@ function PickerDataProvider(_ref) {
26876
26966
  var emojiData = genericEmojiData || defaultEmojiData;
26877
26967
  // Clone to avoid mutation of shared source
26878
26968
  var newData = JSON.parse(JSON.stringify(emojiData));
26969
+ // Group names and emoji ids are user-controlled strings: use
26970
+ // null-prototype dictionaries so names like `__proto__` behave as
26971
+ // ordinary data instead of resolving Object.prototype members.
26972
+ var customGroups = Object.create(null);
26879
26973
  if (customEmojis && customEmojis.length > 0) {
26880
- newData.emojis[Categories.CUSTOM] = customEmojis.map(customToRegularEmoji);
26974
+ for (var _iterator = _createForOfIteratorHelperLoose(customEmojis), _step; !(_step = _iterator()).done;) {
26975
+ var _customGroups$emoji$g;
26976
+ var emoji = _step.value;
26977
+ if (!emoji.group) {
26978
+ continue;
26979
+ }
26980
+ customGroups[emoji.group] = (_customGroups$emoji$g = customGroups[emoji.group]) != null ? _customGroups$emoji$g : [];
26981
+ customGroups[emoji.group].push(customToRegularEmoji(emoji));
26982
+ }
26983
+ newData.emojis[Categories.CUSTOM] = customEmojis.filter(function (emoji) {
26984
+ return !emoji.group;
26985
+ }).map(customToRegularEmoji);
26881
26986
  }
26882
26987
  var emojis = newData.emojis || {};
26883
- var allEmojis = Object.values(emojis).flat();
26884
- var allEmojisByUnified = {};
26885
- var searchIndex = {};
26988
+ var allEmojis = Object.values(emojis).concat(Object.values(customGroups)).flat();
26989
+ var allEmojisByUnified = Object.create(null);
26990
+ var searchIndex = Object.create(null);
26886
26991
  allEmojis.forEach(function (emoji) {
26887
26992
  var unified = emoji[EmojiProperties.unified];
26888
26993
  allEmojisByUnified[unified] = emoji;
@@ -26897,7 +27002,7 @@ function PickerDataProvider(_ref) {
26897
27002
  var joinedNameString = (emoji[EmojiProperties.name] || []).join('').toLowerCase().split('');
26898
27003
  joinedNameString.forEach(function (_char) {
26899
27004
  var _searchIndex$_char;
26900
- searchIndex[_char] = (_searchIndex$_char = searchIndex[_char]) != null ? _searchIndex$_char : {};
27005
+ searchIndex[_char] = (_searchIndex$_char = searchIndex[_char]) != null ? _searchIndex$_char : Object.create(null);
26901
27006
  searchIndex[_char][unified] = emoji;
26902
27007
  });
26903
27008
  });
@@ -26905,7 +27010,8 @@ function PickerDataProvider(_ref) {
26905
27010
  emojiData: newData,
26906
27011
  allEmojis: allEmojis,
26907
27012
  allEmojisByUnified: allEmojisByUnified,
26908
- searchIndex: searchIndex
27013
+ searchIndex: searchIndex,
27014
+ customGroups: customGroups
26909
27015
  };
26910
27016
  }, [genericEmojiData, customEmojis]);
26911
27017
  var emojiByUnified = React__default.useCallback(function (unified) {
@@ -26927,7 +27033,8 @@ function usePickerDataContext() {
26927
27033
  function useGetEmojisByCategory() {
26928
27034
  var _usePickerDataContext = usePickerDataContext(),
26929
27035
  emojiData = _usePickerDataContext.emojiData,
26930
- emojiByUnified = _usePickerDataContext.emojiByUnified;
27036
+ emojiByUnified = _usePickerDataContext.emojiByUnified,
27037
+ customGroups = _usePickerDataContext.customGroups;
26931
27038
  var suggestedEmojisModeConfig = useSuggestedEmojisModeConfig();
26932
27039
  var _useUpdateSuggested = useUpdateSuggested(),
26933
27040
  suggestedUpdated = _useUpdateSuggested[0];
@@ -26948,11 +27055,15 @@ function useGetEmojisByCategory() {
26948
27055
  }).filter(Boolean);
26949
27056
  // eslint-disable-next-line react-hooks/exhaustive-deps
26950
27057
  }, [isMounted, suggestedUpdated, suggestedEmojisModeConfig, emojiByUnified]);
26951
- return function getEmojisByCategory(category) {
27058
+ return function getEmojisByCategory(category, group) {
26952
27059
  var _emojiData$emojis$cat, _emojiData$emojis;
26953
27060
  if (category === Categories.SUGGESTED) {
26954
27061
  return suggested;
26955
27062
  }
27063
+ if (category === Categories.CUSTOM && group) {
27064
+ var _customGroups$group;
27065
+ return (_customGroups$group = customGroups[group]) != null ? _customGroups$group : [];
27066
+ }
26956
27067
  return (_emojiData$emojis$cat = (_emojiData$emojis = emojiData.emojis) == null ? void 0 : _emojiData$emojis[category]) != null ? _emojiData$emojis$cat : [];
26957
27068
  };
26958
27069
  }
@@ -29586,11 +29697,10 @@ function EmojiCategory(_ref) {
29586
29697
  hiddenOnSearch = _ref.hiddenOnSearch,
29587
29698
  height = _ref.height,
29588
29699
  emojisPerRow = _ref.emojisPerRow;
29589
- var category = categoryFromCategoryConfig(categoryConfig);
29590
29700
  var categoryName = categoryNameFromCategoryConfig(categoryConfig);
29591
29701
  return createElement("li", {
29592
29702
  className: cx(styles$7.category, hidden && commonStyles.hidden, hiddenOnSearch && commonInteractionStyles.hiddenOnSearch),
29593
- "data-name": category,
29703
+ "data-name": categoryIdFromCategoryConfig(categoryConfig),
29594
29704
  role: "rowgroup",
29595
29705
  "aria-label": categoryName
29596
29706
  }, createElement("h2", {
@@ -29665,7 +29775,7 @@ function MeasureEmoji() {
29665
29775
  return null;
29666
29776
  }
29667
29777
  var firstCategory = categories[0];
29668
- var dummyEmoji = getEmojisByCategory(categoryFromCategoryConfig(firstCategory))[0];
29778
+ var dummyEmoji = firstCategory ? getEmojisByCategory(categoryFromCategoryConfig(firstCategory), customGroupFromCategoryConfig(firstCategory))[0] : undefined;
29669
29779
  var unified = dummyEmoji ? emojiUnified(dummyEmoji, activeSkinTone) : '';
29670
29780
  if (!dummyEmoji) {
29671
29781
  return null;
@@ -29719,22 +29829,24 @@ function EmojiList(_ref) {
29719
29829
  role: "grid"
29720
29830
  }, createElement(MeasureEmoji, null), categories.map(function (categoryConfig, index) {
29721
29831
  var category = categoryFromCategoryConfig(categoryConfig);
29832
+ var categoryId = categoryIdFromCategoryConfig(categoryConfig);
29833
+ var group = customGroupFromCategoryConfig(categoryConfig);
29722
29834
  var currentOffset = topOffset;
29723
- var categoryHeight = categoryHeights[category];
29835
+ var categoryHeight = categoryHeights[categoryId];
29724
29836
  if (categoryHeight) {
29725
29837
  topOffset += categoryHeight + labelHeight;
29726
29838
  }
29727
29839
  return createElement(RenderCategory, {
29728
- key: category,
29729
- categoryEmojis: getEmojisByCategory(category),
29840
+ key: categoryId,
29841
+ categoryEmojis: getEmojisByCategory(category, group),
29730
29842
  categoryConfig: categoryConfig,
29731
29843
  topOffset: currentOffset,
29732
29844
  isFirstCategory: index === 0,
29733
29845
  onHeightReady: function onHeightReady(height) {
29734
- if (categoryHeights[category] !== height) {
29846
+ if (categoryHeights[categoryId] !== height) {
29735
29847
  setCategoryHeights(function (prev) {
29736
29848
  var _extends2;
29737
- return _extends({}, prev, (_extends2 = {}, _extends2[category] = height, _extends2));
29849
+ return _extends({}, prev, (_extends2 = {}, _extends2[categoryId] = height, _extends2));
29738
29850
  });
29739
29851
  }
29740
29852
  },
@@ -29758,7 +29870,7 @@ function RenderCategory(_ref2) {
29758
29870
  // the deadlock; the observer takes over from there.
29759
29871
  // https://github.com/ealush/emoji-picker-react/issues/469
29760
29872
  // https://github.com/ealush/emoji-picker-react/issues/475
29761
- var isCategoryVisible = isFirstCategory || visibleCategories.includes(categoryConfig.category);
29873
+ var isCategoryVisible = isFirstCategory || visibleCategories.includes(categoryIdFromCategoryConfig(categoryConfig));
29762
29874
  var _useEmojiVirtualizati = useEmojiVirtualization({
29763
29875
  categoryEmojis: categoryEmojis,
29764
29876
  topOffset: topOffset,
@@ -30420,7 +30532,8 @@ function categoryNameFromDom($category) {
30420
30532
 
30421
30533
  function useActiveCategoryScrollDetection(_ref) {
30422
30534
  var setActiveCategory = _ref.setActiveCategory,
30423
- setVisibleCategories = _ref.setVisibleCategories;
30535
+ setVisibleCategories = _ref.setVisibleCategories,
30536
+ categoryIdentitiesKey = _ref.categoryIdentitiesKey;
30424
30537
  var BodyRef = useBodyRef();
30425
30538
  useEffect(function () {
30426
30539
  var visibleCategories = new Map();
@@ -30472,7 +30585,7 @@ function useActiveCategoryScrollDetection(_ref) {
30472
30585
  return function () {
30473
30586
  observer.disconnect();
30474
30587
  };
30475
- }, [BodyRef, setActiveCategory, setVisibleCategories]);
30588
+ }, [BodyRef, categoryIdentitiesKey, setActiveCategory, setVisibleCategories]);
30476
30589
  }
30477
30590
 
30478
30591
  function useScrollCategoryIntoView() {
@@ -30483,7 +30596,8 @@ function useScrollCategoryIntoView() {
30483
30596
  if (!BodyRef.current) {
30484
30597
  return;
30485
30598
  }
30486
- var $category = (_BodyRef$current = BodyRef.current) == null ? void 0 : _BodyRef$current.querySelector("[data-name=\"" + category + "\"]");
30599
+ // Group names are user-controlled; escape for the attribute selector.
30600
+ var $category = (_BodyRef$current = BodyRef.current) == null ? void 0 : _BodyRef$current.querySelector("[data-name=\"" + CSS.escape(category) + "\"]");
30487
30601
  if (!$category) {
30488
30602
  return;
30489
30603
  }
@@ -30857,17 +30971,40 @@ function CategoryNavigation() {
30857
30971
  var _useVisibleCategories = useVisibleCategoriesState(),
30858
30972
  setVisibleCategories = _useVisibleCategories[1];
30859
30973
  var scrollCategoryIntoView = useScrollCategoryIntoView();
30860
- useActiveCategoryScrollDetection({
30861
- setActiveCategory: setActiveCategory,
30862
- setVisibleCategories: setVisibleCategories
30863
- });
30864
30974
  var isSearchMode = useIsSearchMode();
30865
30975
  var categoriesConfig = useCategoriesConfig();
30866
30976
  var categoryIcons = useCategoryIconsConfig();
30867
30977
  var CategoryNavigationRef = useCategoryNavigationRef();
30868
30978
  var hideCustomCategory = useShouldHideCustomEmojis();
30979
+ var _usePickerDataContext = usePickerDataContext(),
30980
+ customGroups = _usePickerDataContext.customGroups,
30981
+ emojiData = _usePickerDataContext.emojiData;
30982
+ // Rendered section identities. Passed to the scroll-detection hook so
30983
+ // added/removed sections are (re-)subscribed; stable across renders
30984
+ // unless the effective category list changes.
30985
+ var categoryIdentitiesKey = categoriesConfig.map(function (entry) {
30986
+ return categoryIdFromCategoryConfig(entry);
30987
+ }).join('|');
30988
+ useActiveCategoryScrollDetection({
30989
+ setActiveCategory: setActiveCategory,
30990
+ setVisibleCategories: setVisibleCategories,
30991
+ categoryIdentitiesKey: categoryIdentitiesKey
30992
+ });
30869
30993
  var visibleCategories = categoriesConfig.filter(function (categoryConfig) {
30870
- return !(isCustomCategory(categoryConfig) && hideCustomCategory);
30994
+ if (isCustomCategory(categoryConfig) && hideCustomCategory) {
30995
+ return false;
30996
+ }
30997
+ // Tabs navigating to an empty (hidden) section are dead weight.
30998
+ var group = customGroupFromCategoryConfig(categoryConfig);
30999
+ if (group) {
31000
+ var _customGroups$group$l, _customGroups$group;
31001
+ return ((_customGroups$group$l = (_customGroups$group = customGroups[group]) == null ? void 0 : _customGroups$group.length) != null ? _customGroups$group$l : 0) > 0;
31002
+ }
31003
+ if (isCustomCategory(categoryConfig)) {
31004
+ var _emojiData$emojis$Cat, _emojiData$emojis, _emojiData$emojis$Cat2;
31005
+ return ((_emojiData$emojis$Cat = (_emojiData$emojis = emojiData.emojis) == null ? void 0 : (_emojiData$emojis$Cat2 = _emojiData$emojis[Categories.CUSTOM]) == null ? void 0 : _emojiData$emojis$Cat2.length) != null ? _emojiData$emojis$Cat : 0) > 0;
31006
+ }
31007
+ return true;
30871
31008
  });
30872
31009
  // A single tab navigates nowhere — hide the bar to reclaim its space.
30873
31010
  // https://github.com/ealush/emoji-picker-react/issues/396
@@ -30882,19 +31019,20 @@ function CategoryNavigation() {
30882
31019
  ref: CategoryNavigationRef
30883
31020
  }, visibleCategories.map(function (categoryConfig) {
30884
31021
  var category = categoryFromCategoryConfig(categoryConfig);
30885
- var isActiveCategory = category === activeCategory;
31022
+ var categoryId = categoryIdFromCategoryConfig(categoryConfig);
31023
+ var isActiveCategory = categoryId === activeCategory;
30886
31024
  var allowNavigation = !isSearchMode && !isActiveCategory;
30887
31025
  return createElement(CategoryButton, {
30888
- key: category,
31026
+ key: categoryId,
30889
31027
  category: category,
30890
31028
  isActiveCategory: isActiveCategory,
30891
31029
  allowNavigation: allowNavigation,
30892
31030
  categoryConfig: categoryConfig,
30893
31031
  customIcon: categoryIcons[category],
30894
31032
  onClick: function onClick() {
30895
- scrollCategoryIntoView(category);
31033
+ scrollCategoryIntoView(categoryId);
30896
31034
  setTimeout(function () {
30897
- setActiveCategory(category);
31035
+ setActiveCategory(categoryId);
30898
31036
  }, 10);
30899
31037
  }
30900
31038
  });