Преглед на файлове

Feature: SelectBox is completed.

lfabl преди 1 месец
родител
ревизия
296ea670f3

+ 170 - 7
example/src/pages/home/index.tsx

@@ -56,6 +56,126 @@ const X = [
         p: "yasfa33",
         n: 95
     },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
+    {
+        t: "x vmönöpwoı6-pğfş -*235*çda",
+        p: "ydfasdfasf",
+        n: 96
+    },
     {
         t: "x vmönöpwoı6-pğfş -*235*çda",
         p: "ydfasdfasf",
@@ -103,6 +223,9 @@ const Home = () => {
             title="Deneme Box"
             isRequired={true}
             data={X}
+            onMoreLoad={(props) => {
+                console.log("GELMİŞEEEE:", props);
+            }}
         />
         <CheckBox
             isChecked={isCheckboxActive}
@@ -121,7 +244,6 @@ const Home = () => {
             onPress={() => {
                 navigation.navigate("TestSubPage");
             }}
-            type="success"
             title="Open Test Sub Page"
             variant="filled"
             spreadBehaviour="stretch"
@@ -158,12 +280,53 @@ const Home = () => {
                 }}
                 title="Git."
             />
-            <View
-                style={{
-                    backgroundColor: "red",
-                    height: 2400
-                }}
-            />
+            {[
+                0,
+                1,
+                2,
+                3,
+                4,
+                5,
+                6,
+                7,
+                8,
+                9,
+                10,
+                11,
+                12,
+                13,
+                14,
+                15,
+                16,
+                17,
+                18,
+                19,
+                20,
+                21,
+                22,
+                23,
+                24,
+                25,
+                26,
+                27,
+                28,
+                29,
+                30,
+                31,
+                32,
+                33,
+                34,
+                35
+            ].map((it) => {
+                return <View
+                    key={`fds-${it}`}
+                    style={{
+                        backgroundColor: `rgb(${it * 10}, ${it > 30 ? it * 5 : "0"}, ${it > 20 ? it * 4 : "0"})`,
+                        height: 150
+                    }}
+                />;
+            })}
+            <Text>Deneme 123</Text>
             <Text>Deneme 123</Text>
             <Text>Deneme 123</Text>
             <Text>Deneme 123</Text>

+ 75 - 2
src/components/bottomSheet/index.tsx

@@ -11,6 +11,7 @@ import {
     PanResponder,
     ScrollView,
     Animated,
+    Easing,
     View
 } from "react-native";
 import type IBottomSheetProps from "./type";
@@ -46,6 +47,7 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
     isWrapSafeAreaContext = true,
     backgroundColor = "default",
     isWorkAsFullScreen = false,
+    scrollEndThreshold = 0.85,
     isWorkWithPortal = true,
     isCloseOnOverlay = true,
     handleContainerSpacing,
@@ -58,6 +60,7 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
     onOverlayPressed,
     scrollViewProps,
     scrollViewStyle,
+    onScrollEnd,
     customTheme,
     modalProps,
     snapPoint,
@@ -267,6 +270,20 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
         };
     }, []);
 
