ソースを参照

Feature: SelectBox 85% completed.

lfabl 1 ヶ月 前
コミット
3cde3be3f0

+ 2 - 2
example/src/pages/home/index.tsx

@@ -54,9 +54,9 @@ const Home = () => {
             isShowSubTitle={true}
             initialSelectedItems={[{
                 __title: X[0]?.t as string,
-                __key: `${X[0]?.t}-0`,
-                __originalIndex: 0
+                __key: `${X[0]?.t}-0`
             }]}
+            isSearchable={true}
             title="Deneme Box"
             isRequired={true}
             data={X}

+ 149 - 30
src/components/selectBox/index.tsx

@@ -45,7 +45,9 @@ import {
     uuid
 } from "../../utils";
 import BottomSheet from "../bottomSheet";
+import TextInput from "../textInput";
 import Text from "../text";
+import Loading from "../loading";
 
 const SelectBoxTypeIcon: Record<Exclude<SelectBoxType, "default">, NCoreUIKitIcon> = {
     "question": BadgeQuestionMarkIcon,
@@ -60,12 +62,15 @@ function SelectBox<T>({
     hintTextIcon: HintTextIconProp,
     spreadBehaviour = "baseline",
     isShowHintTextIcon = false,
+    isWorkWithRealtime = true,
     icon: IconComponentProp,
     hintTextContainerStyle,
+    removeSelectValidation,
     isCleanEnabled = false,
     contentContainerStyle,
     subTitle = "Optional",
     initialSelectedItems,
+    isSearchable = false,
     onFocus: onFocusProp,
     isRequired = false,
     isDisabled = false,
@@ -76,6 +81,7 @@ function SelectBox<T>({
     type = "default",
     rightIconOnPress,
     renderOptionIcon,
+    selectValidation,
     rightIconStyle,
     isShowSubTitle,
     cleanIconStyle,
@@ -85,11 +91,12 @@ function SelectBox<T>({
     placeholder,
     iconOnPress,
     isOptional,
-    validation,
+    renderItem,
     customKey,
     iconStyle,
     onChange,
     hintText,
+    onSearch,
     style,
     title
 }: ISelectBoxProps<T>, ref: Ref<ISelectBoxRef<T>>) {
@@ -114,6 +121,7 @@ function SelectBox<T>({
 
     const {
         bottomSheetHeaderContainer: bottomSheetHeaderContainerDynamicStyle,
+        loadingContainer: loadingContainerDynamicStyle,
         contentContainer: contentContainerDynamicStyle,
         titleContainer: titleContainerDynamicStyle,
         itemContainer: itemContainerDynamicStyle,
@@ -168,7 +176,7 @@ function SelectBox<T>({
     const [
         isLoading,
         setIsLoading
-    ] = useState(false);
+    ] = useState(true);
 
     const [
         isMoreLoading,
@@ -180,6 +188,13 @@ function SelectBox<T>({
         setSelectedItems
     ] = useState<Array<SelectedItem>>(initialSelectedItems ?? []);
 
+    const [
+        tempSelectedItems,
+        setTempSelectedItems
+    ] = useState<Array<SelectedItem>>(initialSelectedItems ?? []);
+
+    const mainSelectedItems = isWorkWithRealtime ? selectedItems : tempSelectedItems;
+
     useImperativeHandle(
         ref,
         () => ({
@@ -201,13 +216,33 @@ function SelectBox<T>({
     }, [isActive]);
 
     useEffect(() => {
-        if(searchText && searchText.length) {
-
+        if(isSearchable && searchText && searchText.length) {
+            if(onSearch) {
+                const _searchedData = prepareDatas(onSearch({
+                    selectedItems: mainSelectedItems,
+                    setIsLoading,
+                    searchText,
+                    data
+                }) as Array<T & SelectedItem>, mainSelectedItems);
+
+                setSearchedData(_searchedData);
+            } else {
+                const _searchedData = prepareDatas(data.filter(dI => {
+                    return dI.__title.toLocaleLowerCase().includes(searchText.toLocaleLowerCase());
+                }) as Array<T & SelectedItem>, mainSelectedItems);
+
+                setSearchedData(_searchedData);
+            }
+        } else if(searchedData && searchedData.length) {
+            setSearchedData([]);
         }
-    }, [searchText]);
+    }, [
+        data,
+        searchText
+    ]);
 
     useEffect(() => {
-        const initData = prepareDatas(initialData, initialSelectedItems);
+        const initData = prepareDatas(initialData as Array<T & SelectedItem>, initialSelectedItems);
 
         setData(initData);
     }, []);
@@ -235,7 +270,11 @@ function SelectBox<T>({
     };
 
     const cleanSelections = () => {
-        setSelectedItems([]);
+        if(isWorkWithRealtime) {
+            setSelectedItems([]);
+        } else {
+            setTempSelectedItems([]);
+        }
 
         if(onChange) {
             onChange([], data);
@@ -246,24 +285,27 @@ function SelectBox<T>({
         const _newData = newData.map((bIItem, bIIndex) => {
             return {
                 ...bIItem,
-                __title: titleExtractor(bIItem, bIIndex),
-                __key: keyExtractor(bIItem, bIIndex)
+                __title: titleExtractor(bIItem as T & SelectedItem, bIIndex),
+                __key: keyExtractor(bIItem as T & SelectedItem, bIIndex)
             };
         });
 
         setData(_newData);
 
-        const _newSelectedItems = JSON.parse(JSON.stringify(newSelectedItems ? newSelectedItems : selectedItems)).map((sItem: SelectedItem) => {
+        const _newSelectedItems = JSON.parse(JSON.stringify(newSelectedItems ? newSelectedItems : mainSelectedItems)).map((sItem: SelectedItem) => {
             const originalDataIndex = _newData.findIndex(ssItem => ssItem.__key === sItem.__key);
 
             return {
-                ...sItem,
                 __title: _newData[originalDataIndex]?.__title,
                 __key: _newData[originalDataIndex]?.__key
             };
         });
 
-        setSelectedItems(_newSelectedItems);
+        if(isWorkWithRealtime) {
+            setSelectedItems(_newSelectedItems);
+        } else {
+            setTempSelectedItems(_newSelectedItems);
+        }
     };
 
     const updateSelections = (newSelectedItems: Array<SelectedItem>) => {
@@ -277,10 +319,14 @@ function SelectBox<T>({
             };
         });
 
-        setSelectedItems(_newSelectedItems);
+        if(isWorkWithRealtime) {
+            setSelectedItems(_newSelectedItems);
+        } else {
+            setTempSelectedItems(_newSelectedItems);
+        }
     };
 
-    const prepareDatas = (items: Array<T>, sItems?: Array<SelectedItem>) => {
+    const prepareDatas = (items: Array<T & SelectedItem>, sItems?: Array<SelectedItem>) => {
         const initData: Array<SelectedItem | T & SelectedItem> = [];
 
         if(sItems && sItems.length) {
@@ -308,19 +354,38 @@ function SelectBox<T>({
     };
 
     const selectObject = (selectedItem: T & SelectedItem | SelectedItem) => {
-        const isAlreadySelected = selectedItems.findIndex(sItem => sItem.__key === selectedItem.__key);
-        let _selectedItems = JSON.parse(JSON.stringify(selectedItems));
+        const isAlreadySelected = mainSelectedItems.findIndex(sItem => sItem.__key === selectedItem.__key);
+        let _selectedItems = JSON.parse(JSON.stringify(mainSelectedItems));
 
         if(isAlreadySelected !== -1) {
-            _selectedItems = _selectedItems.filter((sItem: SelectedItem) => sItem.__key !== selectedItem.__key);
+            if(removeSelectValidation) {
+                if(removeSelectValidation(selectedItem)) {
+                    _selectedItems = _selectedItems.filter((sItem: SelectedItem) => sItem.__key !== selectedItem.__key);
+                }
+            } else {
+                _selectedItems = _selectedItems.filter((sItem: SelectedItem) => sItem.__key !== selectedItem.__key);
+            }
         } else {
-            _selectedItems.push({
-                __title: selectedItem.__title,
-                __key: selectedItem.__key
-            });
+            if(selectValidation) {
+                if(selectValidation(selectedItem)) {
+                    _selectedItems.push({
+                        __title: selectedItem.__title,
+                        __key: selectedItem.__key
+                    });
+                }
+            } else {
+                _selectedItems.push({
+                    __title: selectedItem.__title,
+                    __key: selectedItem.__key
+                });
+            }
         }
 
-        setSelectedItems(_selectedItems);
+        if(isWorkWithRealtime) {
+            setSelectedItems(_selectedItems);
+        } else {
+            setTempSelectedItems(_selectedItems);
+        }
     };
 
     const onFocus = () => {
@@ -351,10 +416,14 @@ function SelectBox<T>({
                 cleanButtonDynamicStyle
             ]}
             onPress={() => {
-                setSelectedItems([]);
+                if(isWorkWithRealtime) {
+                    setSelectedItems([]);
+                } else {
+                    setTempSelectedItems([]);
+                }
 
                 if(onChange) {
-                    onChange([]);
+                    onChange([], data);
                 }
             }}
         >
@@ -572,15 +641,46 @@ function SelectBox<T>({
     };
 
     const renderBottomSheetContent = () => {
-        return data.map((item: T, index: number) => {
+        if(isLoading) {
+            return <View
+                style={[
+                    stylesheet.loadingContainer,
+                    loadingContainerDynamicStyle
+                ]}
+            >
+                <Loading/>
+            </View>;
+        }
+
+        return data.map((item: T & SelectedItem | SelectedItem, index: number) => {
+            const isSelected = mainSelectedItems.findIndex((sI: SelectedItem) => {
+                return sI.__key === item.__key;
+            }) !== -1;
+
+            if(renderItem) {
+                return renderItem({
+                    key: keyExtractor(item as T & SelectedItem, index),
+                    onSelect: (sItem) => {
+                        selectObject(sItem);
+                    },
+                    selectedItems: mainSelectedItems,
+                    setIsLoading,
+                    isSelected,
+                    searchText,
+                    index,
+                    item,
+                    data
+                });
+            }
+
             return <TouchableOpacity
-                key={keyExtractor(item, index)}
+                key={keyExtractor(item as T & SelectedItem, index)}
                 style={[
                     stylesheet.itemContainer,
                     itemContainerDynamicStyle
                 ]}
                 onPress={() => {
-                    selectObject();
+                    selectObject(item);
                 }}
             >
                 <View
@@ -592,10 +692,23 @@ function SelectBox<T>({
                         item,
                         index
                     }) : null}
-                    <Text>Geldi gül mevsimi</Text>
+                    <Text
+                        color={isSelected ? "onPrimary" : undefined}
+                    >{item.__title}</Text>
                 </View>
-                <View>
-                    <CheckIcon/>
+                <View
+                    style={[
+                        {
+                            height: 24 + spaces.spacingSm,
+                            width: 24 + spaces.spacingSm
+                        }
+                    ]}
+                >
+                    {isSelected ?
+                        <CheckIcon
+                            color={colors.content.icon.onPrimary}
+                            size={24}
+                        /> : null}
                 </View>
             </TouchableOpacity>;
         });
@@ -620,6 +733,12 @@ function SelectBox<T>({
                     >
                         {title}
                     </Text>
+                    {isSearchable ? <TextInput
+                        spreadBehaviour="stretch"
+                        onChangeText={(text: string) => {
+                            setSearchText(text);
+                        }}
+                    /> : null}
                 </View>;
             }}
         >

+ 9 - 1
src/components/selectBox/stylesheet.ts

@@ -114,7 +114,7 @@ const stylesheet = StyleSheet.create({
         minHeight: 20
     },
     bottomSheetHeaderContainer: {
-
+        width: "100%"
     },
     itemContainer: {
         flexDirection: "row",
@@ -123,6 +123,11 @@ const stylesheet = StyleSheet.create({
     itemContentContainer: {
         flex: 1
     },
+    loadingContainer: {
+        justifyContent: "center",
+        alignItems: "center",
+        flex: 1
+    },
     cleanButton: {
         justifyContent: "center",
         alignItems: "center",
@@ -207,6 +212,9 @@ export const useStyles = ({
         itemContainer: {
             padding: spaces.spacingSm
         } as Mutable<ViewStyle>,
+        loadingContainer: {
+            padding: spaces.spacingSm
+        } as Mutable<ViewStyle>,
         cleanButton: {
             marginLeft: spaces.spacingSm
         } as Mutable<ViewStyle>,

+ 21 - 6
src/components/selectBox/type.ts

@@ -60,17 +60,19 @@ export type SelectedItem = {
 };
 
 interface ISelectBoxProps<T> {
-    onChange?: (selectedItems: Array<SelectedItem>, data: Array<T>) => void;
-    titleExtractor: (item: T, index: number) => string;
+    onChange?: (selectedItems: Array<SelectedItem>, data: Array<T | T & SelectedItem | SelectedItem>) => void;
+    titleExtractor: (item: T & SelectedItem, index: number) => string;
+    keyExtractor: (item: T & SelectedItem, index: number) => string;
+    removeSelectValidation?: (selectedItem: SelectedItem) => boolean;
+    selectValidation?: (selectedItem: SelectedItem) => boolean;
     onSearch?: (props: {
         data: Array<T & SelectedItem | SelectedItem>;
+        setIsLoading: (state: boolean) => void;
         selectedItems: Array<SelectedItem>;
         searchText: string;
-    }) => void;
-    keyExtractor: (item: T, index: number) => string;
+    }) => Array<T | T & SelectedItem | SelectedItem>;
     spreadBehaviour?: SelectBoxSpreadBehaviour;
     initialSelectedItems?: Array<SelectedItem>;
-    validation?: (text: string) => boolean;
     hintTextContainerStyle?: ViewStyle;
     contentContainerStyle?: ViewStyle;
     hintTextIconStyle?: ViewStyle;
@@ -78,9 +80,21 @@ interface ISelectBoxProps<T> {
     hintTextIcon?: NCoreUIKitIcon;
     isShowHintTextIcon?: boolean;
     renderOptionIcon?: (props: {
+        item: T & SelectedItem | SelectedItem;
         index: number;
-        item: T;
     }) => ReactElement;
+    renderItem?: (props: {
+        onSelect: (selectedItem: SelectedItem) => void;
+        data: Array<T & SelectedItem | SelectedItem>;
+        setIsLoading: (state: boolean) => void;
+        selectedItems: Array<SelectedItem>;
+        isSelected: boolean;
+        searchText: string;
+        item: SelectedItem;
+        index: number;
+        key: string;
+    }) => ReactElement;
+    isWorkWithRealtime?: boolean;
     cleanIconStyle?: ViewStyle;
     rightIconStyle?: ViewStyle;
     rightIcon?: NCoreUIKitIcon;
@@ -89,6 +103,7 @@ interface ISelectBoxProps<T> {
     isCleanEnabled?: boolean;
     iconOnPress?: () => void;
     contentStyle?: ViewStyle;
+    isSearchable?: boolean;
     iconStyle?: ViewStyle;
     icon?: NCoreUIKitIcon;
     placeholder?: string;