1- import React , { useCallback , useEffect , useMemo , useState } from 'react' ;
1+ import React , {
2+ CSSProperties ,
3+ MouseEventHandler ,
4+ useCallback ,
5+ useEffect ,
6+ useMemo ,
7+ useState ,
8+ } from 'react' ;
29import clsx from 'clsx' ;
310
411import { useComponentContext } from '../../context/ComponentContext' ;
512
613import { Item } from './Item' ;
714import { escapeRegExp } from '../Message/renderText' ;
8-
9- export const List = ( {
15+ import type { DefaultStreamChatGenerics } from '../../types' ;
16+ import type { CustomTrigger , UnknownType } from '../../types/types' ;
17+ import {
18+ SuggestionEmoji ,
19+ SuggestionItem ,
20+ SuggestionListProps ,
21+ SuggestionUser ,
22+ } from '../ChatAutoComplete' ;
23+
24+ export const List = <
25+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics ,
26+ V extends CustomTrigger = CustomTrigger ,
27+ EmojiData extends UnknownType = UnknownType ,
28+ > ( {
1029 className,
1130 component,
1231 currentTrigger,
@@ -21,67 +40,76 @@ export const List = ({
2140 SuggestionItem : PropSuggestionItem ,
2241 value : propValue ,
2342 values,
24- } ) => {
25- const { AutocompleteSuggestionItem } = useComponentContext ( 'SuggestionList' ) ;
43+ } : SuggestionListProps < StreamChatGenerics , V > ) => {
44+ const { AutocompleteSuggestionItem } =
45+ useComponentContext < StreamChatGenerics > ( 'SuggestionList' ) ;
2646 const SuggestionItem = PropSuggestionItem || AutocompleteSuggestionItem || Item ;
2747
28- const [ selectedItemIndex , setSelectedItemIndex ] = useState ( undefined ) ;
48+ const [ selectedItemIndex , setSelectedItemIndex ] = useState < number | undefined > (
49+ undefined ,
50+ ) ;
2951
30- const itemsRef = [ ] ;
52+ const itemsRef : HTMLElement [ ] = [ ] ;
3153
32- const isSelected = ( item ) =>
54+ const isSelected = ( item : SuggestionItem < StreamChatGenerics , EmojiData > ) =>
3355 selectedItemIndex === values . findIndex ( ( value ) => getId ( value ) === getId ( item ) ) ;
3456
35- const getId = ( item ) => {
57+ const getId = ( item : SuggestionItem < StreamChatGenerics , EmojiData > ) => {
3658 const textToReplace = getTextToReplace ( item ) ;
3759 if ( textToReplace . key ) {
3860 return textToReplace . key ;
3961 }
4062
41- if ( typeof item === 'string' || ! item . key ) {
63+ if ( typeof item === 'string' || ! ( item as SuggestionEmoji < EmojiData > ) . key ) {
4264 return textToReplace . text ;
4365 }
4466
45- return item . key ;
67+ return ( item as SuggestionEmoji < V > ) . key ;
4668 } ;
4769
4870 const findItemIndex = useCallback (
49- ( item ) =>
71+ ( item : SuggestionItem < StreamChatGenerics , V > ) =>
5072 values . findIndex ( ( value ) =>
51- value . id ? value . id === item . id : value . name === item . name ,
73+ value . id
74+ ? value . id === ( item as SuggestionUser < StreamChatGenerics > ) . id
75+ : value . name === item . name ,
5276 ) ,
5377 [ values ] ,
5478 ) ;
5579
56- const modifyText = ( value ) => {
80+ const modifyText = (
81+ value : SuggestionListProps < StreamChatGenerics , V > [ 'values' ] [ number ] ,
82+ ) => {
5783 if ( ! value ) return ;
5884
5985 onSelect ( getTextToReplace ( value ) ) ;
6086 if ( getSelectedItem ) getSelectedItem ( value ) ;
6187 } ;
6288
6389 const handleClick = useCallback (
64- ( e , item ) => {
90+ (
91+ e : React . MouseEvent < Element , MouseEvent > ,
92+ item : SuggestionItem < StreamChatGenerics , V > ,
93+ ) => {
6594 e ?. preventDefault ( ) ;
6695
6796 const index = findItemIndex ( item ) ;
6897
6998 modifyText ( values [ index ] ) ;
7099 } ,
71- // eslint-disable-next-line react-hooks/exhaustive-deps
72- [ modifyText , findItemIndex ] ,
100+ [ modifyText , findItemIndex , values ] ,
73101 ) ;
74102
75103 const selectItem = useCallback (
76- ( item ) => {
104+ ( item : SuggestionItem < StreamChatGenerics , V > ) => {
77105 const index = findItemIndex ( item ) ;
78106 setSelectedItemIndex ( index ) ;
79107 } ,
80108 [ findItemIndex ] ,
81109 ) ;
82110
83111 const handleKeyDown = useCallback (
84- ( event ) => {
112+ ( event : KeyboardEvent ) => {
85113 if ( event . key === 'ArrowUp' ) {
86114 setSelectedItemIndex ( ( prevSelected ) => {
87115 if ( prevSelected === undefined ) return 0 ;
@@ -104,7 +132,7 @@ export const List = ({
104132 ( event . key === 'Enter' || event . key === 'Tab' ) &&
105133 selectedItemIndex !== undefined
106134 ) {
107- handleClick ( event , values [ selectedItemIndex ] ) ;
135+ modifyText ( values [ selectedItemIndex ] ) ;
108136 }
109137
110138 return null ;
@@ -120,13 +148,13 @@ export const List = ({
120148
121149 useEffect ( ( ) => {
122150 if ( values ?. length ) selectItem ( values [ 0 ] ) ;
123- } , [ values ] ) ; // eslint-disable-line
151+ } , [ selectItem , values ] ) ;
124152
125153 const restructureItem = useCallback (
126- ( item ) => {
127- const matched = item . name || item . id ;
154+ ( item : SuggestionItem < StreamChatGenerics , V > ) => {
155+ const matched = item . name || ( item as SuggestionUser < StreamChatGenerics > ) . id ;
128156
129- const textBeforeCursor = propValue . slice ( 0 , selectionEnd ) ;
157+ const textBeforeCursor = ( propValue || '' ) . slice ( 0 , selectionEnd ) ;
130158 const triggerIndex = textBeforeCursor . lastIndexOf ( currentTrigger ) ;
131159 const editedPropValue = escapeRegExp ( textBeforeCursor . slice ( triggerIndex + 1 ) ) ;
132160
@@ -149,16 +177,17 @@ export const List = ({
149177 { restructuredValues . map ( ( item , i ) => (
150178 < SuggestionItem
151179 className = { itemClassName }
180+ // @ts -ignore
152181 component = { component }
153182 item = { item }
154- key = { getId ( item ) }
183+ key = { getId ( item ) . toString ( ) }
155184 onClickHandler = { handleClick }
156185 onSelectHandler = { selectItem }
157- ref = { ( ref ) => {
186+ ref = { ( ref : HTMLAnchorElement ) => {
158187 itemsRef [ i ] = ref ;
159188 } }
160189 selected = { isSelected ( item ) }
161- style = { itemStyle }
190+ style = { itemStyle as CSSProperties }
162191 value = { propValue }
163192 />
164193 ) ) }
0 commit comments