import { AnyRecord, IJSX, StyledComponentProps, useNestedStylesByKey } from '@codeleap/styles' import { FileInput } from '../FileInput' import { Icon } from '../Icon' import { Image } from '../Image' import { Pressable, View } from 'react-native' import { SortableItemProps, SortablePhoto, SortablePhotosProps, WithId } from './types' import { useSortablePhotos } from './useSortablePhotos' import { useStylesFor } from '../../hooks' import { MobileStyleRegistry } from '../../Registry' import { ActivityIndicator } from '../ActivityIndicator' import Sortable, { type SortableGridRenderItem } from 'react-native-sortables' import { GestureHandlerRootView } from 'react-native-gesture-handler' import { useCallback } from 'react' export * from './styles' export * from './types' const DefaultItem = (props: SortableItemProps) => { const { photo, styles, emptyIcon } = props return ( { !!photo?.filename ? : } ) } const defaultGetFilename = (file: string) => { if (!file) return null const filenameWithExtension = file?.split?.('/').pop() if (filenameWithExtension) { return filenameWithExtension?.split('.').slice(0, -1).join('.') } return new Date().toISOString() } /** * Must be wrapped in its own GestureHandlerRootView to avoid gesture conflicts with any * parent ScrollView or gesture handler; nesting GestureHandlerRootView is intentional here. */ export const SortablePhotos = (props: SortablePhotosProps) => { const allProps = { ...SortablePhotos.defaultProps, ...props, } const { numColumns, renderPhoto: RenderItem, gap, multiple, pickerConfig, emptyIcon, style, loading, ...rest } = allProps const styles = useStylesFor(SortablePhotos.styleRegistryName, style) const loaderStyles = useNestedStylesByKey('loader', styles) const { input, handlePressPhoto, numberPhotosMissing, enabledDragDrop, onChangePhotosOrder, data, } = useSortablePhotos(allProps) const fileInputPickerOptions = { ...SortablePhotos.defaultProps.pickerConfig, ...pickerConfig, multiple, maxFiles: numberPhotosMissing, } /** useCallback is required — Sortable.Grid re-renders every item when renderItem identity changes, causing visible flicker during drag. */ const renderItem: SortableGridRenderItem> = useCallback(({ item, index }) => ( handlePressPhoto(item, index)}> ), [handlePressPhoto]) if (loading) { return ( ) } return onChangePhotosOrder(data as unknown as WithId[])} /> } SortablePhotos.styleRegistryName = 'SortablePhotos' SortablePhotos.elements = ['wrapper', 'photo', 'loader'] SortablePhotos.rootElement = 'wrapper' SortablePhotos.withVariantTypes = (styles: S) => { return SortablePhotos as (props: StyledComponentProps, typeof styles>) => IJSX } SortablePhotos.defaultProps = { numPhotos: 9, numColumns: 3, renderPhoto: DefaultItem, multiple: true, gap: 8, emptyIcon: 'plus', modalTitle: 'Photos', modalBody: null, modalLibraryText: 'Choose from gallery', modalCameraText: 'Take a photo', modalDeleteText: 'Remove photo', getFilename: defaultGetFilename, pickerConfig: { cropping: true, showCropFrame: true, compressImageMaxHeight: 1700, compressImageMaxWidth: 1700, compressImageQuality: 0.8, }, } as Partial> MobileStyleRegistry.registerComponent(SortablePhotos)