Prechádzať zdrojové kódy

Feature: SnackBar system and component completed.

lfabl 1 mesiac pred
rodič
commit
bd904dcaa3

+ 11 - 4
example/src/pages/home/index.tsx

@@ -16,7 +16,8 @@ import {
     SelectBox,
     CheckBox,
     Button,
-    Text
+    Text,
+    NCoreUIKitSnackBar
 } from "ncore-ui-kit-mobile";
 import {
     useNavigation
@@ -265,7 +266,12 @@ const Home = () => {
             variant="filled"
             type="danger"
             onPress={() => {
-
+                NCoreUIKitSnackBar.open({
+                    title: "sdgdsgs",
+                    icon: ({
+                        color
+                    }) => <HomeIcon color={colors.content.icon[color ? color : "default"]}/>
+                });
             }}
         />
         <Button
@@ -276,7 +282,7 @@ const Home = () => {
                 NCoreUIKitToast.open({
                     title: "sdgfsdgsdafs sdlşlgkdfşiklh",
                     subTitle: "tr9uıdgfss 0dgklsd",
-                    isShowAction: false,
+                    isShowAction: true,
                     icon: ({
                         color
                     }) => <HomeIcon color={colors.content.icon[color ? color : "default"]}/>
@@ -307,7 +313,8 @@ const Home = () => {
                 type="warning"
                 onPress={() => {
                     NCoreUIKitToast.open({
-                        title: "sdgfsdgsdg"
+                        title: "sdgfsdgsdg",
+                        type: "danger"
                     });
                 }}
             />

+ 297 - 0
src/components/snackBar/index.tsx

@@ -0,0 +1,297 @@
+import {
+    useEffect,
+    useState,
+    type FC,
+    useRef
+} from "react";
+import {
+    TouchableWithoutFeedback,
+    Animated,
+    Easing,
+    View
+} from "react-native";
+import type ISnackBarProps from "./type";
+import stylesheet, {
+    getSnackBarType,
+    useStyles
+} from "./stylesheet";
+import {
+    NCoreUIKitTheme
+} from "../../core/hooks";
+import {
+    useSafeAreaInsets
+} from "react-native-safe-area-context";
+import {
+    X as XIcon
+} from "lucide-react-native";
+import {
+    Portal
+} from "../../helpers/portalize";
+import Button from "../button";
+import Text from "../text";
+import {
+    windowHeight
+} from "../../utils";
+
+const SnackBar: FC<ISnackBarProps> = ({
+    isCloseOnPressActionButton = true,
+    closeAnimationDelay = 350,
+    openAnimationDelay = 200,
+    contentContainerStyle,
+    autoCloseDelay = 5000,
+    isCloseOnPress = true,
+    isShowAction = true,
+    icon: CustomIcon,
+    type = "neutral",
+    customTheme,
+    onClosed,
+    subTitle,
+    children,
+    onPress,
+    action,
+    style,
+    title,
+    id
+}) => {
+    const {
+        radiuses,
+        colors,
+        spaces
+    } = NCoreUIKitTheme.useContext(customTheme);
+
+    const {
+        top
+    } = useSafeAreaInsets();
+
+    const [
+        isMeasured,
+        setIsMeasured
+    ] = useState(false);
+
+    const contentHeight = useRef<number>(windowHeight);
+
+    const transformAnim = useRef(new Animated.Value(-contentHeight.current + -top + -spaces.spacingSm)).current;
+    const opacityAnim = useRef(new Animated.Value(0)).current;
+
+    const currentType = getSnackBarType({
+        type
+    });
+
+    const {
+        contentContainer: contentContainerDynamicStyle,
+        containerObject: containerObjectDynamicStyle,
+        iconContainer: iconContainerDynamicStyle,
+        container: containerDynamicStyle,
+        subTitle: subTitleDynamicStyle,
+        action: actionDynamicStyle,
+        title: titleDynamicStyle
+    } = useStyles({
+        safeAreaTop: top,
+        currentType,
+        radiuses,
+        spaces,
+        colors,
+        type
+    });
+
+    useEffect(() => {
+        if(isMeasured) {
+            transformAnim.setValue(-contentHeight.current + -top + -spaces.spacingSm);
+
+            Animated.parallel([
+                Animated.timing(opacityAnim, {
+                    duration: openAnimationDelay,
+                    useNativeDriver: true,
+                    easing: Easing.linear,
+                    toValue: 1
+                }),
+                Animated.timing(transformAnim, {
+                    duration: openAnimationDelay,
+                    useNativeDriver: true,
+                    easing: Easing.linear,
+                    toValue: 0
+                })
+            ]).start();
+
+            setTimeout(() => {
+                closeAnimation();
+            }, autoCloseDelay);
+        }
+    }, [isMeasured]);
+
+    const closeAnimation = (_onClosed?: (props: {
+        id: string;
+    }) => void) => {
+        Animated.parallel([
+            Animated.timing(transformAnim, {
+                toValue: -contentHeight.current + -top + -spaces.spacingSm,
+                duration: closeAnimationDelay,
+                useNativeDriver: true,
+                easing: Easing.linear
+            }),
+            Animated.timing(opacityAnim, {
+                duration: closeAnimationDelay,
+                useNativeDriver: true,
+                easing: Easing.linear,
+                toValue: 0
+            })
+        ]).start(({
+            finished
+        }) => {
+            if(finished) {
+                if(onClosed) onClosed({
+                    id
+                });
+
+                if(_onClosed) _onClosed({
+                    id
+                });
+            }
+        });
+    };
+
+    const renderIcon = () => {
+        if(!CustomIcon) {
+            return null;
+        }
+
+        return <View
+            style={[
+                stylesheet.iconContainer,
+                iconContainerDynamicStyle
+            ]}
+        >
+            <CustomIcon
+                color="default"
+                size={18}
+            />
+        </View>;
+    };
+
+    const renderContent = () => {
+        return <View
+            style={[
+                contentContainerStyle,
+                stylesheet.contentContainer,
+                contentContainerDynamicStyle
+            ]}
+        >
+            <Text
+                numberOfLines={3}
+                style={{
+                    ...stylesheet.title,
+                    ...titleDynamicStyle
+                }}
+            >
+                {title}
+            </Text>
+            {
+                subTitle ?
+                    <Text
+                        variant="labelSmallSize"
+                        numberOfLines={2}
+                        color="low"
+                        style={{
+                            ...stylesheet.subTitle,
+                            ...subTitleDynamicStyle
+                        }}
+                    >
+                        {subTitle}
+                    </Text>
+                    :
+                    null
+            }
+        </View>;
+    };
+
+    const renderAction = () => {
+        if(!isShowAction) {
+            return null;
+        }
+
+        return <Button
+            title={action && action.title ? action.title : undefined}
+            isCustomPadding={true}
+            spreadBehaviour="free"
+            onPress={() => {
+                if(isCloseOnPressActionButton) closeAnimation();
+
+                if(action && action.onPress) action.onPress({
+                    closeAnimation: ({
+                        onClosed: _onClosed
+                    }) => closeAnimation(_onClosed)
+                });
+            }}
+            icon={({
+                color
+            }) => {
+                if(action?.title) {
+                    return null;
+                }
+
+                return <XIcon
+                    color={colors.content.icon[color ? color : "default"]}
+                    size={18}
+                />;
+            }}
+            style={{
+                ...action?.style,
+                ...actionDynamicStyle
+            }}
+            variant="ghost"
+            type="neutral"
+            size="small"
+        />;
+    };
+
+    const renderContainer = () => {
+        return <View
+            style={[
+                stylesheet.containerObject,
+                containerObjectDynamicStyle
+            ]}
+        >
+            {renderIcon()}
+            {renderContent()}
+            {renderAction()}
+        </View>;
+    };
+
+    return <Portal name="snack-bar-system">
+        <Animated.View
+            onLayout={(event) => {
+                const _contentHeight = event.nativeEvent.layout.height;
+
+                contentHeight.current = _contentHeight;
+
+                setIsMeasured(true);
+            }}
+            style={[
+                style,
+                stylesheet.container,
+                containerDynamicStyle,
+                {
+                    opacity: opacityAnim,
+                    transform: [{
+                        translateY: transformAnim
+                    }]
+                }
+            ]}
+        >
+            <TouchableWithoutFeedback
+                onPress={() => {
+                    if(onPress) onPress({
+                        id
+                    });
+
+                    if(isCloseOnPress) {
+                        closeAnimation();
+                    }
+                }}
+            >
+                {children ? children : renderContainer()}
+            </TouchableWithoutFeedback>
+        </Animated.View>
+    </Portal>;
+};
+export default SnackBar;

+ 152 - 0
src/components/snackBar/stylesheet.ts

@@ -0,0 +1,152 @@
+import {
+    type TextStyle,
+    type ViewStyle,
+    StyleSheet
+} from "react-native";
+import type {
+    SnackBarDynamicStyleType,
+    SnackBarTypeConstantType,
+    SnackBarTypes,
+    SnackBarType
+} from "./type";
+import type {
+    Mutable
+} from "../../types";
+import {
+    windowWidth
+} from "../../utils";
+
+export const SNACK_BAR_TYPE_STYLES: Record<
+    SnackBarType,
+    {
+        containerColor: keyof NCoreUIKit.ContainerContentColors;
+        subTitleColor: keyof NCoreUIKit.TextContentColors;
+        actionColor: keyof NCoreUIKit.TextContentColors;
+        titleColor: keyof NCoreUIKit.TextContentColors;
+        iconColor: keyof NCoreUIKit.IconContentColors;
+    }
+> = {
+    primary: {
+        actionColor: "onPrimary",
+        iconColor: "emphasized",
+        containerColor: "mid",
+        subTitleColor: "low",
+        titleColor: "mid"
+    },
+    danger: {
+        subTitleColor: "dangerLow",
+        containerColor: "danger",
+        actionColor: "danger",
+        titleColor: "danger",
+        iconColor: "danger"
+    },
+    success: {
+        subTitleColor: "successLow",
+        containerColor: "success",
+        actionColor: "success",
+        titleColor: "success",
+        iconColor: "success"
+    },
+    warning: {
+        subTitleColor: "warningLow",
+        containerColor: "warning",
+        actionColor: "warning",
+        titleColor: "warning",
+        iconColor: "warning"
+    },
+    info: {
+        subTitleColor: "infoLow",
+        containerColor: "info",
+        actionColor: "info",
+        titleColor: "info",
+        iconColor: "info"
+    },
+    neutral: {
+        containerColor: "mid",
+        subTitleColor: "low",
+        actionColor: "mid",
+        titleColor: "mid",
+        iconColor: "mid"
+    }
+};
+
+export const getSnackBarType = ({
+    type
+}: SnackBarTypeConstantType): SnackBarTypes => {
+    const currentType = SNACK_BAR_TYPE_STYLES[type];
+
+    return currentType;
+};
+
+const stylesheet = StyleSheet.create({
+    container: {
+        position: "absolute",
+        alignSelf: "center",
+        zIndex: 99998
+    },
+    containerObject: {
+        flexDirection: "row",
+        alignItems: "center"
+    },
+    contentContainer: {
+        justifyContent: "center",
+        alignItems: "flex-start",
+        flexDirection: "column",
+        flexShrink: 1,
+        flex: 1
+    },
+    iconContainer: {
+        justifyContent: "center",
+        alignItems: "center"
+    },
+    title: {
+        textAlign: "left"
+    },
+    subTitle: {
+        textAlign: "left"
+    }
+});
+
+export const useStyles = ({
+    safeAreaTop,
+    currentType,
+    radiuses,
+    colors,
+    spaces
+}: SnackBarDynamicStyleType) => {
+    const styles = {
+        container: {
+            backgroundColor: colors.content.container[currentType.containerColor],
+            width: windowWidth - (spaces.spacingMd * 2),
+            top: safeAreaTop + spaces.spacingSm,
+            borderRadius: radiuses.lg
+        } as Mutable<ViewStyle>,
+        containerObject: {
+            paddingHorizontal: spaces.spacingLg,
+            paddingVertical: spaces.spacingMd
+        } as Mutable<ViewStyle>,
+        contentContainer: {
+
+        } as Mutable<ViewStyle>,
+        title: {
+
+        } as Mutable<TextStyle>,
+        subTitle: {
+            marginTop: spaces.spacingXs
+        } as Mutable<TextStyle>,
+        iconContainer: {
+            paddingRight: spaces.spacingSm,
+            marginRight: spaces.spacingSm
+        } as Mutable<ViewStyle>,
+        action: {
+            paddingBottom: spaces.spacingSm,
+            paddingRight: spaces.spacingSm,
+            paddingLeft: spaces.spacingMd,
+            paddingTop: spaces.spacingSm,
+            marginLeft: spaces.spacingMd
+        } as Mutable<ViewStyle>
+    };
+
+    return styles;
+};
+export default stylesheet;

+ 82 - 0
src/components/snackBar/type.ts

@@ -0,0 +1,82 @@
+import {
+    type ReactNode
+} from "react";
+import {
+    type StyleProp,
+    type ViewStyle
+} from "react-native";
+import type {
+    NCoreUIKitIcon
+} from "../../types";
+
+export type SnackBarDynamicStyleType = {
+    radiuses: NCoreUIKit.ActivePalette["radiuses"];
+    spaces: NCoreUIKit.ActivePalette["spaces"];
+    colors: NCoreUIKit.ActivePalette["colors"];
+    currentType: SnackBarTypes;
+    safeAreaTop: number;
+    type: SnackBarType;
+    theme?: undefined;
+};
+
+export type SnackBarTypes = {
+    containerColor: keyof NCoreUIKit.ContainerContentColors;
+    subTitleColor: keyof NCoreUIKit.TextContentColors;
+    actionColor: keyof NCoreUIKit.TextContentColors;
+    titleColor: keyof NCoreUIKit.TextContentColors;
+    iconColor: keyof NCoreUIKit.IconContentColors;
+};
+
+export type SnackBarTypeConstantType = {
+    type: SnackBarType;
+};
+
+export type SnackBarType = "primary" | "danger" | "warning" | "neutral" | "success" | "info";
+
+export type SnackBarInternalProps = {
+    contentContainerStyle?: StyleProp<ViewStyle>[] | StyleProp<ViewStyle>;
+    style?: StyleProp<ViewStyle>[] | StyleProp<ViewStyle>;
+    action?: {
+        onPress: (props: {
+            closeAnimation: (props: {
+                onClosed?: (props: {
+                    id: string;
+                }) => void;
+            }) => void;
+        }) => void;
+        icon?: NCoreUIKitIcon;
+        style?: ViewStyle;
+        title?: string;
+    };
+    isCloseOnPressActionButton?: boolean;
+    closeAnimationDelay?: number;
+    openAnimationDelay?: number;
+    isCloseOnPress?: boolean;
+    autoCloseDelay?: number;
+    isShowAction?: boolean;
+    icon?: NCoreUIKitIcon;
+    children?: ReactNode;
+    type?: SnackBarType;
+    onPress?: (props: {
+        id: string;
+    }) => void;
+    subTitle?: string;
+    title: string;
+    id: string;
+    onClosed?: (props: {
+        id: string;
+    }) => void;
+    customTheme?: {
+        gapPropagation?: NCoreUIKit.GapPropagationKey;
+        sharpness?: NCoreUIKit.SharpnessKey;
+        paletteKey?: NCoreUIKit.PaletteKey;
+        themeKey?: NCoreUIKit.ThemeKey;
+    };
+};
+
+interface ISnackBarProps extends SnackBarInternalProps {
+};
+
+export type {
+    ISnackBarProps as default
+};

+ 6 - 7
src/components/toast/index.tsx

@@ -149,7 +149,7 @@ const Toast: FC<IToastProps> = ({
             ]}
         >
             <CustomIcon
-                color="default"
+                color={currentType.iconColor}
                 size={18}
             />
         </View>;
@@ -164,6 +164,7 @@ const Toast: FC<IToastProps> = ({
             ]}
         >
             <Text
+                color={currentType.titleColor}
                 numberOfLines={3}
                 style={{
                     ...stylesheet.title,
@@ -175,9 +176,9 @@ const Toast: FC<IToastProps> = ({
             {
                 subTitle ?
                     <Text
+                        color={currentType.subTitleColor}
                         variant="labelSmallSize"
                         numberOfLines={2}
-                        color="low"
                         style={{
                             ...stylesheet.subTitle,
                             ...subTitleDynamicStyle
@@ -209,15 +210,13 @@ const Toast: FC<IToastProps> = ({
                     }) => closeAnimation(_onClosed)
                 });
             }}
-            icon={({
-                color
-            }) => {
+            icon={() => {
                 if(action?.title) {
                     return null;
                 }
 
                 return <XIcon
-                    color={colors.content.icon[color ? color : "default"]}
+                    color={colors.content.text[currentType.actionColor]}
                     size={18}
                 />;
             }}
@@ -226,8 +225,8 @@ const Toast: FC<IToastProps> = ({
                 ...actionDynamicStyle
             }}
             variant="ghost"
-            type="neutral"
             size="small"
+            type={type}
         />;
     };
 

+ 6 - 6
src/components/toast/stylesheet.ts

@@ -1,13 +1,13 @@
 import {
-    StyleSheet,
     type TextStyle,
-    type ViewStyle
+    type ViewStyle,
+    StyleSheet
 } from "react-native";
 import type {
     ToastDynamicStyleType,
-    ToastType,
     ToastTypeConstantType,
-    ToastTypes
+    ToastTypes,
+    ToastType
 } from "./type";
 import type {
     Mutable
@@ -16,7 +16,7 @@ import {
     windowWidth
 } from "../../utils";
 
-export const CHECK_BOX_TYPE_STYLES: Record<
+export const TOAST_TYPE_STYLES: Record<
     ToastType,
     {
         containerColor: keyof NCoreUIKit.ContainerContentColors;
@@ -73,7 +73,7 @@ export const CHECK_BOX_TYPE_STYLES: Record<
 export const getToastType = ({
     type
 }: ToastTypeConstantType): ToastTypes => {
-    const currentType = CHECK_BOX_TYPE_STYLES[type];
+    const currentType = TOAST_TYPE_STYLES[type];
 
     return currentType;
 };

+ 25 - 12
src/context/index.tsx

@@ -2,9 +2,10 @@ import {
     type ReactNode
 } from "react";
 import NCoreUIKitLocalize from "./localize";
-import NCoreUIKitToast from "./toast";
 import NCoreUIKitModal from "./modal";
+import NCoreUIKitSnackBar from "./snackBar";
 import NCoreUIKitTheme from "./theme";
+import NCoreUIKitToast from "./toast";
 import {
     type NCoreUIKitConfig
 } from "../types";
@@ -14,6 +15,7 @@ import {
 
 class CoreContext<T extends NCoreUIKitConfig> {
     NCoreUIKitLocalize: NCoreUIKitLocalize<T>;
+    NCoreUIKitSnackBar: NCoreUIKitSnackBar;
     NCoreUIKitTheme: NCoreUIKitTheme<T>;
     NCoreUIKitModal: NCoreUIKitModal;
     NCoreUIKitToast: NCoreUIKitToast;
@@ -39,6 +41,10 @@ class CoreContext<T extends NCoreUIKitConfig> {
         this.NCoreUIKitToast = new NCoreUIKitToast({
             data: []
         });
+
+        this.NCoreUIKitSnackBar = new NCoreUIKitSnackBar({
+            data: []
+        });
     }
 
     Provider = ({
@@ -47,24 +53,31 @@ class CoreContext<T extends NCoreUIKitConfig> {
         children: ReactNode
     }) => {
         const LocalizeContext = this.NCoreUIKitLocalize;
+        const SnackBarContext = this.NCoreUIKitSnackBar;
         const ModalContext = this.NCoreUIKitModal;
         const ToastContext = this.NCoreUIKitToast;
         const ThemeContext = this.NCoreUIKitTheme;
 
         return <ThemeContext.Provider>
             <LocalizeContext.Provider>
-                <Host name="toast-system">
-                    <ModalContext.Provider>
-                        <ModalContext.Render>
-                            <Host name="modal-system">
-                                <ToastContext.Provider>
-                                    <ToastContext.Render>
-                                        {children}
-                                    </ToastContext.Render>
-                                </ToastContext.Provider>
+                <Host name="snack-bar-system">
+                    <SnackBarContext.Provider>
+                        <SnackBarContext.Render>
+                            <Host name="toast-system">
+                                <ModalContext.Provider>
+                                    <ModalContext.Render>
+                                        <Host name="modal-system">
+                                            <ToastContext.Provider>
+                                                <ToastContext.Render>
+                                                    {children}
+                                                </ToastContext.Render>
+                                            </ToastContext.Provider>
+                                        </Host>
+                                    </ModalContext.Render>
+                                </ModalContext.Provider>
                             </Host>
-                        </ModalContext.Render>
-                    </ModalContext.Provider>
+                        </SnackBarContext.Render>
+                    </SnackBarContext.Provider>
                 </Host>
             </LocalizeContext.Provider>
         </ThemeContext.Provider>;

+ 114 - 0
src/context/snackBar.tsx

@@ -0,0 +1,114 @@
+import {
+    type ReactNode,
+    Fragment
+} from "react";
+import {
+    type SnackBarContextType,
+    type SnackBarDataType
+} from "../types/snackBar";
+import NCoreContext, {
+    type ConfigType
+} from "ncore-context";
+import SnackBar from "../components/snackBar";
+import {
+    uuid
+} from "../utils";
+
+class NCoreUIKitSnackBar extends NCoreContext<SnackBarContextType, ConfigType<SnackBarContextType>> {
+    constructor({
+        data = []
+    }: {
+        data?: Array<SnackBarDataType>
+    }) {
+        super({
+            close: () => {},
+            open: () => "",
+            data: data
+        }, {
+            key: "NCoreUIKit-SnackBarContext"
+        });
+    };
+
+    open = (snackBarData: SnackBarDataType) => {
+        const currentData = this.state.data;
+
+        const snackBarID = snackBarData.id ? snackBarData.id : uuid();
+
+        currentData.push({
+            ...snackBarData,
+            id: snackBarID
+        });
+
+        this.setState({
+            data: currentData
+        });
+
+        return snackBarID;
+    };
+
+    close = (props?: {
+        index?: number;
+        id?: string;
+    }) => {
+        const currentData = this.state.data;
+
+        if (props && props.id) {
+            const keyIndex = currentData.findIndex((snackBar) => snackBar.id === props.id);
+
+            if (keyIndex !== -1) {
+                currentData.splice(keyIndex, 1);
+
+                this.setState({
+                    data: currentData
+                });
+            }
+
+            return;
+        }
+
+        if (props && props.index !== undefined) {
+            currentData.splice(props.index, 1);
+
+            this.setState({
+                data: currentData
+            });
+
+            return;
+        }
+
+        currentData.pop();
+
+        this.setState({
+            data: currentData
+        });
+    };
+
+    Render = ({
+        children
+    }: {
+        children: ReactNode;
+    }) => {
+        const {
+            data
+        } = this.useContext();
+
+        return <Fragment>
+            {children}
+            {data.map((item: SnackBarDataType) => {
+                return <SnackBar
+                    key={`NCoreUIKit-SnackBar-${item.id}`}
+                    {...item}
+                    id={item.id as string}
+                    onClosed={(props) => {
+                        this.close({
+                            id: item.id
+                        });
+
+                        if(item.onClosed) item.onClosed(props);
+                    }}
+                />;
+            })}
+        </Fragment>;
+    };
+}
+export default NCoreUIKitSnackBar;

+ 3 - 0
src/core/hooks.ts

@@ -7,17 +7,20 @@ import type {
     ThemesType
 } from "../types";
 import type NCoreUIKitLocalizeClass from "../context/localize";
+import type NCoreUIKitSnackBarClass from "../context/snackBar";
 import type NCoreUIKitModalClass from "../context/modal";
 import type NCoreUIKitToastClass from "../context/toast";
 import type NCoreUIKitThemeClass from "../context/theme";
 
 export let NCoreUIKitLocalize: NCoreUIKitLocalizeClass<LocalizeType>;
 export let NCoreUIKitTheme: NCoreUIKitThemeClass<ThemesType>;
+export let NCoreUIKitSnackBar: NCoreUIKitSnackBarClass;
 export let NCoreUIKitModal: NCoreUIKitModalClass;
 export let NCoreUIKitToast: NCoreUIKitToastClass;
 
 export const initializeInstances = (NCoreUIKit: NCoreUIKitBase<NCoreUIKitConfig>) => {
     NCoreUIKitLocalize = NCoreUIKit.NCoreUIKitContext.NCoreUIKitLocalize;
+    NCoreUIKitSnackBar = NCoreUIKit.NCoreUIKitContext.NCoreUIKitSnackBar;
     NCoreUIKitTheme = NCoreUIKit.NCoreUIKitContext.NCoreUIKitTheme;
     NCoreUIKitModal = NCoreUIKit.NCoreUIKitContext.NCoreUIKitModal;
     NCoreUIKitToast = NCoreUIKit.NCoreUIKitContext.NCoreUIKitToast;

+ 2 - 2
src/helpers/portalize/Host.tsx

@@ -102,14 +102,14 @@ export const Host = ({
         name
     }}>
         <View
+            pointerEvents="box-none"
+            collapsable={false}
             style={[
                 {
                     flex: 1
                 },
                 style
             ]}
-            collapsable={false}
-            pointerEvents="box-none"
         >
             {children}
         </View>

+ 2 - 2
src/helpers/portalize/Manager.tsx

@@ -2,8 +2,8 @@ import {
     useImperativeHandle,
     type ReactNode,
     forwardRef,
-    useState,
-    useEffect
+    useEffect,
+    useState
 } from "react";
 import {
     StyleSheet,

+ 1 - 0
src/index.tsx

@@ -5,6 +5,7 @@ export {
 
 export {
     NCoreUIKitLocalize,
+    NCoreUIKitSnackBar,
     NCoreUIKitModal,
     NCoreUIKitTheme,
     NCoreUIKitToast

+ 24 - 0
src/types/snackBar.ts

@@ -0,0 +1,24 @@
+import {
+    type SnackBarInternalProps
+} from "../components/snackBar/type";
+
+export type SnackBarType = {
+    data?: Array<SnackBarDataType>;
+};
+
+export type SnackBarDataType = Omit<SnackBarInternalProps, "id"> & {
+    id?: string;
+};
+
+export type SnackBarContextType = {
+    open: (toastData: SnackBarDataType) => string;
+    close: (props?: {
+        index?: number;
+        id?: string;
+    }) => void;
+    data: Array<SnackBarDataType>;
+};
+
+export type SnackBarStateContextType = {
+    data: Array<SnackBarDataType>;
+};