emoji-picker-react 4.22.3 → 5.0.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.
Files changed (409) hide show
  1. package/README.md +331 -49
  2. package/dist/DomUtils/categoryNameFromDom.d.ts +1 -1
  3. package/dist/DomUtils/classNames.d.ts +23 -23
  4. package/dist/DomUtils/detectEmojyPartiallyBelowFold.d.ts +2 -2
  5. package/dist/DomUtils/elementPositionInRow.d.ts +5 -5
  6. package/dist/DomUtils/eventBelongsToPicker.d.ts +2 -0
  7. package/dist/DomUtils/focusElement.d.ts +5 -5
  8. package/dist/DomUtils/getActiveElement.d.ts +2 -2
  9. package/dist/DomUtils/isJsdom.d.ts +1 -0
  10. package/dist/DomUtils/isRtl.d.ts +1 -0
  11. package/dist/DomUtils/keyboardNavigation.d.ts +15 -8
  12. package/dist/DomUtils/scrollTo.d.ts +4 -5
  13. package/dist/DomUtils/selectors.d.ts +31 -35
  14. package/dist/EmojiPickerReact.d.ts +5 -5
  15. package/dist/Stylesheet/DedupedStyle.d.ts +13 -0
  16. package/dist/Stylesheet/stylesheet.d.ts +40 -37
  17. package/dist/components/ErrorBoundary.d.ts +15 -15
  18. package/dist/components/Layout/Absolute.d.ts +8 -8
  19. package/dist/components/Layout/Flex.d.ts +13 -13
  20. package/dist/components/Layout/Relative.d.ts +8 -8
  21. package/dist/components/Layout/Space.d.ts +7 -7
  22. package/dist/components/Reactions/BtnPlus.d.ts +2 -2
  23. package/dist/components/Reactions/DEFAULT_REACTIONS.d.ts +1 -1
  24. package/dist/components/Reactions/Reactions.d.ts +3 -2
  25. package/dist/components/atoms/Button.d.ts +11 -6
  26. package/dist/components/body/EmojiCategory.d.ts +13 -12
  27. package/dist/components/body/EmojiList.d.ts +7 -4
  28. package/dist/components/body/EmojiVariationPicker.d.ts +2 -2
  29. package/dist/components/body/MeasureEmoji.d.ts +2 -2
  30. package/dist/components/body/listComponents.d.ts +47 -0
  31. package/dist/components/context/ElementRefContext.d.ts +18 -16
  32. package/dist/components/context/PickerConfigContext.d.ts +14 -9
  33. package/dist/components/context/PickerContext.d.ts +57 -25
  34. package/dist/components/context/PickerDataContext.d.ts +23 -17
  35. package/dist/components/emoji/BaseEmojiProps.d.ts +14 -13
  36. package/dist/components/emoji/ClickableEmojiButton.d.ts +23 -15
  37. package/dist/components/emoji/Emoji.d.ts +18 -15
  38. package/dist/components/emoji/EmojiImg.d.ts +11 -11
  39. package/dist/components/emoji/ExportedEmoji.d.ts +11 -11
  40. package/dist/components/emoji/NativeEmoji.d.ts +6 -6
  41. package/dist/components/emoji/ViewOnlyEmoji.d.ts +3 -3
  42. package/dist/components/emoji/emojiStyles.d.ts +6 -1
  43. package/dist/components/footer/Preview.d.ts +7 -7
  44. package/dist/components/header/Header.d.ts +2 -2
  45. package/dist/components/header/Search/BtnClearSearch.d.ts +2 -2
  46. package/dist/components/header/Search/IcnSearch.d.ts +2 -2
  47. package/dist/components/header/Search/Search.d.ts +11 -3
  48. package/dist/components/header/SkinTonePicker/BtnSkinToneVariation.d.ts +12 -12
  49. package/dist/components/header/SkinTonePicker/SkinTonePicker.d.ts +11 -11
  50. package/dist/components/icons/svgIcons.d.ts +4 -0
  51. package/dist/components/main/PickerMainBehaviors.d.ts +4 -0
  52. package/dist/components/main/defaultAppearance.d.ts +12 -0
  53. package/dist/components/main/labelHeight.d.ts +1 -0
  54. package/dist/components/navigation/CategoryButton.d.ts +12 -12
  55. package/dist/components/navigation/CategoryNavIcon.d.ts +4 -4
  56. package/dist/components/navigation/CategoryNavigation.d.ts +19 -2
  57. package/dist/config/categoryConfig.d.ts +34 -34
  58. package/dist/config/cdnUrls.d.ts +2 -2
  59. package/dist/config/compareConfig.d.ts +10 -2
  60. package/dist/config/config.d.ts +166 -64
  61. package/dist/config/customEmojiConfig.d.ts +14 -14
  62. package/dist/config/defaultPickerConfiguration.d.ts +10 -0
  63. package/dist/config/mutableConfig.d.ts +32 -10
  64. package/dist/config/useConfig.d.ts +48 -36
  65. package/dist/data/defaultEmojiData.d.ts +9 -0
  66. package/dist/data/defaultEmojiData.js +40 -0
  67. package/dist/data/emojis-bn.d.mts +39 -0
  68. package/dist/data/emojis-bn.d.ts +38 -2
  69. package/dist/data/emojis-bn.js +25 -2
  70. package/dist/data/emojis-bn.mjs +2 -0
  71. package/dist/data/emojis-da.d.mts +39 -0
  72. package/dist/data/emojis-da.d.ts +38 -2
  73. package/dist/data/emojis-da.js +25 -2
  74. package/dist/data/emojis-da.mjs +2 -0
  75. package/dist/data/emojis-de.d.mts +39 -0
  76. package/dist/data/emojis-de.d.ts +38 -2
  77. package/dist/data/emojis-de.js +25 -2
  78. package/dist/data/emojis-de.mjs +2 -0
  79. package/dist/data/emojis-en-gb.d.mts +39 -0
  80. package/dist/data/emojis-en-gb.d.ts +38 -2
  81. package/dist/data/emojis-en-gb.js +25 -2
  82. package/dist/data/emojis-en-gb.mjs +2 -0
  83. package/dist/data/emojis-en.d.mts +39 -0
  84. package/dist/data/emojis-en.d.ts +38 -2
  85. package/dist/data/emojis-en.js +25 -2
  86. package/dist/data/emojis-en.mjs +2 -0
  87. package/dist/data/emojis-es-mx.d.mts +39 -0
  88. package/dist/data/emojis-es-mx.d.ts +38 -2
  89. package/dist/data/emojis-es-mx.js +25 -2
  90. package/dist/data/emojis-es-mx.mjs +2 -0
  91. package/dist/data/emojis-es.d.mts +39 -0
  92. package/dist/data/emojis-es.d.ts +38 -2
  93. package/dist/data/emojis-es.js +25 -2
  94. package/dist/data/emojis-es.mjs +2 -0
  95. package/dist/data/emojis-et.d.mts +39 -0
  96. package/dist/data/emojis-et.d.ts +38 -2
  97. package/dist/data/emojis-et.js +25 -2
  98. package/dist/data/emojis-et.mjs +2 -0
  99. package/dist/data/emojis-fi.d.mts +39 -0
  100. package/dist/data/emojis-fi.d.ts +38 -2
  101. package/dist/data/emojis-fi.js +25 -2
  102. package/dist/data/emojis-fi.mjs +2 -0
  103. package/dist/data/emojis-fr.d.mts +39 -0
  104. package/dist/data/emojis-fr.d.ts +38 -2
  105. package/dist/data/emojis-fr.js +25 -2
  106. package/dist/data/emojis-fr.mjs +2 -0
  107. package/dist/data/emojis-hi.d.mts +39 -0
  108. package/dist/data/emojis-hi.d.ts +38 -2
  109. package/dist/data/emojis-hi.js +25 -2
  110. package/dist/data/emojis-hi.mjs +2 -0
  111. package/dist/data/emojis-hu.d.mts +39 -0
  112. package/dist/data/emojis-hu.d.ts +38 -2
  113. package/dist/data/emojis-hu.js +25 -2
  114. package/dist/data/emojis-hu.mjs +2 -0
  115. package/dist/data/emojis-it.d.mts +39 -0
  116. package/dist/data/emojis-it.d.ts +38 -2
  117. package/dist/data/emojis-it.js +25 -2
  118. package/dist/data/emojis-it.mjs +2 -0
  119. package/dist/data/emojis-ja.d.mts +39 -0
  120. package/dist/data/emojis-ja.d.ts +38 -2
  121. package/dist/data/emojis-ja.js +25 -2
  122. package/dist/data/emojis-ja.mjs +2 -0
  123. package/dist/data/emojis-ko.d.mts +39 -0
  124. package/dist/data/emojis-ko.d.ts +38 -2
  125. package/dist/data/emojis-ko.js +25 -2
  126. package/dist/data/emojis-ko.mjs +2 -0
  127. package/dist/data/emojis-lt.d.mts +39 -0
  128. package/dist/data/emojis-lt.d.ts +38 -2
  129. package/dist/data/emojis-lt.js +25 -2
  130. package/dist/data/emojis-lt.mjs +2 -0
  131. package/dist/data/emojis-ms.d.mts +39 -0
  132. package/dist/data/emojis-ms.d.ts +38 -2
  133. package/dist/data/emojis-ms.js +25 -2
  134. package/dist/data/emojis-ms.mjs +2 -0
  135. package/dist/data/emojis-nb.d.mts +39 -0
  136. package/dist/data/emojis-nb.d.ts +38 -2
  137. package/dist/data/emojis-nb.js +25 -2
  138. package/dist/data/emojis-nb.mjs +2 -0
  139. package/dist/data/emojis-nl.d.mts +39 -0
  140. package/dist/data/emojis-nl.d.ts +38 -2
  141. package/dist/data/emojis-nl.js +25 -2
  142. package/dist/data/emojis-nl.mjs +2 -0
  143. package/dist/data/emojis-pl.d.mts +39 -0
  144. package/dist/data/emojis-pl.d.ts +38 -2
  145. package/dist/data/emojis-pl.js +25 -2
  146. package/dist/data/emojis-pl.mjs +2 -0
  147. package/dist/data/emojis-pt.d.mts +39 -0
  148. package/dist/data/emojis-pt.d.ts +38 -2
  149. package/dist/data/emojis-pt.js +25 -2
  150. package/dist/data/emojis-pt.mjs +2 -0
  151. package/dist/data/emojis-ru.d.mts +39 -0
  152. package/dist/data/emojis-ru.d.ts +38 -2
  153. package/dist/data/emojis-ru.js +25 -2
  154. package/dist/data/emojis-ru.mjs +2 -0
  155. package/dist/data/emojis-sv.d.mts +39 -0
  156. package/dist/data/emojis-sv.d.ts +38 -2
  157. package/dist/data/emojis-sv.js +25 -2
  158. package/dist/data/emojis-sv.mjs +2 -0
  159. package/dist/data/emojis-th.d.mts +39 -0
  160. package/dist/data/emojis-th.d.ts +38 -2
  161. package/dist/data/emojis-th.js +25 -2
  162. package/dist/data/emojis-th.mjs +2 -0
  163. package/dist/data/emojis-uk.d.mts +39 -0
  164. package/dist/data/emojis-uk.d.ts +38 -2
  165. package/dist/data/emojis-uk.js +25 -2
  166. package/dist/data/emojis-uk.mjs +2 -0
  167. package/dist/data/emojis-vi.d.mts +39 -0
  168. package/dist/data/emojis-vi.d.ts +38 -2
  169. package/dist/data/emojis-vi.js +25 -2
  170. package/dist/data/emojis-vi.mjs +2 -0
  171. package/dist/data/emojis-zh-hant.d.mts +39 -0
  172. package/dist/data/emojis-zh-hant.d.ts +38 -2
  173. package/dist/data/emojis-zh-hant.js +25 -2
  174. package/dist/data/emojis-zh-hant.mjs +2 -0
  175. package/dist/data/emojis-zh.d.mts +39 -0
  176. package/dist/data/emojis-zh.d.ts +38 -2
  177. package/dist/data/emojis-zh.js +25 -2
  178. package/dist/data/emojis-zh.mjs +2 -0
  179. package/dist/data/index.js +1 -0
  180. package/dist/data/registerDefaultEmojiData.d.ts +1 -0
  181. package/dist/data/registerDefaultEmojiData.js +3 -0
  182. package/dist/data/skinToneVariations.js +2 -2
  183. package/dist/data/skinToneVariations.ts +8 -7
  184. package/dist/data-core/pickerData.d.ts +12 -0
  185. package/dist/data-core/prepare.d.ts +23 -0
  186. package/dist/data-core/search.d.ts +13 -0
  187. package/dist/data-core/types.d.ts +23 -0
  188. package/dist/data.d.mts +72 -0
  189. package/dist/data.d.ts +72 -0
  190. package/dist/dataUtils/DataTypes.d.ts +23 -19
  191. package/dist/dataUtils/emojiSelectors.d.ts +15 -16
  192. package/dist/dataUtils/emojiUtils.d.ts +1 -12
  193. package/dist/dataUtils/nativeEmojiSequenceSupport.d.ts +10 -0
  194. package/dist/dataUtils/nativeEmojiSupport.d.ts +40 -0
  195. package/dist/dataUtils/parseNativeEmoji.d.ts +1 -1
  196. package/dist/dataUtils/suggested.d.ts +11 -11
  197. package/dist/dataUtils/suggestedEmojis.d.ts +7 -0
  198. package/dist/esm/chunks/chunk-7ZGTUZFB.mjs +8025 -0
  199. package/dist/esm/chunks/chunk-ACXAQEKG.mjs +149 -0
  200. package/dist/esm/chunks/chunk-F2KS7DCA.mjs +6735 -0
  201. package/dist/esm/chunks/chunk-L5W4PFRJ.mjs +14 -0
  202. package/dist/esm/chunks/chunk-LO4TPPLH.mjs +33 -0
  203. package/dist/esm/chunks/emojis-6L3GRBAP.mjs +7 -0
  204. package/dist/esm/data.mjs +11 -0
  205. package/dist/esm/index.mjs +279 -0
  206. package/dist/esm/primitives/index.mjs +8 -0
  207. package/dist/hooks/preloadEmoji.d.ts +5 -9
  208. package/dist/hooks/useActiveCategoryScrollDetection.d.ts +11 -11
  209. package/dist/hooks/useCategoryHeight.d.ts +7 -5
  210. package/dist/hooks/useCloseAllOpenToggles.d.ts +2 -2
  211. package/dist/hooks/useDataIdentityStabilityWarning.d.ts +13 -0
  212. package/dist/hooks/useDebouncedState.d.ts +1 -1
  213. package/dist/hooks/useDisallowMouseMove.d.ts +4 -4
  214. package/dist/hooks/useDisallowedEmojis.d.ts +2 -3
  215. package/dist/hooks/useEmojiPreviewEvents.d.ts +3 -3
  216. package/dist/hooks/useEmojiVirtualization.d.ts +22 -17
  217. package/dist/hooks/useFilter.d.ts +10 -16
  218. package/dist/hooks/useFocus.d.ts +3 -3
  219. package/dist/hooks/useInitialLoad.d.ts +2 -2
  220. package/dist/hooks/useIsEmojiHidden.d.ts +8 -8
  221. package/dist/hooks/useIsMounted.d.ts +1 -1
  222. package/dist/hooks/useIsSearchMode.d.ts +1 -1
  223. package/dist/hooks/useIsomorphicLayoutEffect.d.ts +2 -2
  224. package/dist/hooks/useKeyboardNavigation.d.ts +3 -1
  225. package/dist/hooks/useMouseDownHandlers.d.ts +8 -4
  226. package/dist/hooks/useOnFocus.d.ts +1 -1
  227. package/dist/hooks/useOnScroll.d.ts +2 -2
  228. package/dist/hooks/useReactionsFocus.d.ts +1 -0
  229. package/dist/hooks/useRegisterRegion.d.ts +24 -0
  230. package/dist/hooks/useResolvedEmojiData.d.ts +37 -0
  231. package/dist/hooks/useScrollCategoryIntoView.d.ts +1 -1
  232. package/dist/hooks/useSearchController.d.ts +17 -0
  233. package/dist/hooks/useSearchResults.d.ts +8 -0
  234. package/dist/hooks/useSetVariationPicker.d.ts +2 -2
  235. package/dist/hooks/useShouldHideCustomEmojis.d.ts +1 -1
  236. package/dist/hooks/useShouldShowSkinTonePicker.d.ts +4 -4
  237. package/dist/index.d.mts +376 -0
  238. package/dist/index.d.ts +376 -9
  239. package/dist/index.js +2 -8
  240. package/dist/primitives/CategoryNav.d.ts +4 -0
  241. package/dist/primitives/Empty.d.ts +6 -0
  242. package/dist/primitives/List.d.ts +4 -0
  243. package/dist/primitives/LoadError.d.ts +8 -0
  244. package/dist/primitives/Loading.d.ts +4 -0
  245. package/dist/primitives/Panel.d.ts +3 -0
  246. package/dist/primitives/Preview.d.ts +3 -0
  247. package/dist/primitives/Reactions.d.ts +2 -0
  248. package/dist/primitives/Root.d.ts +26 -0
  249. package/dist/primitives/Search.d.ts +5 -0
  250. package/dist/primitives/SearchInput.d.ts +3 -0
  251. package/dist/primitives/SkinTone.d.ts +4 -0
  252. package/dist/primitives/Viewport.d.ts +19 -0
  253. package/dist/primitives/appearance.d.ts +3 -0
  254. package/dist/primitives/components.d.ts +27 -0
  255. package/dist/primitives/hooks.d.ts +48 -0
  256. package/dist/primitives/index.d.mts +561 -0
  257. package/dist/primitives/index.d.ts +561 -0
  258. package/dist/primitives/index.js +2 -0
  259. package/dist/primitives/nativeProps.d.ts +15 -0
  260. package/dist/primitives/scope.d.ts +13 -0
  261. package/dist/primitives/structuralStyles.d.ts +16 -0
  262. package/dist/primitives/tokens.d.ts +18 -0
  263. package/dist/primitives/types.d.ts +85 -0
  264. package/dist/state/activeEmojiStore.d.ts +7 -0
  265. package/dist/state/navigationRegistry.d.ts +61 -0
  266. package/dist/state/regionTraversal.d.ts +20 -0
  267. package/dist/typeRefinements/typeRefinements.d.ts +6 -6
  268. package/dist/types/exposedTypes.d.ts +16 -6
  269. package/dist/types/exposedTypes.js +5 -0
  270. package/dist/virtualization/virtualizationHelpers.d.ts +22 -18
  271. package/llms-full.txt +3683 -0
  272. package/llms.txt +66 -480
  273. package/package.json +180 -66
  274. package/src/DomUtils/categoryNameFromDom.ts +1 -1
  275. package/src/DomUtils/classNames.ts +1 -4
  276. package/src/DomUtils/elementPositionInRow.ts +28 -6
  277. package/src/DomUtils/eventBelongsToPicker.ts +17 -0
  278. package/src/DomUtils/getActiveElement.ts +7 -1
  279. package/src/DomUtils/isJsdom.ts +12 -0
  280. package/src/DomUtils/isRtl.ts +5 -0
  281. package/src/DomUtils/keyboardNavigation.ts +164 -144
  282. package/src/DomUtils/scrollTo.ts +20 -18
  283. package/src/DomUtils/selectors.ts +30 -127
  284. package/src/EmojiPickerReact.tsx +155 -48
  285. package/src/Stylesheet/DedupedStyle.tsx +80 -0
  286. package/src/Stylesheet/stylesheet.tsx +128 -59
  287. package/src/components/Layout/Flex.tsx +12 -11
  288. package/src/components/Reactions/BtnPlus.tsx +61 -51
  289. package/src/components/Reactions/Reactions.tsx +113 -55
  290. package/src/components/atoms/Button.tsx +18 -15
  291. package/src/components/body/EmojiCategory.tsx +77 -40
  292. package/src/components/body/EmojiList.tsx +107 -44
  293. package/src/components/body/EmojiVariationPicker.tsx +113 -66
  294. package/src/components/body/MeasureEmoji.tsx +9 -2
  295. package/src/components/body/listComponents.tsx +79 -0
  296. package/src/components/context/ElementRefContext.tsx +46 -35
  297. package/src/components/context/PickerConfigContext.tsx +55 -40
  298. package/src/components/context/PickerContext.tsx +567 -92
  299. package/src/components/context/PickerDataContext.tsx +114 -99
  300. package/src/components/emoji/BaseEmojiProps.ts +5 -4
  301. package/src/components/emoji/ClickableEmojiButton.tsx +148 -63
  302. package/src/components/emoji/Emoji.tsx +24 -2
  303. package/src/components/emoji/EmojiImg.tsx +13 -12
  304. package/src/components/emoji/ExportedEmoji.tsx +5 -4
  305. package/src/components/emoji/NativeEmoji.tsx +19 -16
  306. package/src/components/emoji/ViewOnlyEmoji.tsx +55 -30
  307. package/src/components/emoji/emojiStyles.ts +12 -11
  308. package/src/components/footer/Preview.tsx +86 -91
  309. package/src/components/header/Header.tsx +21 -6
  310. package/src/components/header/Search/BtnClearSearch.tsx +69 -55
  311. package/src/components/header/Search/IcnSearch.tsx +21 -21
  312. package/src/components/header/Search/Search.tsx +79 -137
  313. package/src/components/header/SkinTonePicker/BtnSkinToneVariation.tsx +99 -62
  314. package/src/components/header/SkinTonePicker/SkinTonePicker.tsx +84 -46
  315. package/src/components/icons/svgIcons.ts +17 -0
  316. package/src/components/main/PickerMainBehaviors.tsx +163 -0
  317. package/src/components/main/defaultAppearance.tsx +189 -0
  318. package/src/components/main/labelHeight.ts +5 -0
  319. package/src/components/navigation/CategoryButton.tsx +83 -57
  320. package/src/components/navigation/CategoryNavIcon.tsx +73 -194
  321. package/src/components/navigation/CategoryNavigation.tsx +118 -46
  322. package/src/config/categoryConfig.ts +7 -3
  323. package/src/config/cdnUrls.ts +11 -21
  324. package/src/config/compareConfig.ts +128 -30
  325. package/src/config/config.ts +228 -24
  326. package/src/config/defaultPickerConfiguration.ts +7 -0
  327. package/src/config/mutableConfig.ts +44 -20
  328. package/src/config/useConfig.ts +130 -37
  329. package/src/data/defaultEmojiData.ts +49 -0
  330. package/src/data/registerDefaultEmojiData.ts +8 -0
  331. package/src/data/skinToneVariations.ts +8 -7
  332. package/src/data-core/pickerData.ts +171 -0
  333. package/src/data-core/prepare.ts +163 -0
  334. package/src/data-core/search.ts +122 -0
  335. package/src/data-core/types.ts +36 -0
  336. package/src/data.ts +10 -0
  337. package/src/dataUtils/DataTypes.ts +4 -0
  338. package/src/dataUtils/emojiSelectors.ts +59 -63
  339. package/src/dataUtils/emojiUtils.ts +17 -74
  340. package/src/dataUtils/nativeEmojiSequenceSupport.ts +116 -0
  341. package/src/dataUtils/nativeEmojiSupport.ts +160 -0
  342. package/src/dataUtils/parseNativeEmoji.ts +3 -4
  343. package/src/dataUtils/suggested.ts +8 -4
  344. package/src/dataUtils/suggestedEmojis.ts +92 -0
  345. package/src/env.d.ts +4 -0
  346. package/src/hooks/preloadEmoji.ts +2 -47
  347. package/src/hooks/useActiveCategoryScrollDetection.ts +28 -16
  348. package/src/hooks/useCategoryHeight.ts +116 -10
  349. package/src/hooks/useDataIdentityStabilityWarning.ts +86 -0
  350. package/src/hooks/useDebouncedState.ts +13 -1
  351. package/src/hooks/useDisallowedEmojis.ts +31 -42
  352. package/src/hooks/useEmojiPreviewEvents.ts +43 -10
  353. package/src/hooks/useEmojiVirtualization.tsx +112 -52
  354. package/src/hooks/useFilter.ts +92 -132
  355. package/src/hooks/useFocus.ts +14 -24
  356. package/src/hooks/useIsEmojiHidden.ts +22 -14
  357. package/src/hooks/useKeyboardNavigation.ts +412 -432
  358. package/src/hooks/useMouseDownHandlers.ts +91 -16
  359. package/src/hooks/useOnFocus.ts +12 -3
  360. package/src/hooks/useOnScroll.ts +18 -2
  361. package/src/hooks/useReactionsFocus.ts +118 -0
  362. package/src/hooks/useRegisterRegion.ts +92 -0
  363. package/src/hooks/useResolvedEmojiData.ts +200 -0
  364. package/src/hooks/useScrollCategoryIntoView.ts +74 -12
  365. package/src/hooks/useSearchController.ts +369 -0
  366. package/src/hooks/useSearchResults.ts +51 -0
  367. package/src/hooks/useSetVariationPicker.ts +4 -1
  368. package/src/index.tsx +67 -5
  369. package/src/primitives/CategoryNav.tsx +40 -0
  370. package/src/primitives/Empty.tsx +68 -0
  371. package/src/primitives/List.tsx +61 -0
  372. package/src/primitives/LoadError.tsx +38 -0
  373. package/src/primitives/Loading.tsx +60 -0
  374. package/src/primitives/Panel.tsx +47 -0
  375. package/src/primitives/Preview.tsx +38 -0
  376. package/src/primitives/Reactions.tsx +2 -0
  377. package/src/primitives/Root.tsx +398 -0
  378. package/src/primitives/Search.tsx +41 -0
  379. package/src/primitives/SearchInput.tsx +110 -0
  380. package/src/primitives/SkinTone.tsx +76 -0
  381. package/src/primitives/Viewport.tsx +204 -0
  382. package/src/primitives/appearance.tsx +7 -0
  383. package/src/primitives/components.tsx +30 -0
  384. package/src/primitives/hooks.ts +165 -0
  385. package/src/primitives/index.ts +94 -0
  386. package/src/primitives/nativeProps.ts +90 -0
  387. package/src/primitives/scope.tsx +109 -0
  388. package/src/primitives/structuralStyles.tsx +136 -0
  389. package/src/primitives/tokens.ts +150 -0
  390. package/src/primitives/types.ts +192 -0
  391. package/src/state/activeEmojiStore.ts +39 -0
  392. package/src/state/navigationRegistry.ts +209 -0
  393. package/src/state/regionTraversal.ts +116 -0
  394. package/src/svg.d.ts +2 -2
  395. package/src/types/exposedTypes.ts +28 -1
  396. package/src/virtualization/virtualizationHelpers.ts +29 -8
  397. package/dist/components/body/Body.d.ts +0 -2
  398. package/dist/components/main/PickerMain.d.ts +0 -7
  399. package/dist/dataUtils/alphaNumericEmojiIndex.d.ts +0 -5
  400. package/dist/emoji-picker-react.cjs.development.js +0 -31413
  401. package/dist/emoji-picker-react.cjs.development.js.map +0 -1
  402. package/dist/emoji-picker-react.cjs.production.min.js +0 -2
  403. package/dist/emoji-picker-react.cjs.production.min.js.map +0 -1
  404. package/dist/emoji-picker-react.esm.js +0 -31411
  405. package/dist/emoji-picker-react.esm.js.map +0 -1
  406. package/dist/hooks/useHideEmojisByUniocode.d.ts +0 -1
  407. package/src/components/body/Body.tsx +0 -43
  408. package/src/components/main/PickerMain.tsx +0 -249
  409. package/src/dataUtils/alphaNumericEmojiIndex.ts +0 -21
