import React, { useCallback, useEffect, useMemo, useState } from "react";
import Sortable from "react-native-sortables";
import { Text, View, ViewStyle } from "react-native";
import Animated, { useAnimatedRef } from "react-native-reanimated";
const DEFAULT_HEADERS: any[] = [];
const DEFAULT_SORTABLE_DATA: any[] = [];
const renderHeaderComponent = (component: any) => {
if (!component) return null;
if (React.isValidElement(component)) return component;
if (typeof component === "function") {
const HeaderComponent = component;
return ;
}
return null;
};
const SortableListHeader = ({
title,
style,
}: {
title?: string;
style?: ViewStyle;
}) => {
const displayTitle = typeof title === "string" ? title : String(title ?? "");
return (
{displayTitle ? {displayTitle} : null}
);
};
export type SortableListProps = {
scrollViewStyle?: ViewStyle;
contentContainerStyle?: ViewStyle;
itemStyle?: ViewStyle;
headerStyle?: ViewStyle;
columns?: number;
rowGap?: number;
columnGap?: number;
spacing?: number;
keyExtractor?: (item: any, index?: number) => string;
renderItem: ({
item,
index,
renderHandle,
}: {
item: any;
index: number;
renderHandle: (children: React.ReactElement) => React.ReactElement;
}) => React.ReactNode;
sortableData?: any[];
headers?: { index: number; title?: string; component: any }[];
onDragEnd?: (params: {
fromIndex?: number;
toIndex?: number;
from?: number;
to?: number;
data: any[];
}) => void;
};
const defaultKeyExtractor = (item, index) =>
`sortable-item-${item?.id ?? item?.title ?? index}`;
export const SortableList = ({
scrollViewStyle,
contentContainerStyle,
itemStyle,
headerStyle,
columns = 1,
rowGap = 0,
columnGap = 0,
keyExtractor = defaultKeyExtractor,
renderItem,
sortableData = DEFAULT_SORTABLE_DATA,
headers = DEFAULT_HEADERS,
onDragEnd,
}: SortableListProps) => {
const scrollableRef = useAnimatedRef();
const [localData, setLocalData] = useState(sortableData);
useEffect(() => {
setLocalData((localData) =>
localData !== sortableData ? sortableData : localData
);
}, [sortableData]);
const handleDragEnd = useCallback(
(params: any) => {
if (params?.data) {
setLocalData(params.data);
}
if (onDragEnd) {
onDragEnd(params);
}
},
[onDragEnd]
);
const _renderItem = useCallback(
({ item, index }) => (
{renderItem({
item,
index,
renderHandle: (children) => (
{children}
),
})}
),
[itemStyle, keyExtractor, renderItem]
);
const renderHeader = useMemo(
() =>
(headers || []).map((header, idx) => (
{header.title ? (
) : (
renderHeaderComponent(header.component)
)}
)),
[headers, headerStyle]
);
return (
{renderHeader}
);
};