emoji-picker-react 4.17.4 → 4.18.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 (102) hide show
  1. package/README.md +51 -6
  2. package/dist/components/Layout/Flex.d.ts +1 -1
  3. package/dist/components/body/EmojiCategory.d.ts +1 -1
  4. package/dist/components/context/ElementRefContext.d.ts +1 -1
  5. package/dist/components/emoji/ClickableEmojiButton.d.ts +1 -1
  6. package/dist/components/emoji/Emoji.d.ts +1 -1
  7. package/dist/components/emoji/EmojiImg.d.ts +1 -1
  8. package/dist/components/emoji/ExportedEmoji.d.ts +1 -1
  9. package/dist/components/emoji/NativeEmoji.d.ts +1 -1
  10. package/dist/components/emoji/ViewOnlyEmoji.d.ts +1 -1
  11. package/dist/components/header/SkinTonePicker/BtnSkinToneVariation.d.ts +1 -1
  12. package/dist/components/header/SkinTonePicker/SkinTonePicker.d.ts +1 -1
  13. package/dist/components/navigation/CategoryButton.d.ts +3 -2
  14. package/dist/config/config.d.ts +2 -1
  15. package/dist/config/useConfig.d.ts +1 -0
  16. package/dist/data/groups.js +1 -1
  17. package/dist/data/groups.ts +1 -1
  18. package/dist/data/skinToneVariations.js +2 -2
  19. package/dist/data/skinToneVariations.ts +10 -12
  20. package/dist/emoji-picker-react.cjs.development.js +110 -93
  21. package/dist/emoji-picker-react.cjs.development.js.map +1 -1
  22. package/dist/emoji-picker-react.cjs.production.min.js +1 -1
  23. package/dist/emoji-picker-react.cjs.production.min.js.map +1 -1
  24. package/dist/emoji-picker-react.esm.js +110 -93
  25. package/dist/emoji-picker-react.esm.js.map +1 -1
  26. package/dist/hooks/useActiveCategoryScrollDetection.d.ts +1 -1
  27. package/dist/hooks/useEmojiVirtualization.d.ts +1 -1
  28. package/dist/hooks/useFilter.d.ts +4 -0
  29. package/dist/index.d.ts +2 -1
  30. package/dist/typeRefinements/typeRefinements.d.ts +1 -1
  31. package/dist/types/exposedTypes.d.ts +3 -0
  32. package/dist/virtualization/virtualizationHelpers.d.ts +1 -1
  33. package/package.json +18 -10
  34. package/src/DomUtils/classNames.ts +2 -2
  35. package/src/DomUtils/detectEmojyPartiallyBelowFold.ts +1 -1
  36. package/src/DomUtils/elementPositionInRow.ts +3 -3
  37. package/src/DomUtils/focusElement.ts +0 -1
  38. package/src/DomUtils/keyboardNavigation.ts +2 -2
  39. package/src/DomUtils/scrollTo.ts +2 -2
  40. package/src/DomUtils/selectors.ts +18 -17
  41. package/src/Stylesheet/stylesheet.tsx +22 -22
  42. package/src/components/Layout/Flex.tsx +6 -6
  43. package/src/components/Layout/Space.tsx +0 -1
  44. package/src/components/Reactions/BtnPlus.tsx +8 -8
  45. package/src/components/Reactions/DEFAULT_REACTIONS.ts +1 -1
  46. package/src/components/Reactions/Reactions.tsx +1 -0
  47. package/src/components/atoms/Button.tsx +6 -7
  48. package/src/components/body/Body.tsx +3 -3
  49. package/src/components/body/EmojiCategory.tsx +8 -8
  50. package/src/components/body/EmojiList.tsx +9 -9
  51. package/src/components/body/EmojiVariationPicker.tsx +22 -23
  52. package/src/components/body/MeasureEmoji.tsx +10 -11
  53. package/src/components/context/ElementRefContext.tsx +5 -6
  54. package/src/components/context/PickerConfigContext.tsx +5 -6
  55. package/src/components/context/PickerContext.tsx +8 -8
  56. package/src/components/context/PickerDataContext.tsx +2 -2
  57. package/src/components/emoji/ClickableEmojiButton.tsx +15 -14
  58. package/src/components/emoji/Emoji.tsx +1 -1
  59. package/src/components/emoji/EmojiImg.tsx +10 -5
  60. package/src/components/emoji/ExportedEmoji.tsx +1 -1
  61. package/src/components/emoji/NativeEmoji.tsx +4 -4
  62. package/src/components/emoji/ViewOnlyEmoji.tsx +2 -3
  63. package/src/components/emoji/emojiStyles.ts +3 -3
  64. package/src/components/footer/Preview.tsx +10 -10
  65. package/src/components/header/Search/BtnClearSearch.tsx +13 -13
  66. package/src/components/header/Search/IcnSearch.tsx +3 -3
  67. package/src/components/header/Search/Search.tsx +18 -18
  68. package/src/components/header/SkinTonePicker/BtnSkinToneVariation.tsx +15 -14
  69. package/src/components/header/SkinTonePicker/SkinTonePicker.tsx +15 -15
  70. package/src/components/main/PickerMain.tsx +16 -16
  71. package/src/components/navigation/CategoryButton.tsx +41 -26
  72. package/src/components/navigation/CategoryNavigation.tsx +14 -8
  73. package/src/config/config.ts +3 -0
  74. package/src/config/mutableConfig.ts +2 -2
  75. package/src/config/useConfig.ts +15 -10
  76. package/src/data/groups.ts +1 -1
  77. package/src/data/skinToneVariations.ts +10 -12
  78. package/src/dataUtils/DataTypes.ts +1 -1
  79. package/src/dataUtils/alphaNumericEmojiIndex.ts +1 -1
  80. package/src/dataUtils/parseNativeEmoji.ts +1 -1
  81. package/src/dataUtils/suggested.ts +3 -3
  82. package/src/hooks/preloadEmoji.ts +3 -3
  83. package/src/hooks/useActiveCategoryScrollDetection.ts +9 -7
  84. package/src/hooks/useCloseAllOpenToggles.ts +2 -2
  85. package/src/hooks/useDebouncedState.ts +2 -2
  86. package/src/hooks/useDisallowMouseMove.ts +1 -1
  87. package/src/hooks/useDisallowedEmojis.ts +2 -2
  88. package/src/hooks/useEmojiPreviewEvents.ts +8 -8
  89. package/src/hooks/useEmojiVirtualization.tsx +9 -9
  90. package/src/hooks/useFilter.ts +19 -19
  91. package/src/hooks/useFocus.ts +1 -1
  92. package/src/hooks/useHideEmojisByUniocode.ts +4 -4
  93. package/src/hooks/useInitialLoad.ts +1 -1
  94. package/src/hooks/useIsEmojiHidden.ts +1 -1
  95. package/src/hooks/useKeyboardNavigation.ts +18 -18
  96. package/src/hooks/useMouseDownHandlers.ts +18 -18
  97. package/src/hooks/useOnScroll.ts +1 -1
  98. package/src/hooks/useScrollCategoryIntoView.ts +2 -2
  99. package/src/index.tsx +5 -2
  100. package/src/typeRefinements/typeRefinements.ts +2 -2
  101. package/src/types/exposedTypes.ts +11 -6
  102. package/src/virtualization/virtualizationHelpers.ts +2 -2
