فهرست منبع

Feature: SelectBox bottom sheet footer completed.

lfabl 1 ماه پیش
والد
کامیت
fa0c164e19

+ 1 - 1
example/src/index.tsx

@@ -7,7 +7,7 @@ import {
 } from "ncore-ui-kit-mobile";
 
 const NCoreUIKitBase = setupNCoreUIKit({
-    initialSelectedGapPropagation: "compact",
+    initialSelectedGapPropagation: "spacious",
     initialSelectedTheme: "dark"
 });
 

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

@@ -52,6 +52,7 @@ const Home = () => {
             subTitle="Deneme Subtitle"
             hintText="Test deneme"
             isShowSubTitle={true}
+            // isWorkWithRealtime={false}
             initialSelectedItems={[{
                 __title: X[0]?.t as string,
                 __key: `${X[0]?.t}-0`
@@ -72,6 +73,7 @@ const Home = () => {
             type="success"
             title="Open Test Sub Page"
             variant="filled"
+            spreadBehaviour="stretch"
         />
         <Button
             onPress={() => {

+ 3 - 3
src/assets/svg/loadingIcon/index.tsx

@@ -19,7 +19,7 @@ import {
 } from "react-native-svg";
 
 const SvgLoadingIcon = ({
-    color = "onPrimary",
+    color = "emphasized",
     customColor,
     size = 22,
     ...props
@@ -55,8 +55,8 @@ const SvgLoadingIcon = ({
             1
         ],
         outputRange: [
-            "360deg",
-            "0deg"
+            "0deg",
+            "-360deg"
         ]
     });
 

+ 4 - 3
src/components/bottomSheet/index.tsx

@@ -141,8 +141,8 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
     useImperativeHandle(
         ref,
         () => ({
-            close: () => {
-                closeAnimation();
+            close: (callback) => {
+                closeAnimation(undefined, callback);
             },
             open: () => {
                 setIsActive(true);
@@ -284,7 +284,7 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
         });
     };
 
-    const closeAnimation = (toValue?: number) => {
+    const closeAnimation = (toValue?: number, callback?: () => void) => {
         if(onClose) onClose();
 
         const currentSnapPoint = isWorkAsFullScreen
@@ -304,6 +304,7 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
                 setIsActive(false);
 
                 if(onClosed) onClosed();
+                if(callback) callback();
             }
         });
     };

+ 1 - 1
src/components/bottomSheet/type.ts

@@ -9,7 +9,7 @@ import type {
 import type IModalProps from "../modal/type";
 
 export interface IBottomSheetRef {
-    close: () => void;
+    close: (callback: () => void) => void;
     open: () => void;
 }
 

+ 4 - 4
src/components/button/stylesheet.ts

@@ -152,11 +152,10 @@ const stylesheet = StyleSheet.create({
         borderStyle: "solid",
         alignItems: "center",
         position: "relative",
-        userSelect: "none",
         display: "flex"
     },
     title: {
-        margin: "0 auto",
+        margin: "0",
     },
     loading: {},
     overlay: {
@@ -241,16 +240,17 @@ export const useStyles = ({
     }
 
     if (icon && !isLoading) {
-        styles.title.margin = "initial";
         styles.title.marginLeft = spaces.spacingSm;
+        styles.title.margin = "initial";
     }
 
     if (spreadBehaviour === "baseline") {
         styles.container.alignSelf = spreadBehaviour;
         styles.container.width = "auto";
     } else if (spreadBehaviour === "stretch") {
+        styles.container.alignSelf = spreadBehaviour;
         styles.container.justifyContent = "center";
-        // styles.container.alignSelf = spreadBehaviour; TODO: It was required but now is not. Why ?
+        styles.container.flexShrink = 1;
         styles.container.width = "100%";
     }
 

+ 2 - 2
src/components/loading/index.tsx

@@ -6,13 +6,14 @@ import stylesheet from "./stylesheet";
 import LoadingIcon from "../../assets/svg/loadingIcon";
 
 const Loading: FC<ILoadingProps> = ({
-    color = "primary" as keyof NCoreUIKit.IconContentColors,
+    color = "emphasized" as keyof NCoreUIKit.IconContentColors,
     customColor,
     size = 22,
     style,
     ...props
 }) => {
     return <LoadingIcon
+        {...props}
         customColor={customColor}
         color={color}
         size={size}
@@ -20,7 +21,6 @@ const Loading: FC<ILoadingProps> = ({
             stylesheet.container,
             style
         ]}
-        {...props}
     />;
 };
 export default Loading;

+ 178 - 81
src/components/selectBox/index.tsx

@@ -29,6 +29,9 @@ import {
     type INCoreUIKitIconProps,
     type NCoreUIKitIcon
 } from "../../types";
+import type {
+    IBottomSheetRef
+} from "../bottomSheet/type";
 import type ITextProps from "../text/type";
 import {
     CheckIcon
@@ -46,8 +49,9 @@ import {
 } from "../../utils";
 import BottomSheet from "../bottomSheet";
 import TextInput from "../textInput";
-import Text from "../text";
 import Loading from "../loading";
+import Button from "../button";
+import Text from "../text";
 
 const SelectBoxTypeIcon: Record<Exclude<SelectBoxType, "default">, NCoreUIKitIcon> = {
     "question": BadgeQuestionMarkIcon,
@@ -58,6 +62,7 @@ const SelectBoxTypeIcon: Record<Exclude<SelectBoxType, "default">, NCoreUIKitIco
 };
 
 function SelectBox<T>({
+    renderLoadingIcon : LoadingIconComponentProp,
     rightIcon: RightIconComponentProp,
     hintTextIcon: HintTextIconProp,
     spreadBehaviour = "baseline",
@@ -113,6 +118,8 @@ function SelectBox<T>({
         localize
     } = NCoreUIKitLocalize.useContext();
 
+    const bottomSheetRef = useRef<IBottomSheetRef>(null);
+
     const selectBoxKey = useRef(customKey ? customKey : uuid());
 
     const currentType = getSelectBoxType({
@@ -120,7 +127,13 @@ function SelectBox<T>({
     });
 
     const {
+        bottomSheetContentContainer: bottomSheetContentContainerDynamicStyle,
         bottomSheetHeaderContainer: bottomSheetHeaderContainerDynamicStyle,
+        bottomSheetBottomContainer: bottomSheetBottomContainerDynamicStyle,
+        bottomSheetCancelButton: bottomSheetCancelButtonDynamicStyle,
+        bottomSheetHeaderTitle: bottomSheetHeaderTitleDynamicStyle,
+        bottomSheetOkButton: bottomSheetOkButtonDynamicStyle,
+        checkIconContainer: checkIconContainerDynamicStyle,
         loadingContainer: loadingContainerDynamicStyle,
         contentContainer: contentContainerDynamicStyle,
         titleContainer: titleContainerDynamicStyle,
@@ -141,6 +154,7 @@ function SelectBox<T>({
         icon: IconComponentProp ? true : false,
         spreadBehaviour,
         inlineSpaces,
+        isSearchable,
         currentType,
         isDisabled,
         radiuses,
@@ -176,7 +190,7 @@ function SelectBox<T>({
     const [
         isLoading,
         setIsLoading
-    ] = useState(true);
+    ] = useState(false);
 
     const [
         isMoreLoading,
@@ -201,8 +215,10 @@ function SelectBox<T>({
             updateSelections,
             cleanSelections,
             updateData,
+            cancel,
             focus,
-            blur
+            blur,
+            ok
         }),
         []
     );
@@ -262,17 +278,43 @@ function SelectBox<T>({
     }
 
     const blur = () => {
+        if(!isWorkWithRealtime) {
+            setTempSelectedItems([]);
+        }
+
         setIsActive(false);
     };
 
     const focus = () => {
+        if(!isWorkWithRealtime) {
+            setTempSelectedItems(selectedItems);
+        }
+
         setIsActive(true);
     };
 
+    const cancel = () => {
+        if(!isWorkWithRealtime) {
+            bottomSheetRef.current?.close(() => {
+                blur();
+            });
+        }
+    };
+
+    const ok = () => {
+        if(!isWorkWithRealtime) {
+            setSelectedItems(tempSelectedItems);
+
+            bottomSheetRef.current?.close(() => {
+                blur();
+            });
+        }
+    };
+
     const cleanSelections = () => {
-        if(isWorkWithRealtime) {
-            setSelectedItems([]);
-        } else {
+        setSelectedItems([]);
+
+        if(!isWorkWithRealtime) {
             setTempSelectedItems([]);
         }
 
@@ -648,98 +690,153 @@ function SelectBox<T>({
                     loadingContainerDynamicStyle
                 ]}
             >
-                <Loading/>
+                {LoadingIconComponentProp ? <LoadingIconComponentProp/> : <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 <View
+            style={[
+                bottomSheetContentContainerDynamicStyle
+            ]}
+        >
+            {
+                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 as T & SelectedItem, index)}
+                        style={[
+                            stylesheet.itemContainer,
+                            itemContainerDynamicStyle
+                        ]}
+                        onPress={() => {
+                            selectObject(item);
+                        }}
+                    >
+                        <View
+                            style={[
+                                stylesheet.itemContentContainer
+                            ]}
+                        >
+                            {renderOptionIcon ? renderOptionIcon({
+                                item,
+                                index
+                            }) : null}
+                            <Text
+                                color={isSelected ? "emphasized" : undefined}
+                            >{item.__title}</Text>
+                        </View>
+                        <View
+                            style={[
+                                stylesheet.checkIconContainer,
+                                checkIconContainerDynamicStyle
+                            ]}
+                        >
+                            {isSelected ?
+                                <CheckIcon
+                                    color={colors.content.icon.emphasized}
+                                    size={24}
+                                /> : null}
+                        </View>
+                    </TouchableOpacity>;
+                })
             }
+        </View>;
+    };
 
-            return <TouchableOpacity
-                key={keyExtractor(item as T & SelectedItem, index)}
+    const renderBottomSheetHeader = () => {
+        return <View
+            style={[
+                stylesheet.bottomSheetHeaderContainer,
+                bottomSheetHeaderContainerDynamicStyle
+            ]}
+        >
+            <Text
+                variant="titleMediumSize"
                 style={[
-                    stylesheet.itemContainer,
-                    itemContainerDynamicStyle
+                    bottomSheetHeaderTitleDynamicStyle
                 ]}
+            >
+                {title}
+            </Text>
+            {isSearchable ? <TextInput
+                placeholder={localize("search")}
+                spreadBehaviour="stretch"
+                onChangeText={(text: string) => {
+                    setSearchText(text);
+                }}
+            /> : null}
+        </View>;
+    };
+
+    const renderBottomSheetBottom = () => {
+        if(isWorkWithRealtime) {
+            return null;
+        }
+
+        return <View
+            style={[
+                stylesheet.bottomSheetBottomContainer,
+                bottomSheetBottomContainerDynamicStyle
+            ]}
+        >
+            <Button
+                title={localize("cancel")}
+                spreadBehaviour="stretch"
+                variant="outline"
+                type="neutral"
                 onPress={() => {
-                    selectObject(item);
+                    cancel();
                 }}
-            >
-                <View
-                    style={[
-                        stylesheet.itemContentContainer
-                    ]}
-                >
-                    {renderOptionIcon ? renderOptionIcon({
-                        item,
-                        index
-                    }) : null}
-                    <Text
-                        color={isSelected ? "onPrimary" : undefined}
-                    >{item.__title}</Text>
-                </View>
-                <View
-                    style={[
-                        {
-                            height: 24 + spaces.spacingSm,
-                            width: 24 + spaces.spacingSm
-                        }
-                    ]}
-                >
-                    {isSelected ?
-                        <CheckIcon
-                            color={colors.content.icon.onPrimary}
-                            size={24}
-                        /> : null}
-                </View>
-            </TouchableOpacity>;
-        });
+                style={{
+                    ...bottomSheetCancelButtonDynamicStyle
+                }}
+            />
+            <Button
+                spreadBehaviour="stretch"
+                title={localize("ok")}
+                onPress={() => {
+                    ok();
+                }}
+                style={{
+                    ...bottomSheetOkButtonDynamicStyle
+                }}
+            />
+        </View>;
     };
 
     const renderBottomSheet = () => {
         return <BottomSheet
             customKey={selectBoxKey.current}
+            ref={bottomSheetRef}
+            isAutoHeight={true}
             isActive={isActive}
-            onClose={() => {
-                setIsActive(false);
+            renderBottom={() => {
+                return renderBottomSheetBottom();
             }}
             renderHeader={() => {
-                return <View
-                    style={[
-                        stylesheet.bottomSheetHeaderContainer,
-                        bottomSheetHeaderContainerDynamicStyle
-                    ]}
-                >
-                    <Text
-                        variant="titleMediumSize"
-                    >
-                        {title}
-                    </Text>
-                    {isSearchable ? <TextInput
-                        spreadBehaviour="stretch"
-                        onChangeText={(text: string) => {
-                            setSearchText(text);
-                        }}
-                    /> : null}
-                </View>;
+                return renderBottomSheetHeader();
+            }}
+            onClose={() => {
+                setIsActive(false);
             }}
         >
             {renderBottomSheetContent()}

+ 39 - 2
src/components/selectBox/stylesheet.ts

@@ -114,8 +114,13 @@ const stylesheet = StyleSheet.create({
         minHeight: 20
     },
     bottomSheetHeaderContainer: {
+        flexDirection: "column",
         width: "100%"
     },
+    bottomSheetBottomContainer: {
+        flexDirection: "row",
+        alignItems: "center"
+    },
     itemContainer: {
         flexDirection: "row",
         alignItems: "center"
@@ -123,6 +128,10 @@ const stylesheet = StyleSheet.create({
     itemContentContainer: {
         flex: 1
     },
+    checkIconContainer: {
+        justifyContent: "center",
+        alignItems: "center"
+    },
     loadingContainer: {
         justifyContent: "center",
         alignItems: "center",
@@ -176,6 +185,7 @@ const stylesheet = StyleSheet.create({
 
 export const useStyles = ({
     spreadBehaviour,
+    isSearchable,
     inlineSpaces,
     currentType,
     isDisabled,
@@ -206,14 +216,37 @@ export const useStyles = ({
         contentText: {
 
         } as Mutable<TextStyle>,
+        bottomSheetContentContainer: {
+            padding: spaces.spacingSm
+        } as Mutable<ViewStyle>,
         bottomSheetHeaderContainer: {
             padding: spaces.spacingSm
         } as Mutable<ViewStyle>,
-        itemContainer: {
+        bottomSheetHeaderTitle: {
+
+        } as Mutable<ViewStyle>,
+        bottomSheetBottomContainer: {
+            marginTop: spaces.spacingSm,
             padding: spaces.spacingSm
         } as Mutable<ViewStyle>,
+        bottomSheetCancelButton: {
+            marginRight: spaces.spacingSm
+        } as Mutable<ViewStyle>,
+        bottomSheetOkButton: {
+            marginLeft: spaces.spacingSm
+        } as Mutable<ViewStyle>,
+        itemContainer: {
+            backgroundColor: colors.content.container.mid,
+            paddingHorizontal: spaces.spacingMd,
+            paddingVertical: spaces.spacingSm,
+            borderRadius: radiuses.form
+        } as Mutable<ViewStyle>,
+        checkIconContainer: {
+            height: 24 + spaces.spacingSm,
+            width: 24 + spaces.spacingSm
+        } as Mutable<ViewStyle>,
         loadingContainer: {
-            padding: spaces.spacingSm
+            padding: spaces.spacingMd
         } as Mutable<ViewStyle>,
         cleanButton: {
             marginLeft: spaces.spacingSm
@@ -247,6 +280,10 @@ export const useStyles = ({
         } as Mutable<ViewStyle>
     };
 
+    if(isSearchable) {
+        styles.bottomSheetHeaderTitle.marginBottom = spaces.spacingSm;
+    }
+
     if(isDisabled) {
         const disableStyleType = styleType === "default" ? "neutral" : styleType;
 

+ 4 - 0
src/components/selectBox/type.ts

@@ -14,8 +14,10 @@ export type ISelectBoxRef<T> = {
     updateData: (newData: Array<T>, newSelectedItems: Array<SelectedItem>) => void;
     updateSelections: (newSelectedItems: Array<SelectedItem>) => void;
     cleanSelections: () => void;
+    cancel: () => void;
     focus: () => void;
     blur: () => void;
+    ok: () => void;
 };
 
 export type SelectBoxDynamicStyleType = {
@@ -26,6 +28,7 @@ export type SelectBoxDynamicStyleType = {
     colors: NCoreUIKit.ActivePalette["colors"];
     currentType: SelectBoxTypes;
     borders: NCoreUIKit.Borders;
+    isSearchable?: boolean;
     isDisabled?: boolean;
     type: SelectBoxType;
     title?: string;
@@ -74,6 +77,7 @@ interface ISelectBoxProps<T> {
     spreadBehaviour?: SelectBoxSpreadBehaviour;
     initialSelectedItems?: Array<SelectedItem>;
     hintTextContainerStyle?: ViewStyle;
+    renderLoadingIcon?: NCoreUIKitIcon;
     contentContainerStyle?: ViewStyle;
     hintTextIconStyle?: ViewStyle;
     rightIconOnPress?: () => void;

+ 1 - 1
src/components/textInput/index.tsx

@@ -429,7 +429,7 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
     const renderInput = () => {
         return <NativeTextInput
             {...props}
-            placeholderTextColor={currentType.placeholderColor}
+            placeholderTextColor={colors.content.text[currentType.placeholderColor]}
             secureTextEntry={variant === "hidden" && hideValue}
             underlineColorAndroid="rgba(255,255,255,0)"
             placeholder={placeholder}

+ 2 - 0
src/components/textInput/stylesheet.ts

@@ -259,7 +259,9 @@ export const useStyles = ({
     }
 
     if (spreadBehaviour === "stretch") {
+        styles.container.alignSelf = spreadBehaviour;
         styles.container.justifyContent = "center";
+        styles.container.flexShrink = 1;
         styles.container.width = "100%";
     }
 

+ 3 - 1
src/variants/locales/default.json

@@ -7,6 +7,7 @@
             "select-an-option": "Select an option",
             "is-optional": "Opsiyonel",
             "cancel": "İptal",
+            "search": "Ara",
             "ok": "Tamam"
         }
     },
@@ -15,9 +16,10 @@
         "isRTL": false,
         "translations": {
             "selected-options-with-count": "{{0}} seçim yapıldı",
-            "select-an-option": "Seçim yapın,",
+            "select-an-option": "Seçim yapın",
             "is-optional": "Optional",
             "cancel": "Cancel",
+            "search": "Search",
             "ok": "Okey"
         }
     }