emoji-picker-react 4.22.3 → 5.0.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 (405) hide show
  1. package/README.md +331 -49
  2. package/dist/DomUtils/categoryNameFromDom.d.ts +1 -1
  3. package/dist/DomUtils/classNames.d.ts +24 -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 +7 -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-core/pickerData.d.ts +12 -0
  183. package/dist/data-core/prepare.d.ts +23 -0
  184. package/dist/data-core/search.d.ts +13 -0
  185. package/dist/data-core/types.d.ts +23 -0
  186. package/dist/data.d.mts +72 -0
  187. package/dist/data.d.ts +72 -0
  188. package/dist/dataUtils/DataTypes.d.ts +23 -19
  189. package/dist/dataUtils/emojiSelectors.d.ts +15 -16
  190. package/dist/dataUtils/emojiUtils.d.ts +1 -12
  191. package/dist/dataUtils/nativeEmojiSequenceSupport.d.ts +10 -0
  192. package/dist/dataUtils/nativeEmojiSupport.d.ts +40 -0
  193. package/dist/dataUtils/parseNativeEmoji.d.ts +1 -1
  194. package/dist/dataUtils/suggested.d.ts +11 -11
  195. package/dist/dataUtils/suggestedEmojis.d.ts +7 -0
  196. package/dist/esm/chunks/chunk-46BUDQLE.mjs +228 -0
  197. package/dist/esm/chunks/chunk-7ZGTUZFB.mjs +16 -0
  198. package/dist/esm/chunks/chunk-FQIJ4HBW.mjs +25 -0
  199. package/dist/esm/chunks/chunk-KQPOIRSC.mjs +9305 -0
  200. package/dist/esm/chunks/chunk-LO4TPPLH.mjs +43 -0
  201. package/dist/esm/chunks/emojis-6L3GRBAP.mjs +9 -0
  202. package/dist/esm/data.mjs +18 -0
  203. package/dist/esm/index.mjs +389 -0
  204. package/dist/esm/primitives/index.mjs +67 -0
  205. package/dist/hooks/preloadEmoji.d.ts +9 -9
  206. package/dist/hooks/useActiveCategoryScrollDetection.d.ts +11 -11
  207. package/dist/hooks/useCategoryHeight.d.ts +6 -5
  208. package/dist/hooks/useCloseAllOpenToggles.d.ts +2 -2
  209. package/dist/hooks/useDataIdentityStabilityWarning.d.ts +13 -0
  210. package/dist/hooks/useDebouncedState.d.ts +1 -1
  211. package/dist/hooks/useDisallowMouseMove.d.ts +4 -4
  212. package/dist/hooks/useDisallowedEmojis.d.ts +2 -3
  213. package/dist/hooks/useEmojiPreviewEvents.d.ts +3 -3
  214. package/dist/hooks/useEmojiVirtualization.d.ts +21 -17
  215. package/dist/hooks/useFilter.d.ts +10 -16
  216. package/dist/hooks/useFocus.d.ts +3 -3
  217. package/dist/hooks/useInitialLoad.d.ts +2 -2
  218. package/dist/hooks/useIsEmojiHidden.d.ts +8 -8
  219. package/dist/hooks/useIsMounted.d.ts +1 -1
  220. package/dist/hooks/useIsSearchMode.d.ts +1 -1
  221. package/dist/hooks/useIsomorphicLayoutEffect.d.ts +2 -2
  222. package/dist/hooks/useKeyboardNavigation.d.ts +3 -1
  223. package/dist/hooks/useMouseDownHandlers.d.ts +8 -4
  224. package/dist/hooks/useOnFocus.d.ts +1 -1
  225. package/dist/hooks/useOnScroll.d.ts +2 -2
  226. package/dist/hooks/useReactionsFocus.d.ts +1 -0
  227. package/dist/hooks/useRegisterRegion.d.ts +24 -0
  228. package/dist/hooks/useResolvedEmojiData.d.ts +37 -0
  229. package/dist/hooks/useScrollCategoryIntoView.d.ts +1 -1
  230. package/dist/hooks/useSearchController.d.ts +17 -0
  231. package/dist/hooks/useSearchResults.d.ts +8 -0
  232. package/dist/hooks/useSetVariationPicker.d.ts +2 -2
  233. package/dist/hooks/useShouldHideCustomEmojis.d.ts +1 -1
  234. package/dist/hooks/useShouldShowSkinTonePicker.d.ts +4 -4
  235. package/dist/index.d.mts +376 -0
  236. package/dist/index.d.ts +376 -9
  237. package/dist/index.js +2 -8
  238. package/dist/primitives/CategoryNav.d.ts +4 -0
  239. package/dist/primitives/Empty.d.ts +6 -0
  240. package/dist/primitives/List.d.ts +4 -0
  241. package/dist/primitives/LoadError.d.ts +8 -0
  242. package/dist/primitives/Loading.d.ts +4 -0
  243. package/dist/primitives/Panel.d.ts +3 -0
  244. package/dist/primitives/Preview.d.ts +3 -0
  245. package/dist/primitives/Reactions.d.ts +2 -0
  246. package/dist/primitives/Root.d.ts +26 -0
  247. package/dist/primitives/Search.d.ts +5 -0
  248. package/dist/primitives/SearchInput.d.ts +3 -0
  249. package/dist/primitives/SkinTone.d.ts +4 -0
  250. package/dist/primitives/Viewport.d.ts +19 -0
  251. package/dist/primitives/appearance.d.ts +3 -0
  252. package/dist/primitives/components.d.ts +27 -0
  253. package/dist/primitives/hooks.d.ts +48 -0
  254. package/dist/primitives/index.d.mts +561 -0
  255. package/dist/primitives/index.d.ts +561 -0
  256. package/dist/primitives/index.js +2 -0
  257. package/dist/primitives/nativeProps.d.ts +15 -0
  258. package/dist/primitives/scope.d.ts +13 -0
  259. package/dist/primitives/structuralStyles.d.ts +16 -0
  260. package/dist/primitives/tokens.d.ts +18 -0
  261. package/dist/primitives/types.d.ts +85 -0
  262. package/dist/state/activeEmojiStore.d.ts +7 -0
  263. package/dist/state/navigationRegistry.d.ts +61 -0
  264. package/dist/state/regionTraversal.d.ts +20 -0
  265. package/dist/typeRefinements/typeRefinements.d.ts +6 -6
  266. package/dist/types/exposedTypes.d.ts +16 -6
  267. package/dist/types/exposedTypes.js +5 -0
  268. package/dist/virtualization/virtualizationHelpers.d.ts +20 -18
  269. package/llms-full.txt +3680 -0
  270. package/llms.txt +66 -480
  271. package/package.json +180 -66
  272. package/src/DomUtils/categoryNameFromDom.ts +1 -1
  273. package/src/DomUtils/classNames.ts +1 -0
  274. package/src/DomUtils/elementPositionInRow.ts +26 -4
  275. package/src/DomUtils/eventBelongsToPicker.ts +17 -0
  276. package/src/DomUtils/getActiveElement.ts +7 -1
  277. package/src/DomUtils/isJsdom.ts +12 -0
  278. package/src/DomUtils/isRtl.ts +5 -0
  279. package/src/DomUtils/keyboardNavigation.ts +105 -149
  280. package/src/DomUtils/scrollTo.ts +18 -16
  281. package/src/DomUtils/selectors.ts +20 -111
  282. package/src/EmojiPickerReact.tsx +155 -48
  283. package/src/Stylesheet/DedupedStyle.tsx +80 -0
  284. package/src/Stylesheet/stylesheet.tsx +128 -59
  285. package/src/components/Layout/Flex.tsx +12 -11
  286. package/src/components/Reactions/BtnPlus.tsx +61 -51
  287. package/src/components/Reactions/Reactions.tsx +113 -55
  288. package/src/components/atoms/Button.tsx +18 -15
  289. package/src/components/body/EmojiCategory.tsx +77 -40
  290. package/src/components/body/EmojiList.tsx +55 -23
  291. package/src/components/body/EmojiVariationPicker.tsx +113 -66
  292. package/src/components/body/MeasureEmoji.tsx +9 -2
  293. package/src/components/body/listComponents.tsx +79 -0
  294. package/src/components/context/ElementRefContext.tsx +46 -35
  295. package/src/components/context/PickerConfigContext.tsx +55 -40
  296. package/src/components/context/PickerContext.tsx +567 -92
  297. package/src/components/context/PickerDataContext.tsx +110 -99
  298. package/src/components/emoji/BaseEmojiProps.ts +5 -4
  299. package/src/components/emoji/ClickableEmojiButton.tsx +148 -63
  300. package/src/components/emoji/Emoji.tsx +24 -2
  301. package/src/components/emoji/EmojiImg.tsx +13 -12
  302. package/src/components/emoji/ExportedEmoji.tsx +5 -4
  303. package/src/components/emoji/NativeEmoji.tsx +19 -16
  304. package/src/components/emoji/ViewOnlyEmoji.tsx +55 -30
  305. package/src/components/emoji/emojiStyles.ts +12 -11
  306. package/src/components/footer/Preview.tsx +86 -91
  307. package/src/components/header/Header.tsx +21 -6
  308. package/src/components/header/Search/BtnClearSearch.tsx +69 -55
  309. package/src/components/header/Search/IcnSearch.tsx +21 -21
  310. package/src/components/header/Search/Search.tsx +77 -137
  311. package/src/components/header/SkinTonePicker/BtnSkinToneVariation.tsx +99 -62
  312. package/src/components/header/SkinTonePicker/SkinTonePicker.tsx +84 -46
  313. package/src/components/icons/svgIcons.ts +17 -0
  314. package/src/components/main/PickerMainBehaviors.tsx +163 -0
  315. package/src/components/main/defaultAppearance.tsx +188 -0
  316. package/src/components/main/labelHeight.ts +5 -0
  317. package/src/components/navigation/CategoryButton.tsx +83 -57
  318. package/src/components/navigation/CategoryNavIcon.tsx +73 -194
  319. package/src/components/navigation/CategoryNavigation.tsx +118 -46
  320. package/src/config/categoryConfig.ts +7 -3
  321. package/src/config/cdnUrls.ts +11 -21
  322. package/src/config/compareConfig.ts +128 -30
  323. package/src/config/config.ts +228 -24
  324. package/src/config/defaultPickerConfiguration.ts +7 -0
  325. package/src/config/mutableConfig.ts +44 -20
  326. package/src/config/useConfig.ts +130 -37
  327. package/src/data/defaultEmojiData.ts +49 -0
  328. package/src/data/registerDefaultEmojiData.ts +8 -0
  329. package/src/data-core/pickerData.ts +173 -0
  330. package/src/data-core/prepare.ts +178 -0
  331. package/src/data-core/search.ts +122 -0
  332. package/src/data-core/types.ts +36 -0
  333. package/src/data.ts +10 -0
  334. package/src/dataUtils/DataTypes.ts +4 -0
  335. package/src/dataUtils/emojiSelectors.ts +58 -63
  336. package/src/dataUtils/emojiUtils.ts +17 -74
  337. package/src/dataUtils/nativeEmojiSequenceSupport.ts +116 -0
  338. package/src/dataUtils/nativeEmojiSupport.ts +160 -0
  339. package/src/dataUtils/suggested.ts +8 -4
  340. package/src/dataUtils/suggestedEmojis.ts +92 -0
  341. package/src/env.d.ts +4 -0
  342. package/src/hooks/preloadEmoji.ts +3 -3
  343. package/src/hooks/useActiveCategoryScrollDetection.ts +10 -1
  344. package/src/hooks/useCategoryHeight.ts +82 -8
  345. package/src/hooks/useDataIdentityStabilityWarning.ts +86 -0
  346. package/src/hooks/useDebouncedState.ts +13 -1
  347. package/src/hooks/useDisallowedEmojis.ts +26 -42
  348. package/src/hooks/useEmojiPreviewEvents.ts +43 -10
  349. package/src/hooks/useEmojiVirtualization.tsx +38 -4
  350. package/src/hooks/useFilter.ts +85 -127
  351. package/src/hooks/useFocus.ts +14 -24
  352. package/src/hooks/useIsEmojiHidden.ts +10 -6
  353. package/src/hooks/useKeyboardNavigation.ts +322 -429
  354. package/src/hooks/useMouseDownHandlers.ts +91 -16
  355. package/src/hooks/useOnFocus.ts +12 -3
  356. package/src/hooks/useOnScroll.ts +18 -2
  357. package/src/hooks/useReactionsFocus.ts +118 -0
  358. package/src/hooks/useRegisterRegion.ts +92 -0
  359. package/src/hooks/useResolvedEmojiData.ts +200 -0
  360. package/src/hooks/useScrollCategoryIntoView.ts +74 -12
  361. package/src/hooks/useSearchController.ts +369 -0
  362. package/src/hooks/useSearchResults.ts +51 -0
  363. package/src/hooks/useSetVariationPicker.ts +4 -1
  364. package/src/index.tsx +67 -5
  365. package/src/primitives/CategoryNav.tsx +40 -0
  366. package/src/primitives/Empty.tsx +68 -0
  367. package/src/primitives/List.tsx +61 -0
  368. package/src/primitives/LoadError.tsx +38 -0
  369. package/src/primitives/Loading.tsx +60 -0
  370. package/src/primitives/Panel.tsx +47 -0
  371. package/src/primitives/Preview.tsx +38 -0
  372. package/src/primitives/Reactions.tsx +2 -0
  373. package/src/primitives/Root.tsx +398 -0
  374. package/src/primitives/Search.tsx +41 -0
  375. package/src/primitives/SearchInput.tsx +110 -0
  376. package/src/primitives/SkinTone.tsx +76 -0
  377. package/src/primitives/Viewport.tsx +204 -0
  378. package/src/primitives/appearance.tsx +7 -0
  379. package/src/primitives/components.tsx +30 -0
  380. package/src/primitives/hooks.ts +165 -0
  381. package/src/primitives/index.ts +94 -0
  382. package/src/primitives/nativeProps.ts +90 -0
  383. package/src/primitives/scope.tsx +109 -0
  384. package/src/primitives/structuralStyles.tsx +133 -0
  385. package/src/primitives/tokens.ts +149 -0
  386. package/src/primitives/types.ts +192 -0
  387. package/src/state/activeEmojiStore.ts +39 -0
  388. package/src/state/navigationRegistry.ts +209 -0
  389. package/src/state/regionTraversal.ts +116 -0
  390. package/src/svg.d.ts +2 -2
  391. package/src/types/exposedTypes.ts +28 -1
  392. package/src/virtualization/virtualizationHelpers.ts +20 -6
  393. package/dist/components/body/Body.d.ts +0 -2
  394. package/dist/components/main/PickerMain.d.ts +0 -7
  395. package/dist/dataUtils/alphaNumericEmojiIndex.d.ts +0 -5
  396. package/dist/emoji-picker-react.cjs.development.js +0 -31413
  397. package/dist/emoji-picker-react.cjs.development.js.map +0 -1
  398. package/dist/emoji-picker-react.cjs.production.min.js +0 -2
  399. package/dist/emoji-picker-react.cjs.production.min.js.map +0 -1
  400. package/dist/emoji-picker-react.esm.js +0 -31411
  401. package/dist/emoji-picker-react.esm.js.map +0 -1
  402. package/dist/hooks/useHideEmojisByUniocode.d.ts +0 -1
  403. package/src/components/body/Body.tsx +0 -43
  404. package/src/components/main/PickerMain.tsx +0 -249
  405. package/src/dataUtils/alphaNumericEmojiIndex.ts +0 -21