@@ -4,7 +4,7 @@ import * as React from 'react';
4
4
  import {
5
5
  commonInteractionStyles,
6
6
  darkMode,
7
- stylesheet
7
+ stylesheet,
8
8
  } from '../../../Stylesheet/stylesheet';
9
9
  import { useSearchClearButtonLabelConfig } from '../../../config/useConfig';
10
10
  import { useClearSearch } from '../../../hooks/useFilter';
@@ -20,7 +20,7 @@ export function BtnClearSearch() {
20
20
  <Button
21
21
  className={cx(
22
22
  styles.btnClearSearch,
23
- commonInteractionStyles.visibleOnSearchOnly
23
+ commonInteractionStyles.visibleOnSearchOnly,
24
24
  )}
25
25
  onClick={clearSearch}
26
26
  aria-label={searchClearButtonLabel}
@@ -34,9 +34,9 @@ export function BtnClearSearch() {
34
34
  const HoverDark = {
35
35
  ':hover': {
36
36
  '> .epr-icn-clear-search': {
37
- backgroundPositionY: '-60px'
38
- }
39
- }
37
+ backgroundPositionY: '-60px',
38
+ },
39
+ },
40
40
  };
41
41
 
42
42
  const styles = stylesheet.create({
@@ -54,11 +54,11 @@ const styles = stylesheet.create({
54
54
  padding: '0',
55
55
  borderRadius: '50%',
56
56
  ':hover': {
57
- background: 'var(--epr-hover-bg-color)'
57
+ background: 'var(--epr-hover-bg-color)',
58
58
  },
59
59
  ':focus': {
60
- background: 'var(--epr-hover-bg-color)'
61
- }
60
+ background: 'var(--epr-hover-bg-color)',
61
+ },
62
62
  },
63
63
  icnClearnSearch: {
64
64
  '.': 'epr-icn-clear-search',
@@ -69,14 +69,14 @@ const styles = stylesheet.create({
69
69
  width: '20px',
70
70
  backgroundImage: `url(${SVGTimes})`,
71
71
  ':hover': {
72
- backgroundPositionY: '-20px'
72
+ backgroundPositionY: '-20px',
73
73
  },
74
74
  ':focus': {
75
- backgroundPositionY: '-20px'
76
- }
75
+ backgroundPositionY: '-20px',
76
+ },
77
77
  },
78
78
  ...darkMode('icnClearnSearch', {
79
- backgroundPositionY: '-40px'
79
+ backgroundPositionY: '-40px',
80
80
  }),
81
- ...darkMode('btnClearSearch', HoverDark)
81
+ ...darkMode('btnClearSearch', HoverDark),
82
82
  });
@@ -22,9 +22,9 @@ const styles = stylesheet.create({
22
22
  backgroundRepeat: 'no-repeat',
23
23
  backgroundPosition: '0 0',
24
24
  backgroundSize: '20px',
25
- backgroundImage: `url(${SVGMagnifier})`
25
+ backgroundImage: `url(${SVGMagnifier})`,
26
26
  },
27
27
  ...darkMode('icnSearch', {
28
- backgroundPositionY: '-20px'
29
- })
28
+ backgroundPositionY: '-20px',
29
+ }),
30
30
  });
