import React, { useCallback } from 'react'
import { AnyRecord, AppIcon, IJSX, StyledComponentProps, useCompositionStyles } from '@codeleap/styles'
import { useStylesFor } from '../../hooks'
import { Text } from '../Text'
import { View } from '../View'
import { PlaceItem, PlacesAutocompleteProps } from './types'
import { MobileStyleRegistry } from '../../Registry'
import { TextInput } from '../TextInput'
import { List } from '../List'
import { Touchable } from '../Touchable'
import { EmptyPlaceholder } from '../EmptyPlaceholder'
import { ActivityIndicator } from '../ActivityIndicator'
import { usePlacesAutocompleteUtils } from '@codeleap/hooks'
export * from './styles'
export * from './types'
const DefaultPlaceRow: PlacesAutocompleteProps['renderPlaceRow'] = (props) => {
const { item, onPress, styles } = props
if (item?.content) {
return item?.content
}
const isLatLng = !!item?.formatted_address
const mainTitle = isLatLng ? item?.formatted_address : item?.description
return (
onPress(mainTitle, item)} debugName={`PlaceRow ${item?.place_id}`} style={styles.placeRowWrapper}>
)
}
export const PlacesAutocomplete = (props: PlacesAutocompleteProps) => {
const {
style,
itemRow,
data = [],
customData = [],
onPress,
onValueChange,
showClearIcon,
showEmptyPlaceholder,
clearIcon,
textInputProps,
listProps,
emptyPlaceholderProps,
placeRow = null,
renderPlaceRow: PlaceRow,
activityIndicatorProps,
debounce,
isLoading,
persistResultsOnBlur,
...rest
} = props
const [isFocused, setIsFocused] = React.useState(false)
const styles = useStylesFor(PlacesAutocomplete.styleRegistryName, style)
const compositionStyles = useCompositionStyles(['input', 'list', 'loader'], styles)
/** When the caller fully controls the input value via `textInputProps.value`, the internal debounce is disabled to avoid double-buffering the typed string. */
const hasCustomValue = !!textInputProps?.value
const {
handleChangeAddress,
handlePressAddress,
handleClearAddress,
address,
isTyping,
setIsTyping,
} = usePlacesAutocompleteUtils({
onValueChange,
onPress,
debounce: hasCustomValue ? null : 250
})
const _showEmptyPlaceholder = !!address && !isTyping && showEmptyPlaceholder && !isLoading
const showResults = isFocused || persistResultsOnBlur
const _showClearIcon = showClearIcon && !!address?.trim?.()
const rightIcon = _showClearIcon ? {
name: clearIcon,
onPress: handleClearAddress,
} : textInputProps?.rightIcon
const _data = customData?.length > 0 && address ? [...customData, ...data] : data
const renderItem = useCallback((props) => {
return (
placeRow ? placeRow :
)
}, [placeRow])
return (
{
setIsFocused(false)
}}
onFocus={() => {
setIsFocused(true)
}}
{...textInputProps}
value={hasCustomValue ? textInputProps?.value : address}
onValueChange={(value) => {
setIsTyping(true)
handleChangeAddress(value)
}}
rightIcon={rightIcon}
/>
{isTyping ? (
) : (
showResults ? (
: null
}
style={compositionStyles.list}
separators
{...listProps}
/>
) : null
)
}
)
}
PlacesAutocomplete.styleRegistryName = 'PlacesAutocomplete'
PlacesAutocomplete.elements = ['wrapper', 'input', 'list', 'loader', 'placeRow', 'loadingWrapper']
PlacesAutocomplete.withVariantTypes = (styles: S) => {
return PlacesAutocomplete as (props: StyledComponentProps) => IJSX
}
PlacesAutocomplete.defaultProps = {
showClearIcon: false,
showEmptyPlaceholder: true,
clearIcon: 'x' as AppIcon,
placeRowComponent: DefaultPlaceRow,
renderPlaceRow: DefaultPlaceRow,
debounce: 250,
}
MobileStyleRegistry.registerComponent(PlacesAutocomplete)