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,23 +1,23 @@
1
- import { elementCountInRow } from './elementPositionInRow';
2
1
  import { focusElement } from './focusElement';
3
2
  import { scrollEmojiAboveLabel } from './scrollTo';
4
3
  import {
5
- allVisibleEmojis,
6
4
  closestCategory,
5
+ allVisibleEmojis,
7
6
  firstVisibleEmoji,
8
- lastVisibleEmoji,
9
- nextCategory,
10
- nextVisibleEmoji,
7
+ adjacentCategory,
11
8
  NullableElement,
12
- prevCategory,
13
- prevVisibleEmoji,
14
- closestCategoryContent,
9
+ closestScrollBody,
10
+ categoryLabelHeight,
11
+ VisibleEmojiSelector,
15
12
  } from './selectors';
16
13
 
17
- export function focusFirstVisibleEmoji(parent: NullableElement) {
14
+ export function focusFirstVisibleEmoji(
15
+ parent: NullableElement,
16
+ shouldFocus?: () => boolean,
17
+ ) {
18
18
  const emoji = firstVisibleEmoji(parent);
19
- focusElement(emoji);
20
- scrollEmojiAboveLabel(emoji);
19
+ focusElement(emoji, shouldFocus);
20
+ scrollEmojiAboveLabel(emoji, shouldFocus);
21
21
  }
22
22
 
23
23
  export function focusAndClickFirstVisibleEmoji(parent: NullableElement) {
@@ -27,155 +27,175 @@ export function focusAndClickFirstVisibleEmoji(parent: NullableElement) {
27
27
  firstEmoji?.click();
28
28
  }
29
29
 
30
- export function focusLastVisibleEmoji(parent: NullableElement) {
31
- focusElement(lastVisibleEmoji(parent));
30
+ // Logical coordinates include unmounted cells. The DOM carries only the
31
+ // filtered count, column geometry and each mounted cell's logical index.
32
+ function categoryGeometry(category: HTMLElement) {
33
+ const content = category.querySelector<HTMLElement>(
34
+ '[data-epr-part="category-content"]',
35
+ );
36
+ const count = Number(content?.dataset.eprEmojiCount);
37
+ const columns = Number(content?.dataset.eprEmojisPerRow) || count;
38
+ return { content, count, columns };
32
39
  }
33
40
 
34
- export function focusNextVisibleEmoji(element: NullableElement) {
35
- if (!element) {
36
- return;
37
- }
38
-
39
- const next = nextVisibleEmoji(element);
40
-
41
- if (!next) {
42
- return focusFirstVisibleEmoji(nextCategory(element));
43
- }
44
-
45
- focusElement(next);
46
- scrollEmojiAboveLabel(next);
41
+ export type MoveOptions = {
42
+ shouldFocus?: () => boolean;
43
+ /** Called when an upward move leaves the grid. */
44
+ exitUp?: () => void;
45
+ /** Receives the destination cell; focuses it by default. */
46
+ moveTo?: (emoji: HTMLElement) => void;
47
+ /** Source cell while a virtualized destination is being materialized. */
48
+ origin?: HTMLElement;
49
+ };
50
+
51
+ /** Move to the first filtered result, including a cell outside the viewport. */
52
+ export function focusFirstEmoji(
53
+ body: NullableElement,
54
+ options: MoveOptions,
55
+ ): boolean {
56
+ const category = body?.querySelector<HTMLElement>(
57
+ '[data-epr-part="category-content"]:not([data-epr-emoji-count="0"])',
58
+ )?.parentElement;
59
+ if (category) focusLogicalEmoji(category, 0, options);
60
+ return !!category;
47
61
  }
48
62
 
49
- export function focusPrevVisibleEmoji(element: NullableElement) {
50
- if (!element) {
51
- return;
63
+ const pendingMoves = new WeakMap<
64
+ HTMLElement,
65
+ {
66
+ category: HTMLElement;
67
+ index: number;
68
+ origin?: HTMLElement;
69
+ valid: () => boolean;
52
70
  }
71
+ >();
53
72
 
54
- const prev = prevVisibleEmoji(element);
55
-
56
- if (!prev) {
57
- return focusLastVisibleEmoji(prevCategory(element));
58
- }
59
-
60
- focusElement(prev);
61
- scrollEmojiAboveLabel(prev);
62
- }
63
-
64
- export function focusVisibleEmojiOneRowUp(
73
+ export function focusAdjacentEmoji(
65
74
  element: NullableElement,
66
- exitUp: () => void,
75
+ direction: number,
76
+ row: boolean,
77
+ options: MoveOptions,
67
78
  ) {
68
- if (!element) {
79
+ const { shouldFocus, exitUp } = options;
80
+ if (!element || (shouldFocus && !shouldFocus())) return;
81
+ const category = closestCategory(element);
82
+ if (!category || element.dataset.eprIndex === undefined) {
83
+ // Variation buttons are fully mounted and use ordinary sibling movement.
84
+ const buttons = allVisibleEmojis(element.parentElement);
85
+ focusElement(
86
+ buttons[buttons.indexOf(element) + direction] ?? null,
87
+ shouldFocus,
88
+ );
69
89
  return;
70
90
  }
71
-
72
- const prev = visibleEmojiOneRowUp(element);
73
-
74
- if (!prev) {
75
- return exitUp();
76
- }
77
-
78
- focusElement(prev);
79
- scrollEmojiAboveLabel(prev);
91
+ const cursor = gridCursor(category, element);
92
+ const destination = logicalDestination(
93
+ cursor.category,
94
+ cursor.index,
95
+ direction,
96
+ row,
97
+ );
98
+ if (destination)
99
+ focusLogicalEmoji(destination.category, destination.index, {
100
+ ...options,
101
+ origin: element,
102
+ });
103
+ else if (direction < 0) exitUp?.();
80
104
  }
81
105
 
82
- export function focusVisibleEmojiOneRowDown(element: NullableElement) {
83
- if (!element) {
84
- return;
85
- }
86
-
87
- const next = visibleEmojiOneRowDown(element);
88
-
89
- return focusElement(next);
106
+ // A key pressed before the previous move mounted its destination continues
107
+ // from that destination, not from the still-focused source cell.
108
+ function gridCursor(category: HTMLElement, element: HTMLElement) {
109
+ const body = closestScrollBody(category);
110
+ const pending = body && pendingMoves.get(body);
111
+ return pending?.origin === element && pending.valid()
112
+ ? pending
113
+ : { category, index: Number(element.dataset.eprIndex) };
90
114
  }
91
115
 
92
- function visibleEmojiOneRowUp(element: HTMLElement) {
93
- if (!element) {
94
- return null;
95
- }
96
-
97
- const categoryContent = closestCategoryContent(element);
98
- const category = closestCategory(categoryContent);
99
- const countInRow = elementCountInRow(categoryContent, element);
100
-
101
- const emojisInCurrentCategory = allVisibleEmojis(category);
102
- const currentEmojiIndex = emojisInCurrentCategory.indexOf(element);
103
- const indexInRow = currentEmojiIndex % countInRow;
104
-
105
- if (currentEmojiIndex === -1) {
106
- return null;
107
- }
108
-
109
- if (emojisInCurrentCategory[currentEmojiIndex - countInRow]) {
110
- return emojisInCurrentCategory[currentEmojiIndex - countInRow];
111
- }
112
-
113
- const prevVisibleCategory = prevCategory(category);
114
-
115
- if (!prevVisibleCategory) {
116
- return null;
117
- }
118
-
119
- const allPrevEmojis = allVisibleEmojis(prevVisibleCategory);
120
-
121
- // if there is an emoji in the same index of `indexInRow` in the previous category, return it
122
- // for this we need to find the last emoji in the previous category that shares the same indexInRow
123
- // this is by using the % operator to find the last emoji that matches
124
-
125
- const lastIndexInRow = (allPrevEmojis.length % countInRow) - 1;
126
-
127
- if (indexInRow > lastIndexInRow) {
128
- return allPrevEmojis.at(-1);
129
- }
130
-
131
- // otherwise, return the last emoji that shares the same indexInRow
132
-
133
- for (let i = allPrevEmojis.length - 1; i >= 0; i--) {
134
- if (i % countInRow === indexInRow) {
135
- return allPrevEmojis[i];
136
- }
137
- }
138
-
139
- return allPrevEmojis.at(-1);
116
+ function logicalDestination(
117
+ category: HTMLElement,
118
+ currentIndex: number,
119
+ direction: number,
120
+ row: boolean,
121
+ ) {
122
+ const geometry = categoryGeometry(category);
123
+ const columns = geometry.columns;
124
+ let count = geometry.count;
125
+ if (count <= 0) return null;
126
+ const column = row ? currentIndex % columns : 0;
127
+ let index = row
128
+ ? (Math.floor(currentIndex / columns) + direction) * columns
129
+ : currentIndex + direction;
130
+ if (index < 0 || index >= count) {
131
+ const adjacent = adjacentDestination(category, direction, row);
132
+ if (!adjacent) return null;
133
+ ({ category, count, index } = adjacent);
134
+ }
135
+ return { category, index: Math.min(index + column, count - 1) };
140
136
  }
141
137
 
142
- function visibleEmojiOneRowDown(element: HTMLElement) {
143
- if (!element) {
144
- return null;
145
- }
146
-
147
- const categoryContent = closestCategoryContent(element);
148
- const category = closestCategory(categoryContent);
149
- const countInRow = elementCountInRow(categoryContent, element);
150
-
151
- const emojisInCurrentCategory = allVisibleEmojis(category);
152
- const currentEmojiIndex = emojisInCurrentCategory.indexOf(element);
153
-
154
- if (currentEmojiIndex === -1) {
155
- return null;
156
- }
157
-
158
- // the remainder until the end of the row
159
- const remainder = countInRow - (currentEmojiIndex % countInRow) - 1;
160
- const firstInNextRow = currentEmojiIndex + remainder + 1;
138
+ function adjacentDestination(
139
+ category: HTMLElement,
140
+ direction: number,
141
+ row: boolean,
142
+ ) {
143
+ const adjacent = adjacentCategory(category, direction);
144
+ if (!adjacent) return null;
145
+ const { count, columns } = categoryGeometry(adjacent);
146
+ if (count <= 0) return null;
147
+ const index =
148
+ direction > 0
149
+ ? 0
150
+ : row
151
+ ? Math.floor((count - 1) / columns) * columns
152
+ : count - 1;
153
+ return { category: adjacent, count, index };
154
+ }
161
155
 
162
- if (emojisInCurrentCategory[firstInNextRow]) {
163
- // if we have a next row, search in the next row for the last available emoji
164
- for (let p = currentEmojiIndex + countInRow; p % countInRow >= 0; p--) {
165
- if (emojisInCurrentCategory[p]) {
166
- return emojisInCurrentCategory[p];
167
- }
156
+ function focusLogicalEmoji(
157
+ category: HTMLElement,
158
+ index: number,
159
+ { shouldFocus, moveTo = (emoji) => emoji.focus(), origin }: MoveOptions,
160
+ ) {
161
+ const { content, columns, count } = categoryGeometry(category);
162
+ const body = closestScrollBody(category);
163
+ if (!body || !content || !columns) return;
164
+ const size = content.clientHeight / Math.ceil(count / columns);
165
+ let frames = 60;
166
+ const pending = { category, index, origin, valid: () => valid() };
167
+ pendingMoves.set(body, pending);
168
+ const valid = (): boolean =>
169
+ pendingMoves.get(body) === pending &&
170
+ (!shouldFocus || shouldFocus()) &&
171
+ body.contains(category);
172
+ const attempt = () => {
173
+ if (!valid()) return;
174
+ const emoji = category.querySelector<HTMLElement>(
175
+ `${VisibleEmojiSelector}[data-epr-index="${index}"]`,
176
+ );
177
+ if (emoji) {
178
+ moveTo(emoji);
179
+ scrollEmojiAboveLabel(emoji, valid);
180
+ // Keep the scroll guard valid until a later navigation replaces it,
181
+ // but only unfinished moves supply a logical cursor to another key.
182
+ pending.origin = undefined;
183
+ return;
168
184
  }
169
- }
170
-
171
- const indexInRow = currentEmojiIndex % countInRow;
172
-
173
- const nextVisibleCategory = nextCategory(category);
174
- const emojisInNextCategory = allVisibleEmojis(nextVisibleCategory);
175
-
176
- if (emojisInNextCategory[indexInRow]) {
177
- return emojisInNextCategory[indexInRow];
178
- }
179
-
180
- return emojisInNextCategory.at(0) ?? null;
185
+ if (!size || --frames <= 0) return;
186
+ if (frames === 59)
187
+ body.scrollTop =
188
+ category.offsetTop +
189
+ content.offsetTop +
190
+ Math.floor(index / columns) * size -
191
+ categoryLabelHeight(category);
192
+ requestAnimationFrame(attempt);
193
+ };
194
+ // Mounted cells can move immediately, so a second key in this frame
195
+ // reads the new position. Only unmounted destinations need a frame.
196
+ if (
197
+ category.querySelector(`${VisibleEmojiSelector}[data-epr-index="${index}"]`)
198
+ )
199
+ attempt();
200
+ else requestAnimationFrame(attempt);
181
201
  }
@@ -2,7 +2,7 @@ import { useCallback } from 'react';
2
2
 
3
3
  import { useBodyRef } from '../components/context/ElementRefContext';
4
4
 
5
- import { asSelectors, ClassNames } from './classNames';
5
+ import { ClassNames } from './classNames';
6
6
  import {
7
7
  categoryLabelHeight,
8
8
  closestCategory,
@@ -13,7 +13,11 @@ import {
13
13
  queryScrollBody,
14
14
  } from './selectors';
15
15
 
16
- export function scrollTo(root: NullableElement, top: number = 0) {
16
+ export function scrollTo(
17
+ root: NullableElement,
18
+ top: number | (() => number) = 0,
19
+ shouldScroll?: () => boolean,
20
+ ) {
17
21
  const $eprBody = queryScrollBody(root);
18
22
 
19
23
  if (!$eprBody) {
@@ -21,19 +25,8 @@ export function scrollTo(root: NullableElement, top: number = 0) {
21
25
  }
22
26
 
23
27
  requestAnimationFrame(() => {
24
- $eprBody.scrollTop = top;
25
- });
26
- }
27
-
28
- export function scrollBy(root: NullableElement, by: number): void {
29
- const $eprBody = queryScrollBody(root);
30
-
31
- if (!$eprBody) {
32
- return;
33
- }
34
-
35
- requestAnimationFrame(() => {
36
- $eprBody.scrollTop = $eprBody.scrollTop + by;
28
+ if (!shouldScroll || shouldScroll())
29
+ $eprBody.scrollTop = typeof top === 'function' ? top() : top;
37
30
  });
38
31
  }
39
32
 
@@ -52,16 +45,25 @@ export function useScrollTo() {
52
45
  );
53
46
  }
54
47
 
55
- export function scrollEmojiAboveLabel(emoji: NullableElement) {
48
+ export function scrollEmojiAboveLabel(
49
+ emoji: NullableElement,
50
+ shouldScroll?: () => boolean,
51
+ ) {
56
52
  if (!emoji || !isEmojiBehindLabel(emoji)) {
57
53
  return;
58
54
  }
59
55
 
60
- if (emoji.closest(asSelectors(ClassNames.variationPicker))) {
56
+ if (emoji.closest(`.${ClassNames.variationPicker}`)) {
61
57
  return;
62
58
  }
63
59
 
64
60
  const scrollBody = closestScrollBody(emoji);
65
61
  const by = emojiDistanceFromScrollTop(emoji);
66
- scrollBy(scrollBody, -(categoryLabelHeight(closestCategory(emoji)) - by));
62
+ if (scrollBody)
63
+ scrollTo(
64
+ scrollBody,
65
+ () =>
66
+ scrollBody.scrollTop - categoryLabelHeight(closestCategory(emoji)) + by,
67
+ shouldScroll,
68
+ );
67
69
  }
@@ -1,20 +1,12 @@
1
- import { DataEmoji } from '../dataUtils/DataTypes';
2
- import {
3
- emojiByUnified,
4
- unifiedWithoutSkinTone,
5
- } from '../dataUtils/emojiSelectors';
1
+ import { unifiedWithoutSkinTone } from '../dataUtils/emojiSelectors';
6
2
 
7
- import { asSelectors, ClassNames } from './classNames';
3
+ import { ClassNames } from './classNames';
8
4
  import { firstVisibleElementInContainer } from './elementPositionInRow';
9
5
 
10
6
  export type NullableElement = HTMLElement | null;
11
7
 
12
- export const EmojiButtonSelector = `button${asSelectors(ClassNames.emoji)}`;
13
- export const VisibleEmojiSelector = [
14
- EmojiButtonSelector,
15
- asSelectors(ClassNames.visible),
16
- `:not(${asSelectors(ClassNames.hidden)})`,
17
- ].join('');
8
+ export const EmojiButtonSelector = `button.${ClassNames.emoji}`;
9
+ export const VisibleEmojiSelector = `${EmojiButtonSelector}.${ClassNames.visible}:not(.${ClassNames.hidden})`;
18
10
 
19
11
  export function buttonFromTarget(
20
12
  emojiElement: NullableElement,
@@ -30,36 +22,16 @@ export function isEmojiButton(element: NullableElement): boolean {
30
22
  return element.matches(EmojiButtonSelector);
31
23
  }
32
24
 
33
- export function emojiFromElement(
34
- element: NullableElement,
35
- ): [DataEmoji, string] | [] {
36
- const originalUnified = originalUnifiedFromEmojiElement(element);
37
- const unified = unifiedFromEmojiElement(element);
38
-
39
- if (!originalUnified) {
40
- return [];
41
- }
42
-
43
- const emoji = emojiByUnified(unified ?? originalUnified);
44
-
45
- if (!emoji) {
46
- return [];
47
- }
48
-
49
- return [emoji, unified as string];
50
- }
51
-
25
+ // Any element inside an emoji button counts: custom List cells may nest
26
+ // their content arbitrarily deep.
52
27
  export function isEmojiElement(element: NullableElement): boolean {
53
- return Boolean(
54
- element?.matches(EmojiButtonSelector) ||
55
- element?.parentElement?.matches(EmojiButtonSelector),
56
- );
28
+ return buttonFromTarget(element) !== null;
57
29
  }
58
30
 
59
31
  export function categoryLabelFromCategory(
60
32
  category: NullableElement,
61
33
  ): NullableElement {
62
- return category?.querySelector(asSelectors(ClassNames.label)) ?? null;
34
+ return category?.querySelector(`.${ClassNames.label}`) ?? null;
63
35
  }
64
36
 
65
37
  export function closestCategoryLabel(
@@ -73,6 +45,11 @@ export function elementHeight(element: NullableElement): number {
73
45
  return element?.clientHeight ?? 0;
74
46
  }
75
47
 
48
+ /** Layout size including host button borders (unaffected by transforms). */
49
+ export function elementBorderBoxHeight(element: NullableElement): number {
50
+ return element?.offsetHeight || element?.clientHeight || 0;
51
+ }
52
+
76
53
  export function emojiTrueOffsetTop(element: NullableElement): number {
77
54
  if (!element) {
78
55
  return 0;
@@ -93,7 +70,7 @@ export function categoryLabelHeight(category: NullableElement): number {
93
70
  }
94
71
 
95
72
  const categoryWithoutLabel = category.querySelector(
96
- asSelectors(ClassNames.categoryContent),
73
+ `.${ClassNames.categoryContent}`,
97
74
  );
98
75
 
99
76
  return (
@@ -115,9 +92,9 @@ export function isEmojiBehindLabel(emoji: NullableElement): boolean {
115
92
  export function queryScrollBody(root: NullableElement): NullableElement {
116
93
  if (!root) return null;
117
94
 
118
- return root.matches(asSelectors(ClassNames.scrollBody))
95
+ return root.matches(`.${ClassNames.scrollBody}`)
119
96
  ? root
120
- : root.querySelector(asSelectors(ClassNames.scrollBody));
97
+ : root.querySelector(`.${ClassNames.scrollBody}`);
121
98
  }
122
99
 
123
100
  export function emojiDistanceFromScrollTop(emoji: NullableElement): number {
@@ -133,7 +110,7 @@ export function closestScrollBody(element: NullableElement): NullableElement {
133
110
  return null;
134
111
  }
135
112
 
136
- return element.closest(asSelectors(ClassNames.scrollBody)) ?? null;
113
+ return element.closest(`.${ClassNames.scrollBody}`) ?? null;
137
114
  }
138
115
 
139
116
  export function emojiTruOffsetLeft(element: NullableElement): number {
@@ -152,7 +129,7 @@ function elementOffsetLeft(element: NullableElement): number {
152
129
  }
153
130
 
154
131
  export function unifiedFromEmojiElement(emoji: NullableElement): string | null {
155
- return elementDataSetKey(buttonFromTarget(emoji), 'unified') ?? null;
132
+ return elementDataSetKey(buttonFromTarget(emoji), 'eprUnified') ?? null;
156
133
  }
157
134
 
158
135
  export function originalUnifiedFromEmojiElement(
@@ -214,50 +191,6 @@ export function allVisibleEmojis(parent: NullableElement) {
214
191
  ) as HTMLElement[];
215
192
  }
216
193
 
217
- export function lastVisibleEmoji(element: NullableElement): NullableElement {
218
- if (!element) return null;
219
-
220
- const allEmojis = allVisibleEmojis(element);
221
- const [last] = allEmojis.slice(-1);
222
- if (!last) {
223
- return null;
224
- }
225
-
226
- if (!isVisibleEmoji(last)) {
227
- return prevVisibleEmoji(last);
228
- }
229
-
230
- return last;
231
- }
232
-
233
- export function nextVisibleEmoji(element: HTMLElement): NullableElement {
234
- const next = element.nextElementSibling as HTMLElement;
235
-
236
- if (!next) {
237
- return firstVisibleEmoji(nextCategory(element));
238
- }
239
-
240
- if (!isVisibleEmoji(next)) {
241
- return nextVisibleEmoji(next);
242
- }
243
-
244
- return next;
245
- }
246
-
247
- export function prevVisibleEmoji(element: HTMLElement): NullableElement {
248
- const prev = element.previousElementSibling as HTMLElement;
249
-
250
- if (!prev) {
251
- return lastVisibleEmoji(prevCategory(element));
252
- }
253
-
254
- if (!isVisibleEmoji(prev)) {
255
- return prevVisibleEmoji(prev);
256
- }
257
-
258
- return prev;
259
- }
260
-
261
194
  export function firstVisibleEmoji(parent: NullableElement) {
262
195
  if (!parent) {
263
196
  return null;
@@ -268,58 +201,28 @@ export function firstVisibleEmoji(parent: NullableElement) {
268
201
  return firstVisibleElementInContainer(parent, allEmojis, 0.1);
269
202
  }
270
203
 
271
- export function prevCategory(element: NullableElement): NullableElement {
272
- const category = closestCategory(element);
273
-
274
- if (!category) {
275
- return null;
276
- }
277
-
278
- const prev = category.previousElementSibling as HTMLElement;
279
-
280
- if (!prev) {
281
- return null;
282
- }
283
-
284
- if (isHidden(prev)) {
285
- return prevCategory(prev);
286
- }
287
-
288
- return prev;
289
- }
290
-
291
- export function nextCategory(element: NullableElement): NullableElement {
292
- const category = closestCategory(element);
293
-
294
- if (!category) {
295
- return null;
296
- }
297
-
298
- const next = category.nextElementSibling as HTMLElement;
299
-
300
- if (!next) {
301
- return null;
302
- }
303
-
304
- if (isHidden(next)) {
305
- return nextCategory(next);
306
- }
307
-
308
- return next;
204
+ export function adjacentCategory(
205
+ element: NullableElement,
206
+ direction: number,
207
+ ): NullableElement {
208
+ const sibling =
209
+ direction > 0 ? 'nextElementSibling' : 'previousElementSibling';
210
+ let category = closestCategory(element)?.[sibling] as NullableElement;
211
+ while (category && isHidden(category))
212
+ category = category[sibling] as NullableElement;
213
+ return category ?? null;
309
214
  }
310
215
 
311
216
  export function closestCategory(element: NullableElement) {
312
217
  if (!element) {
313
218
  return null;
314
219
  }
315
- return element.closest(asSelectors(ClassNames.category)) as HTMLElement;
220
+ return element.closest(`.${ClassNames.category}`) as HTMLElement;
316
221
  }
317
222
 
318
223
  export function closestCategoryContent(element: NullableElement) {
319
224
  if (!element) {
320
225
  return null;
321
226
  }
322
- return element.closest(
323
- asSelectors(ClassNames.categoryContent),
324
- ) as HTMLElement;
227
+ return element.closest(`.${ClassNames.categoryContent}`) as HTMLElement;
325
228
  }