@@ -5,7 +5,7 @@ import { darkMode, stylesheet } from '../../../Stylesheet/stylesheet';
5
5
  import {
6
6
  useAutoFocusSearchConfig,
7
7
  useSearchDisabledConfig,
8
- useSearchPlaceHolderConfig
8
+ useSearchPlaceHolderConfig,
9
9
  } from '../../../config/useConfig';
10
10
  import { useCloseAllOpenToggles } from '../../../hooks/useCloseAllOpenToggles';
11
11
  import { useFilter } from '../../../hooks/useFilter';
@@ -58,7 +58,7 @@ export function Search() {
58
58
  type="text"
59
59
  aria-controls="epr-search-id"
60
60
  placeholder={placeholder}
61
- onChange={event => {
61
+ onChange={(event) => {
62
62
  onChange(event?.target?.value ?? value);
63
63
  }}
64
64
  ref={SearchInputRef}
@@ -83,13 +83,13 @@ export function Search() {
83
83
  const styles = stylesheet.create({
84
84
  overlay: {
85
85
  padding: 'var(--epr-header-padding)',
86
- zIndex: 'var(--epr-header-overlay-z-index)'
86
+ zIndex: 'var(--epr-header-overlay-z-index)',
87
87
  },
88
88
  searchContainer: {
89
89
  '.': 'epr-search-container',
90
90
  flex: '1',
91
91
  display: 'block',
92
- minWidth: '0'
92
+ minWidth: '0',
93
93
  },
94
94
  visuallyHidden: {
95
95
  clip: 'rect(0 0 0 0)',
@@ -98,7 +98,7 @@ const styles = stylesheet.create({
98
98
  overflow: 'hidden',
99
99
  position: 'absolute',
100
100
  whiteSpace: 'nowrap',
101
- width: '1px'
101
+ width: '1px',
102
102
  },
103
103
  search: {
104
104
  outline: 'none',
@@ -112,11 +112,11 @@ const styles = stylesheet.create({
112
112
  width: '100%',
113
113
  ':focus': {
114
114
  backgroundColor: 'var(--epr-search-input-bg-color-active)',
115
- border: '1px solid var(--epr-search-border-color-active)'
115
+ border: '1px solid var(--epr-search-border-color-active)',
116
116
  },
117
117
  '::placeholder': {
118
- color: 'var(--epr-search-input-placeholder-color)'
119
- }
118
+ color: 'var(--epr-search-input-placeholder-color)',
119
+ },
120
120
  },
121
121
 
122
122
  btnClearSearch: {
@@ -133,11 +133,11 @@ const styles = stylesheet.create({
133
133
  padding: '0',
134
134
  borderRadius: '50%',
135
135
  ':hover': {
136
- background: 'var(--epr-hover-bg-color)'
136
+ background: 'var(--epr-hover-bg-color)',
137
137
  },
138
138
  ':focus': {
139
- background: 'var(--epr-hover-bg-color)'
140
- }
139
+ background: 'var(--epr-hover-bg-color)',
140
+ },
141
141
  },
142
142
  icnClearnSearch: {
143
143
  '.': 'epr-icn-clear-search',
@@ -148,18 +148,18 @@ const styles = stylesheet.create({
148
148
  width: '20px',
149
149
  backgroundImage: `url(${SVGTimes})`,
150
150
  ':hover': {
151
- backgroundPositionY: '-20px'
151
+ backgroundPositionY: '-20px',
152
152
  },
153
153
  ':focus': {
154
- backgroundPositionY: '-20px'
155
- }
154
+ backgroundPositionY: '-20px',
155
+ },
156
156
  },
157
157
  ...darkMode('icnClearnSearch', {
158
- backgroundPositionY: '-40px'
158
+ backgroundPositionY: '-40px',
159
159
  }),
160
160
  ...darkMode('btnClearSearch', {
161
161
  ':hover > .epr-icn-clear-search': {
162
- backgroundPositionY: '-60px'
163
- }
164
- })
162
+ backgroundPositionY: '-60px',
163
+ },
164
+ }),
165
165
  });
@@ -20,7 +20,7 @@ export function BtnSkinToneVariation({
20
20
  onClick,
21
21
  isActive,
22
22
  skinToneVariation,
23
- style
23
+ style,
24
24
  }: Props) {
25
25
  return (
26
26
  <Button
@@ -30,7 +30,7 @@ export function BtnSkinToneVariation({
30
30
  `epr-tone-${skinToneVariation}`,
31
31
  styles.tone,
32
32
  !isOpen && styles.closedTone,
33
- isActive && styles.active
33
+ isActive && styles.active,
34
34
  )}
35
35
  aria-pressed={isActive}
36
36
  aria-label={`Skin tone ${skinTonesNamed[skinToneVariation as SkinTones]}`}
@@ -41,12 +41,12 @@ export function BtnSkinToneVariation({
41
41
  const styles = stylesheet.create({
42
42
  closedTone: {
43
43
  opacity: '0',
44
- zIndex: '0'
44
+ zIndex: '0',
45
45
  },
46
46
  active: {
47
47
  '.': 'epr-active',
48
48
  zIndex: '1',
49
- opacity: '1'
49
+ opacity: '1',
50
50
  },
51
51
  tone: {
52
52
  '.': 'epr-tone',
@@ -62,28 +62,29 @@ const styles = stylesheet.create({
62
62
  border: '1px solid var(--epr-skin-tone-outer-border-color)',
63
63
  boxShadow: 'inset 0px 0px 0 1px var(--epr-skin-tone-inner-border-color)',
64
64
  ':hover': {
65
- boxShadow: '0 0 0 3px var(--epr-active-skin-hover-color), inset 0px 0px 0 1px var(--epr-skin-tone-inner-border-color)'
65
+ boxShadow:
66
+ '0 0 0 3px var(--epr-active-skin-hover-color), inset 0px 0px 0 1px var(--epr-skin-tone-inner-border-color)',
66
67
  },
67
68
  ':focus': {
68
- boxShadow: '0 0 0 3px var(--epr-focus-bg-color)'
69
+ boxShadow: '0 0 0 3px var(--epr-focus-bg-color)',
69
70
  },
70
71
  '&.epr-tone-neutral': {
71
- backgroundColor: '#ffd225'
72
+ backgroundColor: '#ffd225',
72
73
  },
73
74
  '&.epr-tone-1f3fb': {
74
- backgroundColor: '#ffdfbd'
75
+ backgroundColor: '#ffdfbd',
75
76
  },
76
77
  '&.epr-tone-1f3fc': {
77
- backgroundColor: '#e9c197'
78
+ backgroundColor: '#e9c197',
78
79
  },
79
80
  '&.epr-tone-1f3fd': {
80
- backgroundColor: '#c88e62'
81
+ backgroundColor: '#c88e62',
81
82
  },
82
83
  '&.epr-tone-1f3fe': {
83
- backgroundColor: '#a86637'
84
+ backgroundColor: '#a86637',
84
85
  },
85
86
  '&.epr-tone-1f3ff': {
86
- backgroundColor: '#60463a'
87
- }
88
- }
87
+ backgroundColor: '#60463a',
88
+ },
89
+ },
89
90
  });
@@ -6,7 +6,7 @@ import { ClassNames } from '../../../DomUtils/classNames';
6
6
  import { stylesheet } from '../../../Stylesheet/stylesheet';
7
7
  import {
8
8
  useOnSkinToneChangeConfig,
9
- useSkinTonesDisabledConfig
9
+ useSkinTonesDisabledConfig,
10
10
  } from '../../../config/useConfig';
11
11
  import skinToneVariations from '../../../data/skinToneVariations';
12
12
  import { useCloseAllOpenToggles } from '../../../hooks/useCloseAllOpenToggles';
@@ -16,7 +16,7 @@ import Relative from '../../Layout/Relative';
16
16
  import { useSkinTonePickerRef } from '../../context/ElementRefContext';
17
17
  import {
18
18
  useActiveSkinToneState,
19
- useSkinToneFanOpenState
19
+ useSkinToneFanOpenState,
20
20
  } from '../../context/PickerContext';
21
21
 
22
22
  import { BtnSkinToneVariation } from './BtnSkinToneVariation';
@@ -38,7 +38,7 @@ export function SkinTonePickerMenu() {
38
38
  }
39
39
 
40
40
  export function SkinTonePicker({
41
- direction = SkinTonePickerDirection.HORIZONTAL
41
+ direction = SkinTonePickerDirection.HORIZONTAL,
42
42
  }: Props) {
43
43
  const SkinTonePickerRef = useSkinTonePickerRef();
44
44
  const isDisabled = useSkinTonesDisabledConfig();
@@ -64,7 +64,7 @@ export function SkinTonePicker({
64
64
  styles.skinTones,
65
65
  vertical && styles.vertical,
66
66
  isOpen && styles.open,
67
- vertical && isOpen && styles.verticalShadow
67
+ vertical && isOpen && styles.verticalShadow,
68
68
  )}
69
69
  style={
70
70
  vertical
@@ -86,8 +86,8 @@ export function SkinTonePicker({
86
86
  vertical
87
87
  ? `translateY(-${i * (isOpen ? ITEM_SIZE : 0)}px)`
88
88
  : `translateX(-${i * (isOpen ? ITEM_SIZE : 0)}px)`,
89
- isOpen && active && 'scale(1.3)'
90
- )
89
+ isOpen && active && 'scale(1.3)',
90
+ ),
91
91
  }}
92
92
  isActive={active}
93
93
  onClick={() => {
@@ -110,43 +110,43 @@ export function SkinTonePicker({
110
110
 
111
111
  export enum SkinTonePickerDirection {
112
112
  VERTICAL = ClassNames.vertical,
113
- HORIZONTAL = ClassNames.horizontal
113
+ HORIZONTAL = ClassNames.horizontal,
114
114
  }
115
115
 
116
116
  const styles = stylesheet.create({
117
117
  skinTones: {
118
118
  '.': 'epr-skin-tones',
119
119
  '--': {
120
- '--epr-skin-tone-size': '15px'
120
+ '--epr-skin-tone-size': '15px',
121
121
  },
122
122
  display: 'flex',
123
123
  alignItems: 'center',
124
124
  justifyContent: 'flex-end',
125
125
  transition: 'all 0.3s ease-in-out',
126
- padding: '10px 0'
126
+ padding: '10px 0',
127
127
  },
128
128
  vertical: {
129
129
  padding: '9px',
130
130
  alignItems: 'flex-end',
131
131
  flexDirection: 'column',
132
132
  borderRadius: '6px',
133
- border: '1px solid var(--epr-bg-color)'
133
+ border: '1px solid var(--epr-bg-color)',
134
134
  },
135
135
  verticalShadow: {
136
- boxShadow: '0px 0 7px var(--epr-picker-border-color)'
136
+ boxShadow: '0px 0 7px var(--epr-picker-border-color)',
137
137
  },
138
138
  open: {
139
139
  // @ts-ignore - backdropFilter is not recognized.
140
140
  backdropFilter: 'blur(5px)',
141
141
  background: 'var(--epr-skin-tone-picker-menu-color)',
142
142
  '.epr-active': {
143
- border: '1px solid var(--epr-active-skin-tone-indicator-border-color)'
144
- }
143
+ border: '1px solid var(--epr-active-skin-tone-indicator-border-color)',
144
+ },
145
145
  },
146
146
  select: {
147
147
  '.': 'epr-skin-tone-select',
148
148
  position: 'relative',
149
149
  width: 'var(--epr-skin-tone-size)',
150
- height: 'var(--epr-skin-tone-size)'
151
- }
150
+ height: 'var(--epr-skin-tone-size)',
151
+ },
152
152
  });
@@ -6,7 +6,7 @@ import { stylesheet } from '../../Stylesheet/stylesheet';
6
6
  import {
7
7
  useClassNameConfig,
8
8
  useStyleConfig,
9
- useThemeConfig
9
+ useThemeConfig,
10
10
  } from '../../config/useConfig';
11
11
  import useIsSearchMode from '../../hooks/useIsSearchMode';
12
12
  import { useKeyboardNavigation } from '../../hooks/useKeyboardNavigation';
@@ -15,7 +15,7 @@ import { Theme } from '../../types/exposedTypes';
15
15
  import { usePickerMainRef } from '../context/ElementRefContext';
16
16
  import {
17
17
  PickerContextProvider,
18
- useReactionsModeState
18
+ useReactionsModeState,
19
19
  } from '../context/PickerContext';
20
20
 
21
21
  type Props = Readonly<{
@@ -59,15 +59,15 @@ function PickerRootElement({ children }: RootProps) {
59
59
  theme === Theme.DARK && styles.darkTheme,
60
60
  theme === Theme.AUTO && styles.autoThemeDark,
61
61
  {
62
- [ClassNames.searchActive]: searchModeActive
62
+ [ClassNames.searchActive]: searchModeActive,
63
63
  },
64
64
  reactionsMode && styles.reactionsMenu,
65
- className
65
+ className,
66
66
  )}
67
67
  ref={PickerMainRef}
68
68
  style={{
69
69
  ...styleProps,
70
- ...(!reactionsMode && { height, width })
70
+ ...(!reactionsMode && { height, width }),
71
71
  }}
72
72
  >
73
73
  {children}
@@ -100,7 +100,7 @@ const DarkTheme = {
100
100
  '--epr-skin-tone-outer-border-color':
101
101
  'var(--epr-dark-skin-tone-outer-border-color)',
102
102
  '--epr-skin-tone-inner-border-color':
103
- 'var(--epr-dark-skin-tone-inner-border-color)'
103
+ 'var(--epr-dark-skin-tone-inner-border-color)',
104
104
  };
105
105
 
106
106
  const styles = stylesheet.create({
@@ -118,8 +118,8 @@ const styles = stylesheet.create({
118
118
  transition: 'height 0.3s ease-in-out, background-color 0.1s ease-in-out',
119
119
  '*': {
120
120
  boxSizing: 'border-box',
121
- fontFamily: 'sans-serif'
122
- }
121
+ fontFamily: 'sans-serif',
122
+ },
123
123
  },
124
124
  baseVariables: {
125
125
  '--': {
@@ -218,18 +218,18 @@ const styles = stylesheet.create({
218
218
  '--epr-dark-skin-tone-picker-menu-color': '#22222295',
219
219
  '--epr-dark-skin-tone-outer-border-color':
220
220
  'var(--epr-dark-picker-border-color)',
221
- '--epr-dark-skin-tone-inner-border-color': '#00000000'
222
- }
221
+ '--epr-dark-skin-tone-inner-border-color': '#00000000',
222
+ },
223
223
  },
224
224
  autoThemeDark: {
225
225
  '.': ClassNames.autoTheme,
226
226
  '@media (prefers-color-scheme: dark)': {
227
- '--': DarkTheme
228
- }
227
+ '--': DarkTheme,
228
+ },
229
229
  },
230
230
  darkTheme: {
231
231
  '.': ClassNames.darkTheme,
232
- '--': DarkTheme
232
+ '--': DarkTheme,
233
233
  },
234
234
  reactionsMenu: {
235
235
  '.': 'epr-reactions',
@@ -239,7 +239,7 @@ const styles = stylesheet.create({
239
239
  // @ts-ignore - backdropFilter is not recognized.
240
240
  backdropFilter: 'blur(8px)',
241
241
  '--': {
242
- '--epr-picker-border-radius': '50px'
243
- }
244
- }
242
+ '--epr-picker-border-radius': '50px',
243
+ },
244
+ },
245
245
  });
@@ -5,7 +5,7 @@ import { ClassNames } from '../../DomUtils/classNames';
5
5
  import {
6
6
  commonInteractionStyles,
7
7
  darkMode,
8
- stylesheet
8
+ stylesheet,
9
9
  } from '../../Stylesheet/stylesheet';
10
10
  import { categoryNameFromCategoryConfig } from '../../config/categoryConfig';
11
11
  import { CategoryConfig } from '../../types/exposedTypes';
@@ -19,6 +19,7 @@ type Props = {
19
19
  allowNavigation: boolean;
20
20
  onClick: () => void;
21
21
  categoryConfig: CategoryConfig;
22
+ customIcon?: React.ReactNode;
22
23
  };
23
24
 
24
25
  export function CategoryButton({
@@ -26,42 +27,49 @@ export function CategoryButton({
26
27
  category,
27
28
  allowNavigation,
28
29
  categoryConfig,
29
- onClick
30
+ onClick,
31
+ customIcon,
30
32
  }: Props) {
33
+ // Priority: categoryConfig.icon > customIcon prop (from categoryIcons)
34
+ const icon = categoryConfig.icon ?? customIcon;
35
+ const hasCustomIcon = icon != null;
36
+
31
37
  return (
32
38
  <Button
33
39
  tabIndex={allowNavigation ? 0 : -1}
34
40
  className={cx(
35
41
  styles.catBtn,
36
42
  commonInteractionStyles.categoryBtn,
37
- `epr-icn-${category}`,
43
+ hasCustomIcon ? styles.customIcon : `epr-icn-${category}`,
38
44
  {
39
- [ClassNames.active]: isActiveCategory
40
- }
45
+ [ClassNames.active]: isActiveCategory,
46
+ },
41
47
  )}
42
48
  onClick={onClick}
43
49
  aria-label={categoryNameFromCategoryConfig(categoryConfig)}
44
50
  aria-selected={isActiveCategory}
45
51
  role="tab"
46
52
  aria-controls="epr-category-nav-id"
47
- />
53
+ >
54
+ {hasCustomIcon ? icon : null}
55
+ </Button>
48
56
  );
49
57
  }
50
58
 
51
59
  const DarkActivePositionY = {
52
- backgroundPositionY: 'calc(var(--epr-category-navigation-button-size) * 3)'
60
+ backgroundPositionY: 'calc(var(--epr-category-navigation-button-size) * 3)',
53
61
  };
54
62
  const DarkPositionY = {
55
- backgroundPositionY: 'calc(var(--epr-category-navigation-button-size) * 2)'
63
+ backgroundPositionY: 'calc(var(--epr-category-navigation-button-size) * 2)',
56
64
  };
57
65
 
58
66
  const DarkInactivePosition = {
59
67
  ':not(.epr-search-active)': {
60
68
  catBtn: {
61
69
  ':hover': DarkActivePositionY,
62
- '&.epr-active': DarkActivePositionY
63
- }
64
- }
70
+ '&.epr-active': DarkActivePositionY,
71
+ },
72
+ },
65
73
  };
66
74
 
67
75
  const styles = stylesheet.create({
@@ -84,53 +92,60 @@ const styles = stylesheet.create({
84
92
  right: '-2px',
85
93
  bottom: '-2px',
86
94
  border: '2px solid var(--epr-category-icon-active-color)',
87
- borderRadius: '50%'
95
+ borderRadius: '50%',
88
96
  },
89
97
  '&.epr-icn-suggested': {
90
98
  backgroundPositionX:
91
- 'calc(var(--epr-category-navigation-button-size) * -8)'
99
+ 'calc(var(--epr-category-navigation-button-size) * -8)',
92
100
  },
93
101
  '&.epr-icn-custom': {
94
102
  backgroundPositionX:
95
- 'calc(var(--epr-category-navigation-button-size) * -9)'
103
+ 'calc(var(--epr-category-navigation-button-size) * -9)',
96
104
  },
97
105
  '&.epr-icn-activities': {
98
106
  backgroundPositionX:
99
- 'calc(var(--epr-category-navigation-button-size) * -4)'
107
+ 'calc(var(--epr-category-navigation-button-size) * -4)',
100
108
  },
101
109
  '&.epr-icn-animals_nature': {
102
110
  backgroundPositionX:
103
- 'calc(var(--epr-category-navigation-button-size) * -1)'
111
+ 'calc(var(--epr-category-navigation-button-size) * -1)',
104
112
  },
105
113
  '&.epr-icn-flags': {
106
114
  backgroundPositionX:
107
- 'calc(var(--epr-category-navigation-button-size) * -7)'
115
+ 'calc(var(--epr-category-navigation-button-size) * -7)',
108
116
  },
109
117
  '&.epr-icn-food_drink': {
110
118
  backgroundPositionX:
111
- 'calc(var(--epr-category-navigation-button-size) * -2)'
119
+ 'calc(var(--epr-category-navigation-button-size) * -2)',
112
120
  },
113
121
  '&.epr-icn-objects': {
114
122
  backgroundPositionX:
115
- 'calc(var(--epr-category-navigation-button-size) * -5)'
123
+ 'calc(var(--epr-category-navigation-button-size) * -5)',
116
124
  },
117
125
  '&.epr-icn-smileys_people': {
118
- backgroundPositionX: '0px'
126
+ backgroundPositionX: '0px',
119
127
  },
120
128
  '&.epr-icn-symbols': {
121
129
  backgroundPositionX:
122
- 'calc(var(--epr-category-navigation-button-size) * -6)'
130
+ 'calc(var(--epr-category-navigation-button-size) * -6)',
123
131
  },
124
132
  '&.epr-icn-travel_places': {
125
133
  backgroundPositionX:
126
- 'calc(var(--epr-category-navigation-button-size) * -3)'
127
- }
134
+ 'calc(var(--epr-category-navigation-button-size) * -3)',
135
+ },
136
+ },
137
+ customIcon: {
138
+ '.': 'epr-cat-btn-custom-icon',
139
+ backgroundImage: 'none',
140
+ display: 'flex',
141
+ alignItems: 'center',
142
+ justifyContent: 'center',
128
143
  },
129
144
  ...darkMode('catBtn', DarkPositionY),
130
145
  '.epr-dark-theme': {
131
- ...DarkInactivePosition
146
+ ...DarkInactivePosition,
132
147
  },
133
148
  '.epr-auto-theme': {
134
- ...DarkInactivePosition
135
- }
149
+ ...DarkInactivePosition,
150
+ },
136
151
  });
@@ -4,12 +4,16 @@ import { useState } from 'react';
4
4
 
5
5
  import { stylesheet } from '../../Stylesheet/stylesheet';
6
6
  import { categoryFromCategoryConfig } from '../../config/categoryConfig';
7
- import { useCategoriesConfig } from '../../config/useConfig';
7
+ import {
8
+ useCategoriesConfig,
9
+ useCategoryIconsConfig,
10
+ } from '../../config/useConfig';
8
11
  import { useActiveCategoryScrollDetection } from '../../hooks/useActiveCategoryScrollDetection';
9
12
  import useIsSearchMode from '../../hooks/useIsSearchMode';
10
13
  import { useScrollCategoryIntoView } from '../../hooks/useScrollCategoryIntoView';
11
14
  import { useShouldHideCustomEmojis } from '../../hooks/useShouldHideCustomEmojis';
12
15
  import { isCustomCategory } from '../../typeRefinements/typeRefinements';
16
+ import { Categories } from '../../types/exposedTypes';
13
17
  import { useCategoryNavigationRef } from '../context/ElementRefContext';
14
18
  import { useVisibleCategoriesState } from '../context/PickerContext';
15
19
 
@@ -23,6 +27,7 @@ export function CategoryNavigation() {
23
27
  const isSearchMode = useIsSearchMode();
24
28
 
25
29
  const categoriesConfig = useCategoriesConfig();
30
+ const categoryIcons = useCategoryIconsConfig();
26
31
  const CategoryNavigationRef = useCategoryNavigationRef();
27
32
  const hideCustomCategory = useShouldHideCustomEmojis();
28
33
 
@@ -34,7 +39,7 @@ export function CategoryNavigation() {
34
39
  id="epr-category-nav-id"
35
40
  ref={CategoryNavigationRef}
36
41
  >
37
- {categoriesConfig.map(categoryConfig => {
42
+ {categoriesConfig.map((categoryConfig) => {
38
43
  const category = categoryFromCategoryConfig(categoryConfig);
39
44
  const isActiveCategory = category === activeCategory;
40
45
 
@@ -51,6 +56,7 @@ export function CategoryNavigation() {
51
56
  isActiveCategory={isActiveCategory}
52
57
  allowNavigation={allowNavigation}
53
58
  categoryConfig={categoryConfig}
59
+ customIcon={categoryIcons[category as Categories]}
54
60
  onClick={() => {
55
61
  scrollCategoryIntoView(category);
56
62
  setTimeout(() => {
@@ -70,20 +76,20 @@ const styles = stylesheet.create({
70
76
  display: 'flex',
71
77
  flexDirection: 'row',
72
78
  justifyContent: 'space-around',
73
- padding: 'var(--epr-header-padding)'
79
+ padding: 'var(--epr-header-padding)',
74
80
  },
75
81
  '.epr-search-active': {
76
82
  nav: {
77
83
  opacity: '0.3',
78
84
  cursor: 'default',
79
- pointerEvents: 'none'
80
- }
85
+ pointerEvents: 'none',
86
+ },
81
87
  },
82
88
  '.epr-main:has(input:not(:placeholder-shown))': {
83
89
  nav: {
84
90
  opacity: '0.3',
85
91
  cursor: 'default',
86
- pointerEvents: 'none'
87
- }
88
- }
92
+ pointerEvents: 'none',
93
+ },
94
+ },
89
95
  });
@@ -4,6 +4,7 @@ import { DEFAULT_REACTIONS } from '../components/Reactions/DEFAULT_REACTIONS';
4
4
  import { GetEmojiUrl } from '../components/emoji/BaseEmojiProps';
5
5
  import { emojiUrlByUnified } from '../dataUtils/emojiUtils';
6
6
  import {
7
+ CategoryIcons,
7
8
  EmojiClickData,
8
9
  EmojiData,
9
10
  EmojiStyle,
@@ -113,6 +114,7 @@ export function basePickerConfig(): PickerConfigInternal {
113
114
  allowExpandReactions: true,
114
115
  hiddenEmojis: [],
115
116
  emojiData: undefined,
117
+ categoryIcons: {},
116
118
  };
117
119
  }
118
120
 
@@ -145,6 +147,7 @@ export type PickerConfigInternal = {
145
147
  allowExpandReactions: boolean;
146
148
  hiddenEmojis: string[];
147
149
  emojiData?: EmojiData;
150
+ categoryIcons: CategoryIcons;
148
151
  };
149
152
 
150
153
  export type PreviewConfig = {