@@ -1,58 +1,114 @@
1
1
  import * as React from 'react';
2
2
  import { cx } from 'shipstyles';
3
3
 
4
- import { commonStyles, stylesheet } from '../../Stylesheet/stylesheet';
4
+ import { stylesheet } from '../../Stylesheet/stylesheet';
5
5
  import {
6
6
  MOUSE_EVENT_SOURCE,
7
7
  useEmojiStyleConfig,
8
8
  useReactionsConfig,
9
9
  useAllowExpandReactions,
10
10
  useGetEmojiUrlConfig,
11
+ useLabels,
11
12
  } from '../../config/useConfig';
12
13
  import { DataEmoji } from '../../dataUtils/DataTypes';
13
- import { emojiByUnified } from '../../dataUtils/emojiSelectors';
14
+ import { resolveEntryId } from '../../dataUtils/suggestedEmojis';
15
+ import { useIsEmojiDisallowed } from '../../hooks/useDisallowedEmojis';
14
16
  import { useMouseDownHandlers } from '../../hooks/useMouseDownHandlers';
17
+ import { useRegisterRegion } from '../../hooks/useRegisterRegion';
18
+ import { useDefaultAppearance } from '../../primitives/appearance';
19
+ import { usePickerComponents } from '../../primitives/components';
20
+ import {
21
+ filterPrimitiveProps,
22
+ useMergedRefs,
23
+ } from '../../primitives/nativeProps';
24
+ import { useRootScope } from '../../primitives/scope';
25
+ import { EmojiStyle } from '../../types/exposedTypes';
15
26
  import { useReactionsRef } from '../context/ElementRefContext';
