| 
									
										
										
										
											2023-01-03 11:55:46 -08:00
										 |  |  | // Copyright 2020 Signal Messenger, LLC
 | 
					
						
							| 
									
										
										
										
											2020-10-30 15:34:04 -05:00
										 |  |  | // SPDX-License-Identifier: AGPL-3.0-only
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-23 18:57:37 -05:00
										 |  |  | import * as React from 'react'; | 
					
						
							| 
									
										
										
										
											2020-05-05 15:49:34 -04:00
										 |  |  | import { convertShortName } from '../emoji/lib'; | 
					
						
							| 
									
										
										
										
											2021-10-26 14:15:33 -05:00
										 |  |  | import type { Props as EmojiPickerProps } from '../emoji/EmojiPicker'; | 
					
						
							| 
									
										
										
										
											2022-09-07 11:29:08 -07:00
										 |  |  | import { useDelayedRestoreFocus } from '../../hooks/useRestoreFocus'; | 
					
						
							| 
									
										
										
										
											2021-10-26 14:15:33 -05:00
										 |  |  | import type { LocalizerType } from '../../types/Util'; | 
					
						
							| 
									
										
										
										
											2021-09-13 12:04:45 -05:00
										 |  |  | import { | 
					
						
							|  |  |  |   ReactionPickerPicker, | 
					
						
							|  |  |  |   ReactionPickerPickerEmojiButton, | 
					
						
							|  |  |  |   ReactionPickerPickerMoreButton, | 
					
						
							|  |  |  |   ReactionPickerPickerStyle, | 
					
						
							|  |  |  | } from '../ReactionPickerPicker'; | 
					
						
							| 
									
										
										
										
											2021-09-09 11:29:01 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-05 15:49:34 -04:00
										 |  |  | export type RenderEmojiPickerProps = Pick<Props, 'onClose' | 'style'> & | 
					
						
							| 
									
										
										
										
											2021-09-09 15:53:26 -05:00
										 |  |  |   Pick< | 
					
						
							|  |  |  |     EmojiPickerProps, | 
					
						
							|  |  |  |     'onClickSettings' | 'onPickEmoji' | 'onSetSkinTone' | 
					
						
							|  |  |  |   > & { | 
					
						
							| 
									
										
										
										
											2020-05-05 15:49:34 -04:00
										 |  |  |     ref: React.Ref<HTMLDivElement>; | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2020-01-23 18:57:37 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | export type OwnProps = { | 
					
						
							| 
									
										
										
										
											2020-05-05 15:49:34 -04:00
										 |  |  |   i18n: LocalizerType; | 
					
						
							| 
									
										
										
										
											2020-01-23 18:57:37 -05:00
										 |  |  |   selected?: string; | 
					
						
							|  |  |  |   onClose?: () => unknown; | 
					
						
							|  |  |  |   onPick: (emoji: string) => unknown; | 
					
						
							| 
									
										
										
										
											2021-09-09 15:53:26 -05:00
										 |  |  |   onSetSkinTone: (tone: number) => unknown; | 
					
						
							| 
									
										
										
										
											2021-09-09 11:29:01 -05:00
										 |  |  |   openCustomizePreferredReactionsModal?: () => unknown; | 
					
						
							| 
									
										
										
										
											2022-12-21 16:07:02 -08:00
										 |  |  |   preferredReactionEmoji: ReadonlyArray<string>; | 
					
						
							| 
									
										
										
										
											2020-05-05 15:49:34 -04:00
										 |  |  |   renderEmojiPicker: (props: RenderEmojiPickerProps) => React.ReactElement; | 
					
						
							| 
									
										
										
										
											2020-01-23 18:57:37 -05:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export type Props = OwnProps & Pick<React.HTMLProps<HTMLDivElement>, 'style'>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export const ReactionPicker = React.forwardRef<HTMLDivElement, Props>( | 
					
						
							| 
									
										
										
										
											2022-11-17 16:45:19 -08:00
										 |  |  |   function ReactionPickerInner( | 
					
						
							| 
									
										
										
										
											2021-09-09 11:29:01 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |       i18n, | 
					
						
							|  |  |  |       onClose, | 
					
						
							|  |  |  |       onPick, | 
					
						
							| 
									
										
										
										
											2021-09-09 15:53:26 -05:00
										 |  |  |       onSetSkinTone, | 
					
						
							| 
									
										
										
										
											2021-09-09 11:29:01 -05:00
										 |  |  |       openCustomizePreferredReactionsModal, | 
					
						
							|  |  |  |       preferredReactionEmoji, | 
					
						
							|  |  |  |       renderEmojiPicker, | 
					
						
							|  |  |  |       selected, | 
					
						
							|  |  |  |       style, | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2020-10-02 13:05:09 -07:00
										 |  |  |     ref | 
					
						
							| 
									
										
										
										
											2022-11-17 16:45:19 -08:00
										 |  |  |   ) { | 
					
						
							| 
									
										
										
										
											2020-05-05 15:49:34 -04:00
										 |  |  |     const [pickingOther, setPickingOther] = React.useState(false); | 
					
						
							| 
									
										
										
										
											2020-01-23 18:57:37 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Handle escape key
 | 
					
						
							|  |  |  |     React.useEffect(() => { | 
					
						
							|  |  |  |       const handler = (e: KeyboardEvent) => { | 
					
						
							| 
									
										
										
										
											2022-08-22 16:31:35 -07:00
										 |  |  |         if (onClose && e.key === 'Escape' && !pickingOther) { | 
					
						
							| 
									
										
										
										
											2020-01-23 18:57:37 -05:00
										 |  |  |           onClose(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       document.addEventListener('keydown', handler); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return () => { | 
					
						
							|  |  |  |         document.removeEventListener('keydown', handler); | 
					
						
							|  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2022-08-22 16:31:35 -07:00
										 |  |  |     }, [onClose, pickingOther]); | 
					
						
							| 
									
										
										
										
											2020-01-23 18:57:37 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-05 15:49:34 -04:00
										 |  |  |     // Handle EmojiPicker::onPickEmoji
 | 
					
						
							|  |  |  |     const onPickEmoji: EmojiPickerProps['onPickEmoji'] = React.useCallback( | 
					
						
							| 
									
										
										
										
											2020-10-02 13:05:09 -07:00
										 |  |  |       ({ shortName, skinTone: pickedSkinTone }) => { | 
					
						
							|  |  |  |         onPick(convertShortName(shortName, pickedSkinTone)); | 
					
						
							| 
									
										
										
										
											2020-05-05 15:49:34 -04:00
										 |  |  |       }, | 
					
						
							|  |  |  |       [onPick] | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-07 16:30:58 -05:00
										 |  |  |     // Focus first button and restore focus on unmount
 | 
					
						
							| 
									
										
										
										
											2022-09-07 11:29:08 -07:00
										 |  |  |     const [focusRef] = useDelayedRestoreFocus(); | 
					
						
							| 
									
										
										
										
											2021-09-07 16:30:58 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (pickingOther) { | 
					
						
							| 
									
										
										
										
											2021-09-09 11:29:01 -05:00
										 |  |  |       return renderEmojiPicker({ | 
					
						
							| 
									
										
										
										
											2021-09-29 15:21:26 -05:00
										 |  |  |         onClickSettings: openCustomizePreferredReactionsModal, | 
					
						
							| 
									
										
										
										
											2021-09-09 11:29:01 -05:00
										 |  |  |         onClose, | 
					
						
							|  |  |  |         onPickEmoji, | 
					
						
							| 
									
										
										
										
											2021-09-09 15:53:26 -05:00
										 |  |  |         onSetSkinTone, | 
					
						
							| 
									
										
										
										
											2021-09-09 11:29:01 -05:00
										 |  |  |         ref, | 
					
						
							|  |  |  |         style, | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2021-09-07 16:30:58 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-09 18:47:30 -05:00
										 |  |  |     const otherSelected = | 
					
						
							|  |  |  |       selected && !preferredReactionEmoji.includes(selected); | 
					
						
							| 
									
										
										
										
											2020-05-05 15:49:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-07 16:30:58 -05:00
										 |  |  |     let moreButton: React.ReactNode; | 
					
						
							| 
									
										
										
										
											2021-09-13 12:04:45 -05:00
										 |  |  |     if (otherSelected) { | 
					
						
							| 
									
										
										
										
											2021-09-07 16:30:58 -05:00
										 |  |  |       moreButton = ( | 
					
						
							| 
									
										
										
										
											2021-09-13 12:04:45 -05:00
										 |  |  |         <ReactionPickerPickerEmojiButton | 
					
						
							| 
									
										
										
										
											2021-09-07 16:30:58 -05:00
										 |  |  |           emoji={selected} | 
					
						
							| 
									
										
										
										
											2021-09-13 12:04:45 -05:00
										 |  |  |           onClick={() => { | 
					
						
							| 
									
										
										
										
											2021-09-07 16:30:58 -05:00
										 |  |  |             onPick(selected); | 
					
						
							|  |  |  |           }} | 
					
						
							| 
									
										
										
										
											2021-09-13 12:04:45 -05:00
										 |  |  |           isSelected | 
					
						
							| 
									
										
										
										
											2021-09-07 16:30:58 -05:00
										 |  |  |           title={i18n('Reactions--remove')} | 
					
						
							|  |  |  |         /> | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       moreButton = ( | 
					
						
							| 
									
										
										
										
											2021-09-13 12:04:45 -05:00
										 |  |  |         <ReactionPickerPickerMoreButton | 
					
						
							|  |  |  |           i18n={i18n} | 
					
						
							|  |  |  |           onClick={() => { | 
					
						
							| 
									
										
										
										
											2021-09-07 16:30:58 -05:00
										 |  |  |             setPickingOther(true); | 
					
						
							|  |  |  |           }} | 
					
						
							| 
									
										
										
										
											2021-09-13 12:04:45 -05:00
										 |  |  |         /> | 
					
						
							| 
									
										
										
										
											2021-09-07 16:30:58 -05:00
										 |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-13 12:04:45 -05:00
										 |  |  |     // This logic is here to avoid selecting duplicate emoji.
 | 
					
						
							|  |  |  |     let hasSelectedSomething = false; | 
					
						
							| 
									
										
										
										
											2021-09-09 11:29:01 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-07 16:30:58 -05:00
										 |  |  |     return ( | 
					
						
							| 
									
										
										
										
											2021-09-13 12:04:45 -05:00
										 |  |  |       <ReactionPickerPicker | 
					
						
							|  |  |  |         isSomethingSelected={typeof selected === 'number'} | 
					
						
							|  |  |  |         pickerStyle={ReactionPickerPickerStyle.Picker} | 
					
						
							| 
									
										
										
										
											2021-09-09 11:29:01 -05:00
										 |  |  |         ref={ref} | 
					
						
							|  |  |  |         style={style} | 
					
						
							|  |  |  |       > | 
					
						
							| 
									
										
										
										
											2021-09-09 18:47:30 -05:00
										 |  |  |         {preferredReactionEmoji.map((emoji, index) => { | 
					
						
							| 
									
										
										
										
											2020-01-23 18:57:37 -05:00
										 |  |  |           const maybeFocusRef = index === 0 ? focusRef : undefined; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-13 12:04:45 -05:00
										 |  |  |           const isSelected = !hasSelectedSomething && emoji === selected; | 
					
						
							|  |  |  |           if (isSelected) { | 
					
						
							|  |  |  |             hasSelectedSomething = true; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-23 18:57:37 -05:00
										 |  |  |           return ( | 
					
						
							| 
									
										
										
										
											2021-09-13 12:04:45 -05:00
										 |  |  |             <ReactionPickerPickerEmojiButton | 
					
						
							| 
									
										
										
										
											2021-09-07 16:30:58 -05:00
										 |  |  |               emoji={emoji} | 
					
						
							| 
									
										
										
										
											2021-09-13 12:04:45 -05:00
										 |  |  |               isSelected={isSelected} | 
					
						
							|  |  |  |               // The index is the only thing that uniquely identifies the emoji, because
 | 
					
						
							|  |  |  |               //   there can be duplicates in the list.
 | 
					
						
							|  |  |  |               // eslint-disable-next-line react/no-array-index-key
 | 
					
						
							|  |  |  |               key={index} | 
					
						
							|  |  |  |               onClick={() => { | 
					
						
							| 
									
										
										
										
											2020-01-23 18:57:37 -05:00
										 |  |  |                 onPick(emoji); | 
					
						
							|  |  |  |               }} | 
					
						
							| 
									
										
										
										
											2021-09-07 16:30:58 -05:00
										 |  |  |               ref={maybeFocusRef} | 
					
						
							|  |  |  |             /> | 
					
						
							| 
									
										
										
										
											2020-01-23 18:57:37 -05:00
										 |  |  |           ); | 
					
						
							|  |  |  |         })} | 
					
						
							| 
									
										
										
										
											2021-09-07 16:30:58 -05:00
										 |  |  |         {moreButton} | 
					
						
							| 
									
										
										
										
											2021-09-13 12:04:45 -05:00
										 |  |  |       </ReactionPickerPicker> | 
					
						
							| 
									
										
										
										
											2020-01-23 18:57:37 -05:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | ); |