+    const checkScrollThreshold = () => {
+        if (!onScrollEnd) return;
+
+        const maxS = Math.max(0, scrollViewContentHeight.current - scrollViewLayoutHeight.current);
+
+        if (maxS <= 0) return;
+
+        const ratio = scrollOffset.current / maxS;
+
+        if (ratio >= scrollEndThreshold) {
+            onScrollEnd();
+        }
+    };
+
     const openAnimation = () => {
         resetState();
 
@@ -345,7 +362,21 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
     const panResponder = useRef(
         PanResponder.create({
             onStartShouldSetPanResponder: () => false,
-            onMoveShouldSetPanResponderCapture: () => isCanSwipeRef.current ? true : false,
+            onMoveShouldSetPanResponderCapture: (_, gestureState) => {
+                const {
+                    dy
+                } = gestureState;
+
+                if(!isCanSwipeRef.current) {
+                    return false;
+                }
+
+                if(Math.abs(dy) < 20) {
+                    return false;
+                }
+
+                return true;
+            },
             onPanResponderGrant: (evt) => {
                 if(!isCanSwipeRef.current) return;
 
@@ -512,6 +543,41 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
                 const isFromTopArea = gestureStartY.current < TOP_GRAB_AREA;
 
                 if (isAtTavan && hasScroll && !isAtTop && !isFromTopArea) {
+                    const velocity = gestureState.vy;
+
+                    if (Math.abs(velocity) > 0.1) {
+                        const momentum = velocity * -350;
+
+                        const maxS = Math.max(0, scrollViewContentHeight.current - scrollViewLayoutHeight.current);
+
+                        const targetOffset = Math.max(0, Math.min(scrollOffset.current + momentum, maxS));
+
+                        const scrollAnim = new Animated.Value(scrollOffset.current);
+
+                        scrollAnim.addListener(({
+                            value
+                        }) => {
+                            scrollViewRef.current?.scrollTo({
+                                y: value,
+                                animated: false
+                            });
+                            scrollOffset.current = value;
+                        });
+
+                        Animated.timing(scrollAnim, {
+                            duration: Math.min(Math.abs(momentum) * 2, 600),
+                            easing: Easing.out(Easing.quad),
+                            useNativeDriver: false,
+                            toValue: targetOffset
+                        }).start(() => {
+                            scrollAnim.removeAllListeners();
+
+                            checkScrollThreshold();
+                        });
+                    } else {
+                        checkScrollThreshold();
+                    }
+
                     return;
                 }
 
@@ -535,7 +601,7 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
                 const isFastSwipeDown = gestureState.vy > 0.5;
                 const isFastSwipeUp = gestureState.vy < -0.5;
 
-                if (currentT <= 0.5) {
+                if (currentT <= Math.max(pivot * 0.2, 60)) {
                     let toValue = pivot;
 
                     if (isFastSwipeUp && isCanFullScreenOnSwipeRef.current) {
@@ -565,6 +631,13 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
                         friction: 10,
                         tension: 40
                     }).start();
+
+                    Animated.spring(animatedTranslateY, {
+                        useNativeDriver: false,
+                        toValue: 0,
+                        friction: 10,
+                        tension: 40
+                    }).start();
                 } else {
                     let toValueT = 0;
                     let isClosing = false;

+ 2 - 0
src/components/bottomSheet/type.ts

@@ -27,8 +27,10 @@ interface IBottomSheetProps {
     renderBottom?: () => ReactNode;
     onOverlayPressed?: () => void;
     isWorkAsFullScreen?: boolean;
+    scrollEndThreshold?: number;
     isCloseOnOverlay?: boolean;
     isWorkWithPortal?: boolean;
+    onScrollEnd?: () => void;
     modalProps?: IModalProps;
     isSwipeClose?: boolean;
     isShowHandle?: boolean;

+ 25 - 7
src/components/selectBox/index.tsx

@@ -78,8 +78,10 @@ function SelectBox<T>({
     isRequired = false,
     isDisabled = false,
     onBlur: onBlurProp,
+    moreLoadThreshold,
     hintTextIconStyle,
     data: initialData,
+    selectSheetProps,
     variant = "text",
     type = "default",
     rightIconOnPress,
@@ -96,6 +98,7 @@ function SelectBox<T>({
     customTheme,
     placeholder,
     iconOnPress,
+    onMoreLoad,
     isOptional,
     renderItem,
     customKey,
@@ -188,7 +191,7 @@ function SelectBox<T>({
     const [
         isMoreLoading,
         setIsMoreLoading
-    ] = useState(false);
+    ] = useState(true);
 
     const [
         selectedItems,
@@ -205,9 +208,13 @@ function SelectBox<T>({
     useImperativeHandle(
         ref,
         () => ({
+            setIsMoreLoading: (e) => setIsMoreLoading(e),
+            setIsLoading: (e) => setIsLoading(e),
             updateSelections,
             cleanSelections,
             updateData,
+            selectAll,
+            cleanAll,
             cancel,
             focus,
             blur,
@@ -220,6 +227,15 @@ function SelectBox<T>({
         if(isActive) {
             if(onFocus) onFocus();
         } else {
+            if(!isWorkWithRealtime) {
+                setTempSelectedItems([]);
+            }
+
+            setSearchText("");
+            setSearchedData([]);
+
+            setIsMoreLoading(false);
+
             if(onBlur) onBlur();
         }
     }, [isActive]);
@@ -229,6 +245,7 @@ function SelectBox<T>({
             if(onSearch) {
                 const _searchedData = prepareDatas(onSearch({
                     selectedItems: mainSelectedItems,
+                    setIsMoreLoading,
                     setIsLoading,
                     searchText,
                     data
@@ -271,10 +288,6 @@ function SelectBox<T>({
     }
 
     const blur = () => {
-        if(!isWorkWithRealtime) {
-            setTempSelectedItems([]);
-        }
-
         setIsActive(false);
     };
 
@@ -312,7 +325,7 @@ function SelectBox<T>({
         }
 
         if(onChange) {
-            onChange([], data);
+            onChange([], data, setIsMoreLoading);
         }
     };
 
@@ -543,7 +556,7 @@ function SelectBox<T>({
                 }
 
                 if(onChange) {
-                    onChange([], data);
+                    onChange([], data, setIsMoreLoading);
                 }
             }}
         >
@@ -799,13 +812,17 @@ function SelectBox<T>({
             customLocalize={customSelectSheetLocalize}
             isWorkWithRealtime={isWorkWithRealtime}
             mainSelectedItems={mainSelectedItems}
+            moreLoadThreshold={moreLoadThreshold}
             isShowTools={isShowSelectSheetTools}
             customTheme={customSelectSheetTheme}
             isMultipleSelect={isMultipleSelect}
             renderOptionIcon={renderOptionIcon}
+            setIsMoreLoading={setIsMoreLoading}
+            bottomSheetProps={selectSheetProps}
             selectBoxKey={selectBoxKey.current}
             bottomSheetRef={bottomSheetRef}
             setSearchText={setSearchText}
+            isMoreLoading={isMoreLoading}
             searchedData={searchedData}
             isSearchable={isSearchable}
             keyExtractor={keyExtractor}
@@ -814,6 +831,7 @@ function SelectBox<T>({
             setIsActive={setIsActive}
             searchText={searchText}
             renderItem={renderItem}
+            onMoreLoad={onMoreLoad}
             maxChoice={maxChoice}
             minChoice={minChoice}
             isLoading={isLoading}

+ 29 - 1
src/components/selectBox/type.ts

@@ -9,10 +9,13 @@ import {
 import {
     type NCoreUIKitIcon
 } from "../../types";
+import type IBottomSheetProps from "../bottomSheet/type";
 
 export type ISelectBoxRef<T> = {
     updateData: (newData: Array<T>, newSelectedItems: Array<SelectedItem>) => void;
     updateSelections: (newSelectedItems: Array<SelectedItem>) => void;
+    setIsMoreLoading: (state: boolean) => void;
+    setIsLoading: (state: boolean) => void;
     cleanSelections: () => void;
     selectAll: () => void;
     cleanAll: () => void;
@@ -65,17 +68,29 @@ export type SelectedItem = {
 };
 
 interface ISelectBoxProps<T> {
-    onChange?: (selectedItems: Array<SelectedItem>, data: Array<T | T & SelectedItem | SelectedItem>) => void;
+    onChange?: (
+        selectedItems: Array<SelectedItem>,
+        data: Array<T | T & SelectedItem | SelectedItem>,
+        setIsMoreLoading: (state: boolean) => void
+    ) => 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>;
+        setIsMoreLoading: (state: boolean) => void;
         setIsLoading: (state: boolean) => void;
         selectedItems: Array<SelectedItem>;
         searchText: string;
     }) => Array<T | T & SelectedItem | SelectedItem>;
+    onMoreLoad?: (props: {
+        data: Array<T & SelectedItem | SelectedItem>;
+        setIsMoreLoading: (state: boolean) => void;
+        setIsLoading: (state: boolean) => void;
+        selectedItems: Array<SelectedItem>;
+        searchText: string;
+    }) => void;
     spreadBehaviour?: SelectBoxSpreadBehaviour;
     initialSelectedItems?: Array<SelectedItem>;
     hintTextContainerStyle?: ViewStyle;
@@ -85,6 +100,7 @@ interface ISelectBoxProps<T> {
     rightIconOnPress?: () => void;
     hintTextIcon?: NCoreUIKitIcon;
     isShowHintTextIcon?: boolean;
+    moreLoadThreshold?: number;
     renderOptionIcon?: (props: {
         item: T & SelectedItem | SelectedItem;
         index: number;
@@ -92,6 +108,7 @@ interface ISelectBoxProps<T> {
     renderItem?: (props: {
         onSelect: (selectedItem: SelectedItem) => void;
         data: Array<T & SelectedItem | SelectedItem>;
+        setIsMoreLoading: (state: boolean) => void;
         setIsLoading: (state: boolean) => void;
         selectedItems: Array<SelectedItem>;
         isSelected: boolean;
@@ -118,6 +135,17 @@ interface ISelectBoxProps<T> {
     customLocalize?: {
         activeLocale?: NCoreUIKit.LocaleKey;
     };
+    selectSheetProps?: Omit<
+        IBottomSheetProps,
+        "key" |
+        "customKey" |
+        "ref" |
+        "isAutoHeight" |
+        "isActive" |
+        "renderBottom" |
+        "renderHeader" |
+        "onClose"
+    >;
     isShowSelectSheetTools?: boolean;
     isWorkWithRealtime?: boolean;
     isMultipleSelect?: boolean;

+ 34 - 0
src/components/selectSheet/index.tsx

@@ -28,11 +28,15 @@ function SelectSheet<T>({
     isWorkWithRealtime,
     isShowTools = true,
     mainSelectedItems,
+    moreLoadThreshold,
     isMultipleSelect,
+    setIsMoreLoading,
     renderOptionIcon,
+    bottomSheetProps,
     bottomSheetRef,
     customLocalize,
     setSearchText,
+    isMoreLoading,
     selectBoxKey,
     setIsLoading,
     selectObject,
@@ -41,6 +45,7 @@ function SelectSheet<T>({
     isSearchable,
     customTheme,
     setIsActive,
+    onMoreLoad,
     renderItem,
     searchText,
     maxChoice,
@@ -65,6 +70,7 @@ function SelectSheet<T>({
     } = NCoreUIKitLocalize.useContext(customLocalize);
 
     const {
+        moreLoadingContainer: moreLoadingContainerDynamicStyle,
         checkIconContainer: checkIconContainerDynamicStyle,
         loadingContainer: loadingContainerDynamicStyle,
         contentContainer: contentContainerDynamicStyle,
@@ -114,6 +120,7 @@ function SelectSheet<T>({
                                 selectObject(sItem);
                             },
                             selectedItems: mainSelectedItems,
+                            setIsMoreLoading,
                             setIsLoading,
                             isSelected,
                             searchText,
@@ -199,6 +206,7 @@ function SelectSheet<T>({
                     </TouchableOpacity>;
                 })
             }
+            {renderMoreLoading()}
         </View>;
     };
 
@@ -312,12 +320,38 @@ function SelectSheet<T>({
         </View>;
     };
 
+    const renderMoreLoading = () => {
+        if(!isMoreLoading) {
+            return null;
+        }
+
+        return <View
+            style={[
+                stylesheet.moreLoadingContainer,
+                moreLoadingContainerDynamicStyle
+            ]}
+        >
+            <Loading/>
+        </View>;
+    };
+
     return <BottomSheet
+        {...bottomSheetProps}
+        scrollEndThreshold={moreLoadThreshold}
         key={`${selectBoxKey}-bottomsheet`}
         customKey={selectBoxKey}
         ref={bottomSheetRef}
         isAutoHeight={true}
         isActive={isActive}
+        onScrollEnd={() => {
+            if(onMoreLoad) onMoreLoad({
+                selectedItems: mainSelectedItems,
+                setIsMoreLoading,
+                setIsLoading,
+                searchText,
+                data
+            });
+        }}
         renderBottom={() => {
             return renderBottomSheetBottom();
         }}

+ 8 - 0
src/components/selectSheet/stylesheet.ts

@@ -38,6 +38,11 @@ const stylesheet = StyleSheet.create({
         justifyContent: "space-between",
         flexDirection: "row",
         alignItems: "center"
+    },
+    moreLoadingContainer: {
+        justifyContent: "center",
+        alignItems: "center",
+        width: "100%"
     }
 });
 
@@ -82,6 +87,9 @@ export const useStyles = ({
         } as Mutable<ViewStyle>,
         toolsContainer: {
             marginTop: spaces.spacingSm
+        } as Mutable<ViewStyle>,
+        moreLoadingContainer: {
+            padding: spaces.spacingSm
         } as Mutable<ViewStyle>
     };
 

+ 23 - 0
src/components/selectSheet/type.ts

@@ -10,6 +10,7 @@ import {
 import type {
     IBottomSheetRef
 } from "../bottomSheet/type";
+import type IBottomSheetProps from "../bottomSheet/type";
 
 export type SelectSheetDynamicStyleType = {
     radiuses: NCoreUIKit.ActivePalette["radiuses"];
@@ -30,6 +31,7 @@ interface ISelectSheetProps<T> {
     renderItem?: (props: {
         onSelect: (selectedItem: SelectedItem) => void;
         data: Array<T & SelectedItem | SelectedItem>;
+        setIsMoreLoading: (state: boolean) => void;
         setIsLoading: (state: boolean) => void;
         selectedItems: Array<SelectedItem>;
         isSelected: boolean;
@@ -47,12 +49,32 @@ interface ISelectSheetProps<T> {
     customLocalize?: {
         activeLocale?: NCoreUIKit.LocaleKey;
     };
+    onMoreLoad?: (props: {
+        data: Array<T & SelectedItem | SelectedItem>;
+        setIsMoreLoading: (state: boolean) => void;
+        setIsLoading: (state: boolean) => void;
+        selectedItems: Array<SelectedItem>;
+        searchText: string;
+    }) => void;
     setSearchText: Dispatch<SetStateAction<string>>;
     setIsLoading: Dispatch<SetStateAction<boolean>>;
     setIsActive: Dispatch<SetStateAction<boolean>>;
     data: Array<SelectedItem | (T & SelectedItem)>;
     bottomSheetRef: Ref<IBottomSheetRef> | null;
+    setIsMoreLoading: (state: boolean) => void;
     LoadingIconComponentProp?: NCoreUIKitIcon;
+    moreLoadThreshold?: number;
+    bottomSheetProps?: Omit<
+        IBottomSheetProps,
+        "key" |
+        "customKey" |
+        "ref" |
+        "isAutoHeight" |
+        "isActive" |
+        "renderBottom" |
+        "renderHeader" |
+        "onClose"
+    >;
     renderOptionIcon?: (props: {
         item: T & SelectedItem | SelectedItem;
         index: number;
@@ -60,6 +82,7 @@ interface ISelectSheetProps<T> {
     mainSelectedItems: Array<SelectedItem>;
     isWorkWithRealtime: boolean;
     isMultipleSelect?: boolean;
+    isMoreLoading: boolean;
     isSearchable?: boolean;
     isShowTools?: boolean;
     selectAll: () => void;