16
- import { useReactionsModeState } from '../context/PickerContext';
27
+ import {
28
+ useReactionsModeState,
29
+ useRequestNativeProbe,
30
+ } from '../context/PickerContext';
31
+ import { usePickerDataContext } from '../context/PickerDataContext';
17
32
  import { ClickableEmoji } from '../emoji/Emoji';
18
33
 
19
34
  import { BtnPlus } from './BtnPlus';
20
35
 
21
- export function Reactions() {
36
+ // Memoized: a direct child of the per-keystroke-rerendering Root aside.
37
+ // Props never change (none); context slices resubscribe on real changes,
38
+ // so typing never rerenders the bar while reactions state is untouched.
39
+ export type ReactionsProps = Omit<
40
+ React.HTMLAttributes<HTMLUListElement>,
41
+ 'role' | 'children' | 'dangerouslySetInnerHTML'
42
+ >;
43
+ const ReactionsImpl = /* @__PURE__ */ React.forwardRef<
44
+ HTMLUListElement,
45
+ ReactionsProps
46
+ >(function Reactions(allProps: ReactionsProps, ref) {
47
+ const { className, ...props } = allProps;
48
+ const inScope = useRootScope('Reactions');
49
+ const appearance = useDefaultAppearance();
50
+ const { Emoji: CustomEmoji } = usePickerComponents();
51
+ const decorated = appearance && !CustomEmoji;
22
52
  const [reactionsOpen] = useReactionsModeState();
23
53
  const ReactionsRef = useReactionsRef();
54
+ const mergedRef = useMergedRefs(ref, ReactionsRef);
24
55
  const reactions = useReactionsConfig();
25
56
  useMouseDownHandlers(ReactionsRef, MOUSE_EVENT_SOURCE.REACTIONS);
26
57
  const emojiStyle = useEmojiStyleConfig();
27
58
  const allowExpandReactions = useAllowExpandReactions();
28
59
  const getEmojiUrl = useGetEmojiUrlConfig();
60
+ const { emojiByUnified } = usePickerDataContext();
61
+ const labels = useLabels();
62
+ const isEmojiDisallowed = useIsEmojiDisallowed();
63
+ const requestNativeProbe = useRequestNativeProbe();
64
+ // Filled while rendering: every reaction, including ones the version
65
+ // prediction hid, gets an exact native glyph check.
66
+ const shown: string[] = [];
67
+ React.useEffect(() => requestNativeProbe(shown));
68
+
69
+ // Registered before the closed-mode early return so collapsing the full
70
+ // picker registers the bar and expanding unregisters it.
71
+ useRegisterRegion('reactions', ReactionsRef, [reactionsOpen]);
29
72
 
30
- if (!reactionsOpen) {
73
+ if (!inScope || !reactionsOpen) {
31
74
  return null;
32
75
  }
33
76
 
34
77
  return (
35
78
  <ul
36
- className={cx(styles.list, !reactionsOpen && commonStyles.hidden)}
37
- ref={ReactionsRef}
38
- aria-label="Reactions"
79
+ {...filterPrimitiveProps(props, ['role'])}
80
+ className={cx(styles.list, className)}
81
+ ref={mergedRef}
82
+ aria-label={labels.reactions}
83
+ data-epr-part="reactions"
39
84
  >
40
- {reactions.map((reaction) => {
41
- const emoji = emojiByUnified(reaction);
85
+ {reactions.map((reaction, index) => {
86
+ // Reaction identifiers use the same shared Root lookup as the
87
+ // picker, normalized case-insensitively.
88
+ const raw =
89
+ typeof reaction === 'string' ? reaction.trim().toLowerCase() : '';
90
+ // Emoji characters resolve like suggestedEmojis entries.
91
+ const normalized = resolveEntryId(raw, emojiByUnified) || raw;
92
+ const emoji = normalized ? emojiByUnified(normalized) : undefined;
93
+ if (emoji) shown.push(normalized);
42
94
 
43
- if (!emoji) {
95
+ if (
96
+ !emoji ||
97
+ (emojiStyle === EmojiStyle.NATIVE &&
98
+ isEmojiDisallowed(emoji, normalized))
99
+ ) {
44
100
  return null;
45
101
  }
46
102
 
47
103
  return (
48
- <li key={reaction}>
104
+ <li key={`${index}:${normalized}`} data-epr-part="reaction">
49
105
  <ClickableEmoji
50
106
  emoji={emoji as DataEmoji}
51
107
  emojiStyle={emojiStyle}
52
- unified={reaction}
108
+ unified={normalized}
53
109
  showVariations={false}
54
- className={cx(styles.emojiButton)}
55
- buttonClassName={cx(styles.reactionButton)}
110
+ className={cx(decorated && styles.emojiButton)}
111
+ buttonClassName={cx(decorated && styles.reactionButton)}
56
112
  noBackground
57
113
  getEmojiUrl={getEmojiUrl}
58
114
  />
@@ -66,47 +122,49 @@ export function Reactions() {
66
122
  ) : null}
67
123
  </ul>
68
124
  );
69
- }
125
+ });
126
+ export const Reactions = /* @__PURE__ */ React.memo(ReactionsImpl);
70
127
 
71
- const styles = stylesheet.create({
72
- list: {
73
- listStyle: 'none',
74
- margin: '0',
75
- padding: '0 5px',
76
- display: 'flex',
77
- justifyContent: 'space-between',
78
- alignItems: 'center',
79
- height: '100%',
80
- },
81
- reactionButton: {
82
- // Every picker button sets outline: none, and reaction buttons also
83
- // suppress the focus background, so keyboard focus was invisible.
84
- // Focus mirrors the hover treatment (scale plus a soft circular
85
- // wash, no outline ring): the scale transform on the inner image
86
- // alone is clipped by the button's overflow: hidden, and does
87
- // nothing on inline native emoji, so the button itself carries the
88
- // effect. Scoped to the reactions bar so grid focus treatment is
89
- // untouched.
90
- // https://github.com/ealush/emoji-picker-react/issues/473
91
- ':focus-visible': {
92
- transform: 'scale(1.2)',
93
- transition:
94
- 'background-color 0.2s, transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.5)',
95
- backgroundColor: 'var(--epr-hover-bg-color-reduced-opacity)',
96
- borderRadius: '50%',
97
- outline: 'none',
98
- },
99
- },
100
- emojiButton: {
101
- ':hover': {
102
- transform: 'scale(1.2)',
128
+ const styles = /* @__PURE__ */ (() =>
129
+ stylesheet.create({
130
+ list: {
131
+ listStyle: 'none',
132
+ margin: '0',
133
+ padding: '0 5px',
134
+ display: 'flex',
135
+ justifyContent: 'space-between',
136
+ alignItems: 'center',
137
+ height: '100%',
103
138
  },
104
- ':focus': {
105
- transform: 'scale(1.2)',
139
+ reactionButton: {
140
+ // Every picker button sets outline: none, and reaction buttons also
141
+ // suppress the focus background, so keyboard focus was invisible.
142
+ // Focus mirrors the hover treatment (scale plus a soft circular
143
+ // wash, no outline ring): the scale transform on the inner image
144
+ // alone is clipped by the button's overflow: hidden, and does
145
+ // nothing on inline native emoji, so the button itself carries the
146
+ // effect. Scoped to the reactions bar so grid focus treatment is
147
+ // untouched.
148
+ // https://github.com/ealush/emoji-picker-react/issues/473
149
+ ':focus-visible': {
150
+ transform: 'scale(1.2)',
151
+ transition:
152
+ 'background-color 0.2s, transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.5)',
153
+ backgroundColor: 'var(--epr-hover-bg-color-reduced-opacity)',
154
+ borderRadius: '50%',
155
+ outline: 'none',
156
+ },
106
157
  },
107
- ':active': {
108
- transform: 'scale(1.1)',
158
+ emojiButton: {
159
+ ':hover': {
160
+ transform: 'scale(1.2)',
161
+ },
162
+ ':focus': {
163
+ transform: 'scale(1.2)',
164
+ },
165
+ ':active': {
166
+ transform: 'scale(1.1)',
167
+ },
168
+ transition: 'transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.5)',
109
169
  },
110
- transition: 'transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.5)',
111
- },
112
- });
170
+ }))();
@@ -2,6 +2,7 @@ import * as React from 'react';
2
2
  import { cx } from 'shipstyles';
3
3
 
4
4
  import { stylesheet } from '../../Stylesheet/stylesheet';
5
+ import { useDefaultAppearance } from '../../primitives/appearance';
5
6
 
6
7
  interface Props extends React.DetailedHTMLProps<
7
8
  React.ButtonHTMLAttributes<HTMLButtonElement>,
@@ -11,28 +12,30 @@ interface Props extends React.DetailedHTMLProps<
11
12
  }
12
13
 
13
14
  export function Button(props: Props) {
15
+ const appearance = useDefaultAppearance();
14
16
  return (
15
17
  <button
16
18
  type="button"
17
19
  {...props}
18
- className={cx(styles.button, props.className)}
20
+ className={cx(appearance && buttonStyles.button, props.className)}
19
21
  >
20
22
  {props.children}
21
23
  </button>
22
24
  );
23
25
  }
24
26
 
25
- const styles = stylesheet.create({
26
- button: {
27
- '.': 'epr-btn',
28
- cursor: 'pointer',
29
- border: '0',
30
- // Longhand, not `background: 'none'`: a shorthand reset shares its
31
- // conflict keys with every background longhand, so cx() would drop
32
- // this whole class wherever a later class sets background-image
33
- // (e.g. the category nav sprite) and the native button face would
34
- // show through.
35
- backgroundColor: 'transparent',
36
- outline: 'none',
37
- },
38
- });
27
+ export const buttonStyles = /* @__PURE__ */ (() =>
28
+ stylesheet.create({
29
+ button: {
30
+ '.': 'epr-btn',
31
+ cursor: 'pointer',
32
+ border: '0',
33
+ // Longhand, not `background: 'none'`: a shorthand reset shares its
34
+ // conflict keys with every background longhand, so cx() would drop
35
+ // this whole class wherever a later class sets background-image
36
+ // (e.g. the category nav sprite) and the native button face would
37
+ // show through.
38
+ backgroundColor: 'transparent',
39
+ outline: 'none',
40
+ },
41
+ }))();
@@ -11,8 +11,11 @@ import {
11
11
  categoryIdFromCategoryConfig,
12
12
  categoryNameFromCategoryConfig,
13
13
  } from '../../config/categoryConfig';
14
+ import { useDefaultAppearance } from '../../primitives/appearance';
14
15
  import { CategoryConfig } from '../../types/exposedTypes';
15
16
 
17
+ import { useListComponents } from './listComponents';
18
+
16
19
  type Props = Readonly<{
17
20
  categoryConfig: CategoryConfig;
18
21
  children?: React.ReactNode;
@@ -20,6 +23,7 @@ type Props = Readonly<{
20
23
  hiddenOnSearch?: boolean;
21
24
  height?: number;
22
25
  emojisPerRow?: number;
26
+ emojiCount?: number;
23
27
  }>;
24
28
 
25
29
  export function EmojiCategory({
@@ -29,8 +33,13 @@ export function EmojiCategory({
29
33
  hiddenOnSearch,
30
34
  height,
31
35
  emojisPerRow,
36
+ emojiCount,
32
37
  }: Props) {
38
+ const appearance = useDefaultAppearance();
33
39
  const categoryName = categoryNameFromCategoryConfig(categoryConfig);
40
+ const categoryId = categoryIdFromCategoryConfig(categoryConfig);
41
+ const { CategoryHeader } = useListComponents();
42
+ const hasCells = React.Children.count(children) > 0;
34
43
 
35
44
  return (
36
45
  <li
@@ -39,16 +48,40 @@ export function EmojiCategory({
39
48
  hidden && commonStyles.hidden,
40
49
  hiddenOnSearch && commonInteractionStyles.hiddenOnSearch,
41
50
  )}
42
- data-name={categoryIdFromCategoryConfig(categoryConfig)}
51
+ data-epr-part="category"
52
+ data-epr-category={categoryId}
43
53
  role="rowgroup"
44
54
  aria-label={categoryName}
45
55
  >
46
- <h2 className={cx(styles.label)}>{categoryName}</h2>
56
+ {CategoryHeader ? (
57
+ <CategoryHeader
58
+ className={cx(styles.label, appearance && styles.labelAppearance)}
59
+ aria-hidden
60
+ data-epr-part="category-label"
61
+ category={{ id: categoryId, name: categoryName }}
62
+ >
63
+ {categoryName}
64
+ </CategoryHeader>
65
+ ) : (
66
+ // Visual only: the rowgroup already carries the category name, and
67
+ // a heading is not an allowed child of a grid rowgroup.
68
+ <h2
69
+ className={cx(styles.label, appearance && styles.labelAppearance)}
70
+ aria-hidden
71
+ data-epr-part="category-label"
72
+ >
73
+ {categoryName}
74
+ </h2>
75
+ )}
47
76
  <div
48
77
  className={cx(styles.categoryContent)}
49
78
  style={{ height }}
50
- role="row"
51
- data-emojis-per-row={emojisPerRow}
79
+ // A row must own cells: while virtualization renders none, the
80
+ // container is presentational.
81
+ role={hasCells ? 'row' : 'none'}
82
+ data-epr-part="category-content"
83
+ data-epr-emojis-per-row={emojisPerRow}
84
+ data-epr-emoji-count={emojiCount}
52
85
  >
53
86
  {children}
54
87
  </div>
@@ -56,39 +89,43 @@ export function EmojiCategory({
56
89
  );
57
90
  }
58
91
 
59
- const styles = stylesheet.create({
60
- category: {
61
- '.': ClassNames.category,
62
- minHeight:
63
- 'calc(var(--epr-emoji-fullsize) + var(--epr-category-label-height))',
64
- position: 'relative',
65
- },
66
- categoryContent: {
67
- '.': ClassNames.categoryContent,
68
- display: 'grid',
69
- gridGap: '0',
70
- gridTemplateColumns: 'repeat(auto-fill, var(--epr-emoji-fullsize))',
71
- justifyContent: 'space-between',
72
- margin: 'var(--epr-category-padding)',
73
- position: 'relative',
74
- },
75
- label: {
76
- '.': ClassNames.label,
77
- alignItems: 'center',
78
- // @ts-ignore - backdropFilter is not recognized.
79
- backdropFilter: 'blur(3px)',
80
- backgroundColor: 'var(--epr-category-label-bg-color)',
81
- color: 'var(--epr-category-label-text-color)',
82
- display: 'flex',
83
- fontSize: '16px',
84
- fontWeight: 'bold',
85
- height: 'var(--epr-category-label-height)',
86
- margin: '0',
87
- padding: 'var(--epr-category-label-padding)',
88
- position: 'sticky',
89
- textTransform: 'capitalize',
90
- top: '0',
91
- width: '100%',
92
- zIndex: 'var(--epr-category-label-z-index)',
93
- },
94
- });
92
+ const styles = /* @__PURE__ */ (() =>
93
+ stylesheet.create({
94
+ category: {
95
+ '.': ClassNames.category,
96
+ minHeight:
97
+ 'calc(var(--epr-emoji-fullsize) + var(--epr-category-label-height))',
98
+ position: 'relative',
99
+ },
100
+ categoryContent: {
101
+ '.': ClassNames.categoryContent,
102
+ display: 'grid',
103
+ gridGap: '0',
104
+ gridTemplateColumns: 'repeat(auto-fill, var(--epr-emoji-fullsize))',
105
+ justifyContent: 'space-between',
106
+ margin: 'var(--epr-category-padding)',
107
+ position: 'relative',
108
+ },
109
+ label: {
110
+ '.': ClassNames.label,
111
+ alignItems: 'center',
112
+ display: 'flex',
113
+ height: 'var(--epr-category-label-height)',
114
+ margin: '0',
115
+ padding: 'var(--epr-category-label-padding)',
116
+ position: 'sticky',
117
+ top: '0',
118
+ width: '100%',
119
+ zIndex: 'var(--epr-category-label-z-index)',
120
+ },
121
+ labelAppearance: {
122
+ '.': 'epr-category-label-appearance',
123
+ // @ts-ignore - backdropFilter is not recognized.
124
+ backdropFilter: 'blur(3px)',
125
+ backgroundColor: 'var(--epr-category-label-bg-color)',
126
+ color: 'var(--epr-category-label-text-color)',
127
+ fontSize: '16px',
128
+ fontWeight: 'bold',
129
+ textTransform: 'capitalize',
130
+ },
131
+ }))();
@@ -12,36 +12,81 @@ import {
12
12
  import { useCategoriesConfig } from '../../config/useConfig';
13
13
  import { DataEmojis } from '../../dataUtils/DataTypes';
14
14
  import { useEmojiVirtualization } from '../../hooks/useEmojiVirtualization';
15
+ import { useRegisterRegion } from '../../hooks/useRegisterRegion';
16
+ import { useMergedRefs } from '../../primitives/nativeProps';
15
17
  import { CategoryConfig } from '../../types/exposedTypes';
16
- import { useEmojiListRef } from '../context/ElementRefContext';
17
- import { useVisibleCategoriesState } from '../context/PickerContext';
18
+ import { OVERSCAN_ROWS } from '../../virtualization/virtualizationHelpers';
19
+ import { useBodyRef, useEmojiListRef } from '../context/ElementRefContext';
20
+ import {
21
+ useEmojiSizeState,
22
+ useVisibleCategoriesState,
23
+ } from '../context/PickerContext';
18
24
  import { useGetEmojisByCategory } from '../context/PickerDataContext';
19
25
 
20
26
  import { EmojiCategory } from './EmojiCategory';
21
27
  import { MeasureEmoji } from './MeasureEmoji';
22
28
 
23
- export function EmojiList({ scrollTop }: { scrollTop: number }) {
29
+ export function EmojiList({
30
+ scrollTop,
31
+ outerRef,
32
+ className,
33
+ nativeProps,
34
+ }: {
35
+ scrollTop: number;
36
+ outerRef?: React.Ref<HTMLUListElement>;
37
+ className?: string;
38
+ nativeProps?: Omit<
39
+ React.HTMLAttributes<HTMLUListElement>,
40
+ 'role' | 'children' | 'className' | 'ref'
41
+ >;
42
+ }) {
24
43
  const categories = useCategoriesConfig();
25
44
  const [categoryHeights, setCategoryHeights] = React.useState<{
26
45
  [key: string]: number;
27
46
  }>({});
28
47
  const EmojiListRef = useEmojiListRef();
48
+ const BodyRef = useBodyRef();
49
+ const [emojiSize] = useEmojiSizeState();
50
+ const [visibleCategories] = useVisibleCategoriesState();
51
+ const onHeightReady = React.useCallback(
52
+ (categoryId: string, height: number) => {
53
+ setCategoryHeights((previous) =>
54
+ previous[categoryId] === height
55
+ ? previous
56
+ : {
57
+ ...previous,
58
+ [categoryId]: height,
59
+ },
60
+ );
61
+ },
62
+ [],
63
+ );
64
+ const mergedRef = useMergedRefs(EmojiListRef, outerRef);
29
65
  const getEmojisByCategory = useGetEmojisByCategory();
66
+ useRegisterRegion('grid', EmojiListRef);
30
67
 
31
68
  const labelHeight = getLabelHeight(EmojiListRef.current);
32
69
 
33
70
  let topOffset = 0;
71
+ // A section's offset is real once every section above it is measured.
72
+ let positioned = true;
34
73
  // role="grid" makes screen readers switch out of virtual-cursor mode so
35
74
  // arrow keys reach the picker's keyboard handler. Each category is one
36
75
  // rowgroup: visual rows shift under virtualization, so the category is
37
- // the only stable row unit. Emoji buttons intentionally keep their
38
- // native button role for activation semantics.
76
+ // the only stable row unit. Emoji buttons are gridcells; as native
77
+ // buttons they still activate with Enter and Space.
39
78
  // https://github.com/ealush/emoji-picker-react/issues/508
40
79
  // The list markup is kept for a backwards-compatible DOM structure;
41
80
  // the grid role override is intentional.
42
81
  return (
43
- // eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role
44
- <ul className={cx(styles.emojiList)} ref={EmojiListRef} role="grid">
82
+ <ul
83
+ {...nativeProps}
84
+ className={cx(styles.emojiList, className)}
85
+ ref={mergedRef}
86
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role
87
+ role="grid"
88
+ data-epr-part="list"
89
+ >
45
90
  <MeasureEmoji />
46
91
  {categories.map((categoryConfig, index) => {
47
92
  const category = categoryFromCategoryConfig(categoryConfig);
@@ -49,6 +94,8 @@ export function EmojiList({ scrollTop }: { scrollTop: number }) {
49
94
  const group = customGroupFromCategoryConfig(categoryConfig);
50
95
 
51
96
  const currentOffset = topOffset;
97
+ const isPositioned = positioned;
98
+ positioned = positioned && categoryId in categoryHeights;
52
99
  const categoryHeight = categoryHeights[categoryId];
53
100
  if (categoryHeight) {
54
101
  topOffset += categoryHeight + labelHeight;
@@ -60,16 +107,28 @@ export function EmojiList({ scrollTop }: { scrollTop: number }) {
60
107
  categoryEmojis={getEmojisByCategory(category, group)}
61
108
  categoryConfig={categoryConfig}
62
109
  topOffset={currentOffset}
63
- isFirstCategory={index === 0}
64
- onHeightReady={(height) => {
65
- if (categoryHeights[categoryId] !== height) {
66
- setCategoryHeights((prev) => ({
67
- ...prev,
68
- [categoryId]: height,
69
- }));
70
- }
71
- }}
72
- scrollTop={scrollTop}
110
+ isCategoryVisible={
111
+ index === 0 || visibleCategories.includes(categoryId)
112
+ }
113
+ positioned={isPositioned}
114
+ onHeightReady={onHeightReady}
115
+ // Outside a section's rendering/preload margin, scrolling
116
+ // cannot change its cells. Keep its prop stable so it can bail.
117
+ scrollTop={
118
+ categoryHeight === undefined
119
+ ? scrollTop
120
+ : Math.max(
121
+ currentOffset -
122
+ (BodyRef.current?.clientHeight ?? 0) -
123
+ (emojiSize || 40) * (OVERSCAN_ROWS + 1),
124
+ Math.min(
125
+ scrollTop,
126
+ currentOffset +
127
+ categoryHeight +
128
+ (emojiSize || 40) * (OVERSCAN_ROWS + 1),
129
+ ),
130
+ )
131
+ }
73
132
  />
74
133
  );
75
134
  })}
@@ -77,22 +136,28 @@ export function EmojiList({ scrollTop }: { scrollTop: number }) {
77
136
  );
78
137
  }
79
138
 
80
- function RenderCategory({
139
+ const RenderCategory = /* @__PURE__ */ React.memo(function RenderCategory({
81
140
  categoryEmojis,
82
141
  categoryConfig,
83
142
  topOffset,
84
143
  onHeightReady,
85
144
  scrollTop,
86
- isFirstCategory,
145
+ isCategoryVisible,
146
+ positioned,
87
147
  }: {
88
148
  categoryEmojis: DataEmojis;
89
149
  categoryConfig: CategoryConfig;
90
150
  topOffset: number;
91
- onHeightReady: (height: number) => void;
151
+ onHeightReady: (categoryId: string, height: number) => void;
92
152
  scrollTop: number;
93
- isFirstCategory: boolean;
153
+ isCategoryVisible: boolean;
154
+ positioned: boolean;
94
155
  }) {
95
- const [visibleCategories] = useVisibleCategoriesState();
156
+ const categoryId = categoryIdFromCategoryConfig(categoryConfig);
157
+ const reportHeight = React.useCallback(
158
+ (height: number) => onHeightReady(categoryId, height),
159
+ [categoryId, onHeightReady],
160
+ );
96
161
 
97
162
  // The observer is the only writer of visibleCategories. When it never
98
163
  // fires (zero-height container at mount, hidden modal), no category
@@ -100,25 +165,22 @@ function RenderCategory({
100
165
  // the deadlock; the observer takes over from there.
101
166
  // https://github.com/ealush/emoji-picker-react/issues/469
102
167
  // https://github.com/ealush/emoji-picker-react/issues/475
103
- const isCategoryVisible =
104
- isFirstCategory ||
105
- visibleCategories.includes(
106
- categoryIdFromCategoryConfig(categoryConfig),
107
- );
108
-
109
- const { virtualizedCounter, emojis, dimensions } = useEmojiVirtualization({
110
- categoryEmojis,
111
- topOffset,
112
- onHeightReady,
113
- scrollTop,
114
- isCategoryVisible,
115
- });
168
+ const { virtualizedCounter, emojis, dimensions, emojiCount } =
169
+ useEmojiVirtualization({
170
+ categoryEmojis,
171
+ topOffset,
172
+ onHeightReady: reportHeight,
173
+ scrollTop,
174
+ isCategoryVisible,
175
+ positioned,
176
+ });
116
177
 
117
178
  return (
118
179
  <EmojiCategory
119
180
  categoryConfig={categoryConfig}
120
181
  height={dimensions?.categoryHeight}
121
182
  emojisPerRow={dimensions?.emojisPerRow}
183
+ emojiCount={emojiCount}
122
184
  // Indicates that there are no visible emojis
123
185
  // Hence, the category should be hidden
124
186
  hidden={!emojis.length && virtualizedCounter === 0}
@@ -126,13 +188,14 @@ function RenderCategory({
126
188
  {emojis}
127
189
  </EmojiCategory>
128
190
  );
129
- }
130
-
131
- const styles = stylesheet.create({
132
- emojiList: {
133
- '.': ClassNames.emojiList,
134
- listStyle: 'none',
135
- margin: '0',
136
- padding: '0',
137
- },
138
191
  });
192
+
193
+ const styles = /* @__PURE__ */ (() =>
194
+ stylesheet.create({
195
+ emojiList: {
196
+ '.': ClassNames.emojiList,
197
+ listStyle: 'none',
198
+ margin: '0',
199
+ padding: '0',
200
+ },
201
+ }))();