@@ -5,6 +5,7 @@ import { cx } from 'shipstyles';
5
5
  import { ClassNames } from '../../DomUtils/classNames';
6
6
  import { focusFirstVisibleEmoji } from '../../DomUtils/keyboardNavigation';
7
7
  import {
8
+ allUnifiedFromEmojiElement,
8
9
  buttonFromTarget,
9
10
  elementHeight,
10
11
  emojiTrueOffsetTop,
@@ -20,16 +21,21 @@ import {
20
21
  emojiUnified,
21
22
  emojiVariations,
22
23
  } from '../../dataUtils/emojiUtils';
24
+ import { useIsEmojiDisallowed } from '../../hooks/useDisallowedEmojis';
25
+ import { useDefaultAppearance } from '../../primitives/appearance';
26
+ import { EmojiStyle } from '../../types/exposedTypes';
23
27
  import {
24
28
  useAnchoredEmojiRef,
25
29
  useBodyRef,
26
30
  useSetAnchoredEmojiRef,
27
31
  useVariationPickerRef,
28
32
  } from '../context/ElementRefContext';
29
- import { useEmojiVariationPickerState } from '../context/PickerContext';
33
+ import {
34
+ useEmojiVariationPickerState,
35
+ useRequestNativeProbe,
36
+ } from '../context/PickerContext';
30
37
  import { ClickableEmoji } from '../emoji/Emoji';
31
-
32
- import SVGTriangle from './svg/triangle.svg';
38
+ import { TRIANGLE_ICON as SVGTriangle } from '../icons/svgIcons';
33
39
 
34
40
  enum Direction {
35
41
  Up,
@@ -38,10 +44,12 @@ enum Direction {
38
44
 
39
45
  // eslint-disable-next-line complexity
40
46
  export function EmojiVariationPicker() {
47
+ const appearance = useDefaultAppearance();
41
48
  const AnchoredEmojiRef = useAnchoredEmojiRef();
42
49
  const VariationPickerRef = useVariationPickerRef();
43
50
  const [emoji] = useEmojiVariationPickerState();
44
51
  const emojiStyle = useEmojiStyleConfig();
52
+ const isEmojiDisallowed = useIsEmojiDisallowed();
45
53
 
46
54
  const { getTop, getMenuDirection } =
47
55
  useVariationPickerTop(VariationPickerRef);
@@ -54,6 +62,11 @@ export function EmojiVariationPicker() {
54
62
  const visible = Boolean(
55
63
  emoji &&
56
64
  button &&
65
+ (emojiStyle !== EmojiStyle.NATIVE ||
66
+ !isEmojiDisallowed(
67
+ emoji,
68
+ allUnifiedFromEmojiElement(button).unified ?? undefined,
69
+ )) &&
57
70
  emojiHasVariations(emoji) &&
58
71
  button.classList.contains(ClassNames.emojiHasVariations),
59
72
  );
@@ -66,6 +79,14 @@ export function EmojiVariationPicker() {
66
79
  focusFirstVisibleEmoji(VariationPickerRef.current);
67
80
  }, [VariationPickerRef, visible, AnchoredEmojiRef]);
68
81
 
82
+ // Tones are checked when the menu opens, not for every grid cell.
83
+ const requestNativeProbe = useRequestNativeProbe();
84
+ useEffect(() => {
85
+ if (visible && emoji) {
86
+ requestNativeProbe([emojiUnified(emoji)].concat(emojiVariations(emoji)));
87
+ }
88
+ }, [requestNativeProbe, visible, emoji]);
89
+
69
90
  let top, pointerStyle;
70
91
 
71
92
  if (!visible && AnchoredEmojiRef.current) {
@@ -78,17 +99,19 @@ export function EmojiVariationPicker() {
78
99
  return (
79
100
  <div
80
101
  ref={VariationPickerRef}
81
- className={cx(
82
- styles.variationPicker,
83
- getMenuDirection() === Direction.Down && styles.pointingUp,
84
- visible && styles.visible,
85
- )}
102
+ data-epr-part="variation-picker"
103
+ className={variationClassName(appearance, visible, getMenuDirection())}
86
104
  style={{ top }}
87
105
  >
88
106
  {visible && emoji
89
107
  ? [emojiUnified(emoji)]
90
108
  .concat(emojiVariations(emoji))
91
109
  .slice(0, 6)
110
+ .filter(
111
+ (unified) =>
112
+ emojiStyle !== EmojiStyle.NATIVE ||
113
+ !isEmojiDisallowed(emoji, unified),
114
+ )
92
115
  .map((unified) => (
93
116
  <ClickableEmoji
94
117
  key={unified}
@@ -100,12 +123,30 @@ export function EmojiVariationPicker() {
100
123
  />
101
124
  ))
102
125
  : null}
103
- <div className={cx(styles.pointer)} style={pointerStyle} />
126
+ {appearance && (
127
+ <div className={cx(styles.pointer)} style={pointerStyle} />
128
+ )}
104
129
  </div>
105
130
  );
106
131
  }
107
132
 
108
- function usePointerStyle(VariationPickerRef: React.RefObject<HTMLElement>) {
133
+ function variationClassName(
134
+ appearance: boolean,
135
+ visible: boolean,
136
+ direction: Direction,
137
+ ) {
138
+ return cx(
139
+ styles.geometry,
140
+ appearance && styles.variationPicker,
141
+ appearance && direction === Direction.Down && styles.pointingUp,
142
+ visible && styles.visibleGeometry,
143
+ appearance && visible && styles.visible,
144
+ );
145
+ }
146
+
147
+ function usePointerStyle(
148
+ VariationPickerRef: React.RefObject<HTMLElement | null>,
149
+ ) {
109
150
  const AnchoredEmojiRef = useAnchoredEmojiRef();
110
151
  return function getPointerStyle() {
111
152
  const style: React.CSSProperties = {};
@@ -131,7 +172,7 @@ function usePointerStyle(VariationPickerRef: React.RefObject<HTMLElement>) {
131
172
  }
132
173
 
133
174
  function useVariationPickerTop(
134
- VariationPickerRef: React.RefObject<HTMLElement>,
175
+ VariationPickerRef: React.RefObject<HTMLElement | null>,
135
176
  ) {
136
177
  const AnchoredEmojiRef = useAnchoredEmojiRef();
137
178
  const BodyRef = useBodyRef();
@@ -176,60 +217,66 @@ function useVariationPickerTop(
176
217
  }
177
218
  }
178
219
 
179
- const styles = stylesheet.create({
180
- variationPicker: {
181
- '.': ClassNames.variationPicker,
182
- position: 'absolute',
183
- right: '15px',
184
- left: '15px',
185
- padding: '5px',
186
- boxShadow: '0px 2px 5px rgba(0, 0, 0, 0.2)',
187
- borderRadius: '3px',
188
- display: 'flex',
189
- alignItems: 'center',
190
- justifyContent: 'space-around',
191
- opacity: '0',
192
- visibility: 'hidden',
193
- pointerEvents: 'none',
194
- top: '-100%',
195
- border: '1px solid var(--epr-picker-border-color)',
196
- height: 'var(--epr-emoji-variation-picker-height)',
197
- zIndex: 'var(--epr-skin-variation-picker-z-index)',
198
- background: 'var(--epr-emoji-variation-picker-bg-color)',
199
- transform: 'scale(0.9)',
200
- transition: 'transform 0.1s ease-out, opacity 0.2s ease-out',
201
- },
202
- visible: {
203
- opacity: '1',
204
- visibility: 'visible',
205
- pointerEvents: 'all',
206
- transform: 'scale(1)',
207
- },
208
- pointingUp: {
209
- '.': 'pointing-up',
210
- transformOrigin: 'center 0%',
211
- transform: 'scale(0.9)',
212
- },
213
- '.pointing-up': {
220
+ const styles = /* @__PURE__ */ (() =>
221
+ stylesheet.create({
222
+ geometry: {
223
+ '.': ClassNames.variationPicker,
224
+ position: 'absolute',
225
+ right: '15px',
226
+ left: '15px',
227
+ padding: '5px',
228
+ display: 'flex',
229
+ alignItems: 'center',
230
+ justifyContent: 'space-around',
231
+ opacity: '0',
232
+ visibility: 'hidden',
233
+ pointerEvents: 'none',
234
+ top: '-100%',
235
+ height: 'var(--epr-emoji-variation-picker-height)',
236
+ zIndex: 'var(--epr-skin-variation-picker-z-index)',
237
+ },
238
+ variationPicker: {
239
+ '.': ClassNames.variationPicker,
240
+ boxShadow: '0px 2px 5px rgba(0, 0, 0, 0.2)',
241
+ borderRadius: '3px',
242
+ border: '1px solid var(--epr-picker-border-color)',
243
+ background: 'var(--epr-emoji-variation-picker-bg-color)',
244
+ transform: 'scale(0.9)',
245
+ transition: 'transform 0.1s ease-out, opacity 0.2s ease-out',
246
+ },
247
+ visibleGeometry: {
248
+ opacity: '1',
249
+ visibility: 'visible',
250
+ pointerEvents: 'all',
251
+ },
252
+ visible: {
253
+ transform: 'scale(1)',
254
+ },
255
+ pointingUp: {
256
+ '.': 'pointing-up',
257
+ transformOrigin: 'center 0%',
258
+ transform: 'scale(0.9)',
259
+ },
260
+ '.pointing-up': {
261
+ pointer: {
262
+ top: '0',
263
+ transform: 'rotate(180deg) translateY(100%) translateX(18px)',
264
+ },
265
+ },
214
266
  pointer: {
215
- top: '0',
216
- transform: 'rotate(180deg) translateY(100%) translateX(18px)',
267
+ '.': 'epr-emoji-pointer',
268
+ content: '',
269
+ position: 'absolute',
270
+ width: '25px',
271
+ height: '15px',
272
+ backgroundRepeat: 'no-repeat',
273
+ backgroundPosition: '0 0',
274
+ backgroundSize: '50px 15px',
275
+ top: '100%',
276
+ transform: 'translateX(-18px)',
277
+ backgroundImage: `url("${SVGTriangle}")`,
217
278
  },
218
- },
219
- pointer: {
220
- '.': 'epr-emoji-pointer',
221
- content: '',
222
- position: 'absolute',
223
- width: '25px',
224
- height: '15px',
225
- backgroundRepeat: 'no-repeat',
226
- backgroundPosition: '0 0',
227
- backgroundSize: '50px 15px',
228
- top: '100%',
229
- transform: 'translateX(-18px)',
230
- backgroundImage: `url(${SVGTriangle})`,
231
- },
232
- ...darkMode('pointer', {
233
- backgroundPosition: '-25px 0',
234
- }),
235
- });
279
+ ...darkMode('pointer', {
280
+ backgroundPosition: '-25px 0',
281
+ }),
282
+ }))();
@@ -1,5 +1,6 @@
1
1
  import * as React from 'react';
2
2
 
3
+ import { elementBorderBoxHeight } from '../../DomUtils/selectors';
3
4
  import {
4
5
  categoryFromCategoryConfig,
5
6
  customGroupFromCategoryConfig,
@@ -31,7 +32,12 @@ export function MeasureEmoji() {
31
32
 
32
33
  useIsomorphicLayoutEffect(() => {
33
34
  if (ref.current) {
34
- setEmojiSize(ref.current.clientHeight);
35
+ // Measure the button itself: the wrapper collapses to zero height
36
+ // because its only child is absolutely positioned, which would
37
+ // report 0 forever and keep this measurer mounted (navigation
38
+ // invalidation and stray-node costs on every render).
39
+ const button = ref.current.querySelector('button');
40
+ setEmojiSize(elementBorderBoxHeight(button) || ref.current.clientHeight);
35
41
  }
36
42
  });
37
43
 
@@ -53,7 +59,7 @@ export function MeasureEmoji() {
53
59
  }
54
60
 
55
61
  return (
56
- <div ref={ref}>
62
+ <div ref={ref} aria-hidden="true">
57
63
  <ClickableEmoji
58
64
  emoji={dummyEmoji}
59
65
  unified={unified}
@@ -62,6 +68,7 @@ export function MeasureEmoji() {
62
68
  lazyLoad={lazyLoadEmojis}
63
69
  showVariations={false}
64
70
  hidden={false}
71
+ tabIndex={-1}
65
72
  style={{
66
73
  opacity: 0,
67
74
  pointerEvents: 'none',
@@ -0,0 +1,79 @@
1
+ import * as React from 'react';
2
+
3
+ import { DataEmoji } from '../../dataUtils/DataTypes';
4
+ import { emojiNames, emojiHasVariations } from '../../dataUtils/emojiUtils';
5
+ import { parseNativeEmoji } from '../../dataUtils/parseNativeEmoji';
6
+ import { isCustomEmoji } from '../../typeRefinements/typeRefinements';
7
+ import { EmojiStyle, EmojiStyleValue } from '../../types/exposedTypes';
8
+
9
+ /** The emoji a custom `Emoji` cell renders. */
10
+ export type ListEmoji = {
11
+ /** True while hovered or keyboard-focused. */
12
+ isActive: boolean;
13
+ /** Unified code including the active skin tone, e.g. `1f44d-1f3fd`. */
14
+ unified: string;
15
+ names: string[];
16
+ /** Native emoji text (custom emojis: their id). */
17
+ emoji: string;
18
+ isCustom: boolean;
19
+ /** Active image style URL, or undefined for standard native emojis. */
20
+ imageUrl?: string;
21
+ /** Whether a long press opens skin tone variations. */
22
+ hasVariations: boolean;
23
+ };
24
+
25
+ /**
26
+ * Props for a custom emoji cell. Spread everything except `emoji` onto a
27
+ * `<button>`: the library-owned attributes (type, class, position style,
28
+ * tabIndex, aria-label, data-epr-*) carry selection, keyboard navigation,
29
+ * virtualization and accessibility. `children` is the default glyph/image;
30
+ * render it or your own content.
31
+ */
32
+ export type EmojiRenderProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
33
+ emoji: ListEmoji;
34
+ children: React.ReactNode;
35
+ };
36
+
37
+ /**
38
+ * Props for a custom category header. Spread everything except `category`
39
+ * onto the header element; it stays sticky and measured.
40
+ */
41
+ export type CategoryHeaderRenderProps = React.HTMLAttributes<HTMLElement> & {
42
+ category: { id: string; name: string };
43
+ children: React.ReactNode;
44
+ };
45
+
46
+ export type ListComponents = {
47
+ Emoji?: React.ComponentType<EmojiRenderProps>;
48
+ CategoryHeader?: React.ComponentType<CategoryHeaderRenderProps>;
49
+ };
50
+
51
+ const NO_COMPONENTS: ListComponents = {};
52
+
53
+ export const ListComponentsContext =
54
+ /* @__PURE__ */ React.createContext<ListComponents>(NO_COMPONENTS);
55
+
56
+ export function useListComponents(): ListComponents {
57
+ return React.useContext(ListComponentsContext);
58
+ }
59
+
60
+ export function emojiRenderInfo(
61
+ emoji: DataEmoji,
62
+ unified: string,
63
+ emojiStyle: EmojiStyleValue,
64
+ getEmojiUrl: (unified: string, style: EmojiStyleValue) => string,
65
+ ): Omit<ListEmoji, 'isActive'> {
66
+ const isCustom = isCustomEmoji(emoji);
67
+ return {
68
+ unified,
69
+ names: emojiNames(emoji),
70
+ emoji: isCustom ? unified : parseNativeEmoji(unified),
71
+ isCustom,
72
+ imageUrl: isCustom
73
+ ? emoji.imgUrl
74
+ : emojiStyle === EmojiStyle.NATIVE
75
+ ? undefined
76
+ : getEmojiUrl(unified, emojiStyle),
77
+ hasVariations: emojiHasVariations(emoji),
78
+ };
79
+ }
@@ -8,37 +8,43 @@ export function ElementRefContextProvider({
8
8
  }: {
9
9
  children: React.ReactNode;
10
10
  }) {
11
- const PickerMainRef = React.useRef<HTMLElement>(null);
12
- const AnchoredEmojiRef = React.useRef<HTMLElement>(null);
13
- const BodyRef = React.useRef<HTMLDivElement>(null);
14
- const EmojiListRef = React.useRef<HTMLUListElement>(null);
15
- const SearchInputRef = React.useRef<HTMLInputElement>(null);
16
- const SkinTonePickerRef = React.useRef<HTMLDivElement>(null);
17
- const CategoryNavigationRef = React.useRef<HTMLDivElement>(null);
18
- const VariationPickerRef = React.useRef<HTMLDivElement>(null);
19
- const ReactionsRef = React.useRef<HTMLUListElement>(null);
20
-
11
+ const [refs] = React.useState(createElementRefs);
21
12
  return (
22
- <ElementRefContext.Provider
23
- value={{
24
- AnchoredEmojiRef,
25
- BodyRef,
26
- EmojiListRef,
27
- CategoryNavigationRef,
28
- PickerMainRef,
29
- SearchInputRef,
30
- SkinTonePickerRef,
31
- VariationPickerRef,
32
- ReactionsRef,
33
- }}
34
- >
13
+ <ElementRefContext.Provider value={refs}>
35
14
  {children}
36
15
  </ElementRefContext.Provider>
37
16
  );
38
17
  }
39
18
 
40
19
  export type ElementRef<E extends HTMLElement = HTMLElement> =
41
- React.MutableRefObject<E | null>;
20
+ React.MutableRefObject<E | null> & {
21
+ subscribe?: (listener: () => void) => () => void;
22
+ };
23
+
24
+ // Observe attachment without rerendering ref consumers. Root services follow
25
+ // conditional parts, native element replacements and remounts.
26
+ function createElementRef<E extends HTMLElement>(): ElementRef<E> {
27
+ let current: E | null = null;
28
+ const listeners = new Set<() => void>();
29
+ const ref = {} as ElementRef<E>;
30
+ Object.defineProperty(ref, 'current', {
31
+ configurable: false,
32
+ enumerable: true,
33
+ get: () => current,
34
+ set: (element: E | null) => {
35
+ if (element === current) return;
36
+ current = element;
37
+ listeners.forEach((listener) => listener());
38
+ },
39
+ });
40
+ ref.subscribe = (listener: () => void) => {
41
+ listeners.add(listener);
42
+ return () => {
43
+ listeners.delete(listener);
44
+ };
45
+ };
46
+ return ref;
47
+ }
42
48
 
43
49
  type ElementRefs = {
44
50
  PickerMainRef: ElementRef;
@@ -52,17 +58,22 @@ type ElementRefs = {
52
58
  ReactionsRef: ElementRef<HTMLUListElement>;
53
59
  };
54
60
 
55
- const ElementRefContext = React.createContext<ElementRefs>({
56
- AnchoredEmojiRef: React.createRef(),
57
- BodyRef: React.createRef(),
58
- CategoryNavigationRef: React.createRef(),
59
- EmojiListRef: React.createRef(),
60
- PickerMainRef: React.createRef(),
61
- SearchInputRef: React.createRef(),
62
- SkinTonePickerRef: React.createRef(),
63
- VariationPickerRef: React.createRef(),
64
- ReactionsRef: React.createRef(),
65
- });
61
+ function createElementRefs(): ElementRefs {
62
+ return {
63
+ PickerMainRef: createElementRef(),
64
+ AnchoredEmojiRef: createElementRef(),
65
+ BodyRef: createElementRef<HTMLDivElement>(),
66
+ EmojiListRef: createElementRef<HTMLUListElement>(),
67
+ SearchInputRef: createElementRef<HTMLInputElement>(),
68
+ SkinTonePickerRef: createElementRef<HTMLDivElement>(),
69
+ CategoryNavigationRef: createElementRef<HTMLDivElement>(),
70
+ VariationPickerRef: createElementRef<HTMLDivElement>(),
71
+ ReactionsRef: createElementRef<HTMLUListElement>(),
72
+ };
73
+ }
74
+
75
+ const ElementRefContext =
76
+ /* @__PURE__ */ React.createContext<ElementRefs>(createElementRefs());
66
77
 
67
78
  function useElementRef() {
68
79
  return React.useContext(ElementRefContext);
@@ -14,59 +14,74 @@ type Props = PickerConfig &
14
14
  }>;
15
15
 
16
16
  const ConfigContext =
17
- React.createContext<PickerConfigInternal>(basePickerConfig());
17
+ /* @__PURE__ */ React.createContext<PickerConfigInternal>(basePickerConfig());
18
+
19
+ type SearchSlice = {
20
+ searchValue: string | undefined;
21
+ defaultSearchValue: string | undefined;
22
+ };
23
+
24
+ const SearchConfigContext = /* @__PURE__ */ React.createContext<SearchSlice>({
25
+ searchValue: undefined,
26
+ defaultSearchValue: undefined,
27
+ });
18
28
 
19
29
  export function PickerConfigProvider({ children, ...config }: Props) {
20
30
  const mergedConfig = useSetConfig(config);
31
+ // Hot per-keystroke values bypass the merged config: their identity
32
+ // changes only when the values change, so typing never rebuilds or
33
+ // rebroadcasts the merged configuration.
34
+ const searchSlice = React.useMemo<SearchSlice>(
35
+ () => ({
36
+ searchValue: config.searchValue,
37
+ defaultSearchValue: config.defaultSearchValue,
38
+ }),
39
+ [config.searchValue, config.defaultSearchValue],
40
+ );
21
41
 
22
42
  return (
23
43
  <ConfigContext.Provider value={mergedConfig}>
24
- {children}
44
+ <SearchConfigContext.Provider value={searchSlice}>
45
+ {children}
46
+ </SearchConfigContext.Provider>
25
47
  </ConfigContext.Provider>
26
48
  );
27
49
  }
28
50
 
51
+ export function useSearchSliceConfig(): SearchSlice {
52
+ return React.useContext(SearchConfigContext);
53
+ }
54
+
29
55
  export function useSetConfig(config: PickerConfig) {
30
- const [mergedConfig, setMergedConfig] = React.useState(() =>
31
- mergeConfig(config),
32
- );
56
+ const cache = React.useRef<{
57
+ inputs: PickerConfig;
58
+ merged: PickerConfigInternal;
59
+ } | null>(null);
33
60
 
34
- React.useEffect(() => {
35
- if (compareConfig(mergedConfig, config)) {
36
- return;
37
- }
38
- setMergedConfig(mergeConfig(config));
39
- // not gonna...
40
- // eslint-disable-next-line react-hooks/exhaustive-deps
41
- }, [
42
- // New references rebuild merged categories and data even at equal
43
- // length; compareConfig above still gates no-op updates so inline
44
- // literals don't loop.
45
- config.categories,
46
- config.customEmojis,
47
- config.open,
48
- config.emojiVersion,
49
- config.reactionsDefaultOpen,
50
- config.searchPlaceHolder,
51
- config.searchPlaceholder,
52
- config.searchClearButtonLabel,
53
- config.defaultSkinTone,
54
- config.skinTonesDisabled,
55
- config.autoFocusSearch,
56
- config.emojiStyle,
57
- config.theme,
58
- config.suggestedEmojisMode,
59
- config.lazyLoadEmojis,
60
- config.className,
61
- config.height,
62
- config.width,
63
- config.searchDisabled,
64
- config.skinTonePickerLocation,
65
- config.allowExpandReactions,
66
- config.emojiData,
67
- ]);
61
+ // The search slice travels separately (see above); the merged config
62
+ // must not rebuild when only it changes.
63
+ const {
64
+ searchValue: _searchValue,
65
+ defaultSearchValue: _defaultSearchValue,
66
+ ...mainInputs
67
+ } = config;
68
+ void _searchValue;
69
+ void _defaultSearchValue;
68
70
 
69
- return mergedConfig;
71
+ // Derived during render with a content comparison, not settled in a
72
+ // trailing effect: consumers observe prop changes in the same commit,
73
+ // with no extra render pass and no cycle of lag. The derivation is
74
+ // idempotent (same inputs always rebuild identically), so a discarded
75
+ // concurrent render simply recomputes on the next pass. Inline
76
+ // literals with equal contents still reuse the cached merge via the
77
+ // structural comparison, as before.
78
+ const cached = cache.current;
79
+ if (!cached || !compareConfig(cached.inputs, mainInputs)) {
80
+ const merged = mergeConfig(mainInputs);
81
+ cache.current = { inputs: mainInputs, merged };
82
+ return merged;
83
+ }
84
+ return cached.merged;
70
85
  }
71
86
 
72
87
  export function usePickerConfig() {