Răsfoiți Sursa

Merge branch 'release/1.0.0-pre-alpha.11'

lfabl 1 lună în urmă
părinte
comite
8100023c71
46 a modificat fișierele cu 2932 adăugiri și 99 ștergeri
  1. 0 1
      example/package.json
  2. 130 3
      example/src/pages/home/index.tsx
  3. 1 3
      package.json
  4. 27 8
      src/components/bottomSheet/index.tsx
  5. 11 3
      src/components/bottomSheet/type.ts
  6. 2 0
      src/components/button/index.tsx
  7. 8 0
      src/components/button/stylesheet.ts
  8. 2 1
      src/components/button/type.ts
  9. 0 1
      src/components/checkBox/type.ts
  10. 335 0
      src/components/dialog/index.tsx
  11. 126 0
      src/components/dialog/stylesheet.ts
  12. 83 0
      src/components/dialog/type.ts
  13. 5 2
      src/components/index.ts
  14. 48 10
      src/components/modal/index.tsx
  15. 4 4
      src/components/modal/stylesheet.ts
  16. 18 9
      src/components/modal/type.ts
  17. 8 3
      src/components/selectBox/index.tsx
  18. 297 0
      src/components/snackBar/index.tsx
  19. 152 0
      src/components/snackBar/stylesheet.ts
  20. 81 0
      src/components/snackBar/type.ts
  21. 272 0
      src/components/toast/index.tsx
  22. 156 0
      src/components/toast/stylesheet.ts
  23. 79 0
      src/components/toast/type.ts
  24. 121 0
      src/context/bottomSheet.tsx
  25. 120 0
      src/context/dialog.tsx
  26. 60 5
      src/context/index.tsx
  27. 25 15
      src/context/modal.tsx
  28. 114 0
      src/context/snackBar.tsx
  29. 114 0
      src/context/toast.tsx
  30. 12 0
      src/core/hooks.ts
  31. 4 4
      src/core/index.tsx
  32. 53 0
      src/helpers/portalize/Consumer.tsx
  33. 122 0
      src/helpers/portalize/Host.tsx
  34. 75 0
      src/helpers/portalize/Manager.tsx
  35. 30 0
      src/helpers/portalize/Portal.tsx
  36. 49 0
      src/helpers/portalize/context/index.ts
  37. 49 0
      src/helpers/portalize/hooks/useKey.ts
  38. 15 0
      src/helpers/portalize/index.tsx
  39. 15 4
      src/index.tsx
  40. 23 0
      src/types/bottomSheet.ts
  41. 23 0
      src/types/dialog.ts
  42. 3 2
      src/types/modal.ts
  43. 24 0
      src/types/snackBar.ts
  44. 24 0
      src/types/toast.ts
  45. 12 8
      src/variants/locales/default.json
  46. 0 13
      yarn.lock

+ 0 - 1
example/package.json

@@ -22,7 +22,6 @@
         "react": "19.2.0",
         "react-dom": "19.2.0",
         "react-native": "0.83.2",
-        "react-native-portalize": "^1.0.7",
         "react-native-safe-area-context": "^5.7.0",
         "react-native-screens": "^4.24.0",
         "react-native-svg": "^15.15.3",

+ 130 - 3
example/src/pages/home/index.tsx

@@ -1,6 +1,6 @@
 import {
-    useRef,
-    useState
+    useState,
+    useRef
 } from "react";
 import {
     View
@@ -9,13 +9,18 @@ import stylesheet from "./stylesheet";
 import {
     type IBottomSheetRef,
     getNCoreUIKitVersion,
+    NCoreUIKitSnackBar,
+    NCoreUIKitDialog,
+    NCoreUIKitToast,
     NCoreUIKitTheme,
     BottomSheet,
     TextInput,
     SelectBox,
+    CheckBox,
     Button,
+    Dialog,
     Text,
-    CheckBox
+    NCoreUIKitBottomSheet
 } from "ncore-ui-kit-mobile";
 import {
     useNavigation
@@ -24,6 +29,9 @@ import type {
     NativeStackNavigationProp
 } from "@react-navigation/native-stack";
 import type RootStackParamList from "../../navigation/type";
+import {
+    HomeIcon
+} from "lucide-react-native";
 
 const X = [
     {
@@ -197,6 +205,11 @@ const Home = () => {
         setIsCheckboxActive
     ] = useState<"partially" | "checked" | null>("checked");
 
+    const [
+        isDialogActive,
+        setIsDialogActive
+    ] = useState(false);
+
     return <View
         style={[
             stylesheet.container,
@@ -253,15 +266,118 @@ const Home = () => {
                 bottomSheetRef.current?.open();
             }}
             type="success"
+            title="Open Local BottomSheet"
+            variant="filled"
+        />
+        <Button
+            onPress={() => {
+                NCoreUIKitBottomSheet.open({
+                    children: <View>
+                        <Text>Deneme 123</Text>
+                        <Text>Deneme 123</Text>
+                        <Text>Deneme 123</Text>
+                        <Text>Deneme 123</Text>
+                        <Text>Deneme 123</Text>
+                        <Text>Deneme 123</Text>
+                    </View>
+                });
+            }}
+            type="success"
             title="Open BottomSheet"
             variant="filled"
         />
+        <Button
+            onPress={() => {
+                setIsDialogActive(!isDialogActive);
+            }}
+            type="neutral"
+            title="Open Local Dialog"
+            variant="filled"
+        />
         <Button
             title="Open Snackbar"
             variant="filled"
             type="danger"
             onPress={() => {
+                NCoreUIKitSnackBar.open({
+                    title: "sdgdsgs",
+                    icon: ({
+                        color
+                    }) => <HomeIcon color={colors.content.icon[color ? color : "default"]}/>
+                });
+            }}
+        />
+        <Button
+            onPress={() => {
+                NCoreUIKitDialog.open({
+                    content: "etgweı09gı9w0eg",
+                    title: "Merhaba Dünya!",
+                    isVisible: true,
+                    onOverlayPress: ({
+                        closeAnimation
+                    }) => {
+                        closeAnimation();
+                    },
+                    variant: "info",
+                    secondaryButtonProps: {
+                        title: "sdfgsdg",
+                        onPress: () => {
 
+                        }
+                    },
+                    primaryButtonProps: {
+                        onPress: ({
+                            closeAnimation
+                        }) => {
+                            closeAnimation();
+                        }
+                    }
+                });
+            }}
+            type="neutral"
+            title="Open Dialog"
+            variant="filled"
+        />
+        <Button
+            title="Open Toast"
+            variant="filled"
+            type="warning"
+            onPress={() => {
+                NCoreUIKitToast.open({
+                    title: "sdgfsdgsdafs sdlşlgkdfşiklh",
+                    subTitle: "tr9uıdgfss 0dgklsd",
+                    isShowAction: true,
+                    icon: ({
+                        color
+                    }) => <HomeIcon color={colors.content.icon[color ? color : "default"]}/>
+                });
+            }}
+        />
+        <Dialog
+            isVisible={isDialogActive}
+            content="etgweı09gı9w0eg"
+            title="Merhaba Dünya!"
+            modalProps={{
+                isWorkWithPortal: false
+            }}
+            onOverlayPress={({
+                closeAnimation
+            }) => {
+                closeAnimation(() => setIsDialogActive(false));
+            }}
+            variant="info"
+            secondaryButtonProps={{
+                title: "sdfgsdg",
+                onPress: () => {
+
+                }
+            }}
+            primaryButtonProps={{
+                onPress: ({
+                    closeAnimation
+                }) => {
+                    closeAnimation(() => setIsDialogActive(false));
+                }
             }}
         />
         <BottomSheet
@@ -282,6 +398,17 @@ const Home = () => {
             snapPoint={300}
             key="ahmet"
         >
+            <Button
+                title="Open Toast"
+                variant="filled"
+                type="warning"
+                onPress={() => {
+                    NCoreUIKitToast.open({
+                        title: "sdgfsdgsdg",
+                        type: "danger"
+                    });
+                }}
+            />
             <Button
                 onPress={() => {
                     navigation.navigate("TestSubPage");

+ 1 - 3
package.json

@@ -1,6 +1,6 @@
 {
     "name": "ncore-ui-kit-mobile",
-    "version": "1.0.0-pre-alpha.10",
+    "version": "1.0.0-pre-alpha.11",
     "description": "NİBGAT® | NCore - UI Kit for React-Native Mobile Apps.",
     "main": "./lib/module/index.js",
     "types": "./lib/typescript/src/index.d.ts",
@@ -102,7 +102,6 @@
         "ncore-context": ">= 1.0.5",
         "react": "*",
         "react-native": "*",
-        "react-native-portalize": ">= 1.0.7",
         "react-native-safe-area-context": ">= 5.7.0",
         "react-native-svg": ">= 15.15.3"
     },
@@ -158,7 +157,6 @@
     "dependencies": {
         "lucide-react-native": "0.577.0",
         "ncore-context": "1.0.5",
-        "react-native-portalize": "1.0.7",
         "react-native-safe-area-context": "5.7.0",
         "react-native-svg": "15.15.3"
     }

+ 27 - 8
src/components/bottomSheet/index.tsx

@@ -62,9 +62,11 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
     scrollViewStyle,
     onScrollEnd,
     customTheme,
+    portalName,
     modalProps,
     snapPoint,
     customKey,
+    id: outID,
     children,
     onClosed,
     onOpened,
@@ -93,6 +95,8 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
         setIsActive
     ] = useState(isActiveProp === undefined ? false : isActiveProp);
 
+    const id = useRef(outID ? outID : uuid());
+
     const bottomSheetKey = useRef(customKey ? customKey : uuid());
 
     let bottomSafeArea = isWrapSafeAreaContext ? bottom : 0;
@@ -145,8 +149,8 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
     useImperativeHandle(
         ref,
         () => ({
-            close: (callback) => {
-                closeAnimation(undefined, callback);
+            close: (onClosed) => {
+                closeAnimation(undefined, onClosed);
             },
             open: () => {
                 setIsActive(true);
@@ -302,8 +306,12 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
         });
     };
 
-    const closeAnimation = (toValue?: number, callback?: () => void) => {
-        if(onClose) onClose();
+    const closeAnimation = (toValue?: number, _onClosed?: (props: {
+        id: string;
+    }) => void) => {
+        if(onClose) onClose({
+            id: id.current
+        });
 
         const currentSnapPoint = isWorkAsFullScreen
             ? containerHeightRef.current
@@ -321,8 +329,13 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
 
                 setIsActive(false);
 
-                if(onClosed) onClosed();
-                if(callback) callback();
+                if(onClosed) onClosed({
+                    id: id.current
+                });
+
+                if(_onClosed) _onClosed({
+                    id: id.current
+                });
             }
         });
     };
@@ -672,7 +685,9 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
                             }
                         }
 
-                        if(onClose) onClose();
+                        if(onClose) onClose({
+                            id: id.current
+                        });
 
                         Animated.timing(animatedTranslateY, {
                             useNativeDriver: false,
@@ -684,7 +699,9 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
                             if (finished && isClosing) {
                                 setIsActive(false);
 
-                                if (onClosed) onClosed();
+                                if (onClosed) onClosed({
+                                    id: id.current
+                                });
                             }
                         });
                     }
@@ -806,12 +823,14 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
 
     return <Modal
         {...modalProps}
+        portalName={portalName ? portalName : "bottomSheet-system"}
         isWorkWithPortal={isWorkWithPortal}
         key={`${bottomSheetKey}-modal`}
         isContentRequired={false}
         isActive={isActive}
         alignContent="free"
         isAnimated={false}
+        id={id.current}
         ref={modalRef}
         onContainerLayout={(e) => {
             const containerLayoutHeight = e.nativeEvent.layout.height;

+ 11 - 3
src/components/bottomSheet/type.ts

@@ -9,7 +9,9 @@ import type {
 import type IModalProps from "../modal/type";
 
 export interface IBottomSheetRef {
-    close: (callback: () => void) => void;
+    close: (onClosed: (props: {
+        id: string;
+    }) => void) => void;
     open: () => void;
 }
 
@@ -36,12 +38,17 @@ interface IBottomSheetProps {
     isShowHandle?: boolean;
     isAutoHeight?: boolean;
     handleHeight?: number;
-    onClosed?: () => void;
     onOpened?: () => void;
     isCanSwipe?: boolean;
-    onClose?: () => void;
     children?: ReactNode;
+    onClosed?: (props: {
+        id: string;
+    }) => void;
+    portalName?: string;
     onOpen?: () => void;
+    onClose?: (props: {
+        id: string;
+    }) => void;
     snapPoint?: number;
     isActive?: boolean;
     customKey?: string;
@@ -52,6 +59,7 @@ interface IBottomSheetProps {
         paletteKey?: NCoreUIKit.PaletteKey;
         themeKey?: NCoreUIKit.ThemeKey;
     };
+    id?: string;
 }
 export type {
     IBottomSheetProps as default

+ 2 - 0
src/components/button/index.tsx

@@ -30,6 +30,7 @@ import Text from "../text";
 const Button: FC<IButtonProps> = ({
     displayBehaviourWhileLoading = "disabled",
     spreadBehaviour = "baseline",
+    isCustomPadding = false,
     icon: IconComponentProp,
     iconDirection = "left",
     variant = "filled",
@@ -73,6 +74,7 @@ const Button: FC<IButtonProps> = ({
     } = useStyles({
         displayBehaviourWhileLoading,
         icon: IconComponentProp,
+        isCustomPadding,
         spreadBehaviour,
         currentVariant,
         iconDirection,

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

@@ -171,6 +171,7 @@ const stylesheet = StyleSheet.create({
 export const useStyles = ({
     displayBehaviourWhileLoading,
     spreadBehaviour,
+    isCustomPadding,
     currentVariant,
     iconDirection,
     currentType,
@@ -274,6 +275,13 @@ export const useStyles = ({
         }
     }
 
+    if(isCustomPadding) {
+        delete styles.container.paddingBottom;
+        delete styles.container.paddingRight;
+        delete styles.container.paddingLeft;
+        delete styles.container.paddingTop;
+    }
+
     return styles;
 };
 export default stylesheet;

+ 2 - 1
src/components/button/type.ts

@@ -18,12 +18,12 @@ export type ButtonDynamicStyleType = {
     currentVariant: ButtonVariants;
     borders: NCoreUIKit.Borders;
     currentSize: ButtonMeasures;
+    isCustomPadding?: boolean;
     currentType: ButtonTypes;
     variant: ButtonVariant;
     icon?: NCoreUIKitIcon;
     isDisabled?: boolean;
     isLoading?: boolean;
-    theme?: undefined;
     type: ButtonType;
     title?: string;
 };
@@ -89,6 +89,7 @@ interface IButtonProps extends Omit<ButtonProps, "title"> {
     };
     spreadBehaviour?: ButtonSpreadBehaviour;
     iconDirection?: "left" | "right";
+    isCustomPadding?: boolean;
     variant?: ButtonVariant;
     icon?: NCoreUIKitIcon;
     isDisabled?: boolean;

+ 0 - 1
src/components/checkBox/type.ts

@@ -17,7 +17,6 @@ export type CheckBoxDynamicStyleType = {
     isDisabled?: boolean;
     isLoading?: boolean;
     type: CheckBoxType;
-    theme?: undefined;
     isFlip?: boolean;
 };
 

+ 335 - 0
src/components/dialog/index.tsx

@@ -0,0 +1,335 @@
+import {
+    useImperativeHandle,
+    forwardRef,
+    useEffect,
+    useRef
+} from "react";
+import {
+    Animated,
+    Easing,
+    View
+} from "react-native";
+import type IDialogProps from "./type";
+import type {
+    IDialogRef
+} from "./type";
+import stylesheet, {
+    useStyles
+} from "./stylesheet";
+import {
+    NCoreUIKitLocalize,
+    NCoreUIKitTheme
+} from "../../core/hooks";
+import type {
+    RefForwardingComponent
+} from "../../types";
+import type {
+    IModalRef
+} from "../modal/type";
+import {
+    X as XIcon
+} from "lucide-react-native";
+import Button from "../button";
+import Modal from "../modal";
+import Text from "../text";
+import {
+    uuid
+} from "../../utils";
+
+const Dialog: RefForwardingComponent<IDialogRef, IDialogProps> = ({
+    bottomContentContainerStyle,
+    contentJustify = "centered",
+    contentContainerStyle,
+    bottomContainerStyle,
+    headerContainerStyle,
+    secondaryButtonStyle,
+    secondaryButtonProps,
+    primaryButtonStyle,
+    primaryButtonProps,
+    closeIconProps = {
+        color: "low",
+        size: 22
+    },
+    isVisible = false,
+    withModal = true,
+    headerComponent,
+    bottomComponent,
+    onOverlayPress,
+    variant = "ok",
+    modalProps,
+    id: outID,
+    onClosed,
+    children,
+    content,
+    style,
+    title
+}, ref) => {
+    const {
+        radiuses,
+        colors,
+        spaces
+    } = NCoreUIKitTheme.useContext();
+
+    const {
+        localize
+    } = NCoreUIKitLocalize.useContext();
+
+    const id = useRef(outID ? outID : uuid());
+
+    const {
+        bottomContentContainer: bottomContentContainerDynamicStyle,
+        headerContainer: headerContainerDynamicStyle,
+        bottomContainer: bottomContainerDynamicStyle,
+        primaryButton: primaryButtonDynamicStyle,
+        contentText: contentTextDynamicStyle,
+        headerTitle: headerTitleDynamicStyle,
+        container: containerDynamicStyle,
+        closeIcon: closeIconDynamicStyle,
+        content: contentDynamicStyle
+    } = useStyles({
+        contentJustify,
+        isVisible,
+        radiuses,
+        variant,
+        colors,
+        spaces
+    });
+
+    const scaleAnim = useRef(new Animated.Value(0)).current;
+
+    const modalRef = useRef<IModalRef>(null);
+
+    useEffect(() => {
+        if(isVisible) {
+            Animated.timing(scaleAnim, {
+                useNativeDriver: true,
+                easing: Easing.linear,
+                duration: 350,
+                toValue: 1
+            }).start();
+        }
+    }, [isVisible]);
+
+    useImperativeHandle(
+        ref,
+        () => ({
+            closeAnimation
+        }),
+        []
+    );
+
+    const closeAnimation = (_onClosed?: (props: {
+        id: string;
+    }) => void) => {
+        Animated.timing(scaleAnim, {
+            useNativeDriver: true,
+            easing: Easing.linear,
+            duration: 250,
+            toValue: 0
+        }).start(({
+            finished
+        }) => {
+            if(finished) {
+                if(_onClosed) _onClosed({
+                    id: id.current
+                });
+
+                if(onClosed) onClosed({
+                    id: id.current
+                });
+
+                if(modalRef && modalRef.current) modalRef.current.closeAnimation();
+            }
+        });
+    };
+
+    const renderHeader = () => {
+        return <View
+            style={[
+                headerContainerStyle,
+                stylesheet.headerContainer,
+                headerContainerDynamicStyle
+            ]}
+        >
+            {headerComponent || <Text
+                style={[
+                    stylesheet.headerTitle,
+                    headerTitleDynamicStyle
+                ]}
+                variant="titleLargeSize"
+                color="mid"
+            >
+                {title}
+            </Text>}
+        </View>;
+    };
+
+    const renderBottom = () => {
+        if(variant === "info") {
+            return null;
+        }
+
+        return <View
+            style={[
+                bottomContainerStyle,
+                stylesheet.bottomContainer,
+                bottomContainerDynamicStyle
+            ]}
+        >
+            {bottomComponent || <View
+                style={[
+                    bottomContentContainerStyle,
+                    stylesheet.bottomContentContainer,
+                    bottomContentContainerDynamicStyle
+                ]}
+            >
+                {secondaryButton()}
+                {primaryButton()}
+            </View>}
+        </View>;
+    };
+
+    const secondaryButton = () => {
+        if(variant !== "yes-no") {
+            return null;
+        }
+
+        return <Button
+            onPress={() => {
+                if(secondaryButtonProps?.onPress) secondaryButtonProps.onPress({
+                    closeAnimation: (onClosed?: (props: {
+                        id: string;
+                    }) => void) => {
+                        closeAnimation(onClosed);
+                    }
+                });
+            }}
+            spreadBehaviour={contentJustify === "centered" ? "stretch" : "free"}
+            title={secondaryButtonProps?.title || localize("cancel")}
+            isLoading={secondaryButtonProps?.isLoading}
+            style={secondaryButtonStyle}
+            variant="outline"
+            type="neutral"
+        />;
+    };
+
+    const primaryButton = () => {
+        return <Button
+            displayBehaviourWhileLoading={primaryButtonProps?.displayBehaviourWhileLoading}
+            spreadBehaviour={contentJustify === "centered" ? "stretch" : "free"}
+            onPress={() => {
+                if(primaryButtonProps?.onPress) primaryButtonProps?.onPress({
+                    closeAnimation: (onClosed?: (props: {
+                        id: string;
+                    }) => void) => {
+                        closeAnimation(onClosed);
+                    }
+                });
+            }}
+            title={primaryButtonProps?.title || localize("ok")}
+            isLoading={primaryButtonProps?.isLoading}
+            style={[
+                primaryButtonStyle,
+                stylesheet.primaryButton,
+                primaryButtonDynamicStyle
+            ]}
+            variant="filled"
+            type="primary"
+            size="medium"
+        />;
+    };
+
+    const renderCloseIcon = () => {
+        if(variant !== "info") {
+            return null;
+        }
+
+        if(contentJustify === "centered") {
+            return null;
+        }
+
+        return <Button
+            onPress={() => {
+                if(onOverlayPress) onOverlayPress({
+                    closeAnimation: (onClosed?: (props: {
+                        id: string;
+                    }) => void) => {
+                        closeAnimation(onClosed);
+                    }
+                });
+            }}
+            icon={() => <XIcon
+                color={closeIconProps.color}
+                size={closeIconProps.size}
+            />}
+            style={[
+                stylesheet.closeIcon,
+                closeIconDynamicStyle
+            ]}
+            isCustomPadding={true}
+            variant="ghost"
+        />;
+    };
+
+    const renderDialog = () => {
+        if(!isVisible) {
+            return null;
+        }
+
+        return <Animated.View
+            style={[
+                style,
+                stylesheet.container,
+                containerDynamicStyle,
+                {
+                    transform: [{
+                        scale: scaleAnim
+                    }]
+                }
+            ]}
+        >
+            {renderCloseIcon()}
+            {renderHeader()}
+            <View
+                style={[
+                    contentContainerStyle,
+                    stylesheet.content,
+                    contentDynamicStyle
+                ]}
+            >
+                {children || <Text
+                    style={[
+                        stylesheet.contentText,
+                        contentTextDynamicStyle
+                    ]}
+                    variant="bodyLargeSize"
+                >
+                    {content}
+                </Text>}
+            </View>
+            {renderBottom()}
+        </Animated.View>;
+    };
+
+    if(!isVisible) {
+        return null;
+    }
+
+    return withModal ? <Modal
+        {...modalProps}
+        id={`${id.current}-modal`}
+        ref={modalRef}
+        onOverlayPress={() => {
+            if(onOverlayPress) onOverlayPress({
+                closeAnimation: (onClosed?: (props: {
+                    id: string;
+                }) => void) => {
+                    closeAnimation(onClosed);
+                }
+            });
+        }}
+    >
+        {renderDialog()}
+    </Modal> : renderDialog();
+};
+export default forwardRef(Dialog);

+ 126 - 0
src/components/dialog/stylesheet.ts

@@ -0,0 +1,126 @@
+import {
+    type TextStyle,
+    type ViewStyle,
+    StyleSheet
+} from "react-native";
+import {
+    type DialogDynamicStyleType
+} from "./type";
+import type {
+    Mutable
+} from "../../types";
+
+const stylesheet = StyleSheet.create({
+    container: {
+        flexDirection: "column",
+        position: "relative",
+        overflow: "hidden",
+        maxHeight: "80%",
+        maxWidth: "85%",
+        minWidth: "23%",
+        zIndex: 99998
+    },
+    content: {
+        flexWrap: "wrap"
+    },
+    headerContainer: {
+        paddingBottom: 0
+    },
+    bottomContainer: {
+        width: "100%"
+    },
+    bottomContentContainer: {
+        justifyContent: "flex-end",
+        flexDirection: "row"
+    },
+    headerTitle: {
+
+    },
+    contentText: {
+
+    },
+    primaryButton: {
+
+    },
+    closeIcon: {
+        position: "absolute",
+        right: 0,
+        top: 0
+    }
+});
+
+export const useStyles = ({
+    contentJustify,
+    isVisible,
+    radiuses,
+    variant,
+    colors,
+    spaces
+}: DialogDynamicStyleType) => {
+    const styles = {
+        container: {
+            backgroundColor: colors.content.container.default,
+            borderRadius: radiuses.md
+        } as Mutable<ViewStyle>,
+        content: {
+            paddingBottom: spaces.spacingMd,
+            paddingRight: spaces.spacingMd,
+            paddingLeft: spaces.spacingMd,
+            paddingTop: spaces.spacingMd
+        } as Mutable<ViewStyle>,
+        headerContainer: {
+            paddingRight: spaces.spacingMd,
+            paddingLeft: spaces.spacingMd,
+            paddingTop: spaces.spacingLg
+        } as Mutable<ViewStyle>,
+        bottomContainer: {
+            paddingTop: spaces.spacingSm
+        } as Mutable<ViewStyle>,
+        bottomContentContainer: {
+            paddingBottom: spaces.spacingMd,
+            paddingRight: spaces.spacingMd,
+            paddingLeft: spaces.spacingMd
+        } as Mutable<ViewStyle>,
+        headerTitle: {
+
+        } as Mutable<TextStyle>,
+        contentText: {
+
+        } as Mutable<TextStyle>,
+        closeIcon: {
+            padding: spaces.spacingMd
+        } as Mutable<ViewStyle>,
+        primaryButton: {
+
+        } as Mutable<ViewStyle>
+    };
+
+    if(variant === "yes-no") {
+        styles.primaryButton.marginLeft = spaces.spacingMd;
+    }
+
+    if(isVisible === false) {
+        styles.container.display = "none";
+    }
+
+    if(contentJustify === "centered") {
+        styles.content.justifyContent = "center";
+        styles.content.alignItems = "center";
+        styles.content.display = "flex";
+
+        styles.contentText.textAlign = "center";
+
+        styles.headerContainer.justifyContent = "center";
+        styles.headerContainer.alignItems = "center";
+        styles.headerContainer.display = "flex";
+
+        styles.headerTitle.textAlign = "center";
+    }
+
+    if(variant === "info") {
+        styles.content.paddingBottom = spaces.spacingLg;
+    }
+
+    return styles;
+};
+export default stylesheet;

+ 83 - 0
src/components/dialog/type.ts

@@ -0,0 +1,83 @@
+import {
+    type ReactNode
+} from "react";
+import {
+    type StyleProp,
+    type ViewStyle
+} from "react-native";
+import type {
+    ModalInternalProps
+} from "../modal/type";
+import type IButtonProps from "../button/type";
+import type {
+    INCoreUIKitIconProps
+} from "../../types";
+import type {
+    ButtonDisplayBehaviourWhileLoading
+} from "../button/type";
+
+export type IDialogRef = {
+    closeAnimation: (onClosed: (props: {
+        id: string;
+    }) => void) => void;
+};
+
+export type DialogDynamicStyleType = {
+    radiuses: NCoreUIKit.ActivePalette["radiuses"];
+    colors: NCoreUIKit.ActivePalette["colors"];
+    spaces: NCoreUIKit.ActivePalette["spaces"];
+    contentJustify?: DialogContentJustify;
+    variant: DialogVariant;
+    isVisible?: boolean;
+};
+
+export type DialogVariant = "yes-no" | "ok" | "info";
+
+export type DialogContentJustify = "centered" | "language-based";
+
+type DialogButton = {
+    displayBehaviourWhileLoading?: ButtonDisplayBehaviourWhileLoading;
+    onPress?: (props: {
+        closeAnimation: (onClosed?: (props: {
+            id: string;
+        }) => void) => void;
+    }) => void;
+    isLoading?: boolean;
+    title?: string;
+};
+
+interface IDialogProps {
+    bottomContentContainerStyle?: StyleProp<ViewStyle> | Array<StyleProp<ViewStyle>>;
+    contentContainerStyle?: StyleProp<ViewStyle> | Array<StyleProp<ViewStyle>>;
+    bottomContainerStyle?: StyleProp<ViewStyle> | Array<StyleProp<ViewStyle>>;
+    headerContainerStyle?: StyleProp<ViewStyle> | Array<StyleProp<ViewStyle>>;
+    style?: StyleProp<ViewStyle> | Array<StyleProp<ViewStyle>>;
+    onOverlayPress?: (props: {
+        closeAnimation: (onClosed?: (props: {
+            id: string;
+        }) => void) => void;
+    }) => void;
+    secondaryButtonStyle?: IButtonProps["style"];
+    modalProps?: Omit<ModalInternalProps, "id">;
+    primaryButtonStyle?: IButtonProps["style"];
+    closeIconProps?: INCoreUIKitIconProps;
+    contentJustify?: DialogContentJustify;
+    secondaryButtonProps?: DialogButton;
+    primaryButtonProps?: DialogButton;
+    headerComponent?: ReactNode;
+    bottomComponent?: ReactNode;
+    variant?: DialogVariant;
+    children?: ReactNode;
+    isVisible?: boolean;
+    withModal?: boolean;
+    onClosed?: (props: {
+        id: string;
+    }) => void;
+    content?: string;
+    title: string;
+    id?: string;
+};
+
+export type {
+    IDialogProps as default
+};

+ 5 - 2
src/components/index.ts

@@ -10,7 +10,6 @@ export {
     default as PageContainer
 } from "./pageContainer";
 
-/*
 export {
     default as Dialog
 } from "./dialog";
@@ -18,7 +17,7 @@ export {
 export type {
     IDialogRef
 } from "./dialog/type";
-*/
+
 export {
     default as Modal
 } from "./modal";
@@ -54,3 +53,7 @@ export {
 export {
     default as CheckBox
 } from "./checkBox";
+
+export {
+    default as Toast
+} from "./toast";

+ 48 - 10
src/components/modal/index.tsx

@@ -24,7 +24,10 @@ import {
 } from "../../types";
 import {
     Portal
-} from "react-native-portalize";
+} from "../../helpers/portalize";
+import {
+    uuid
+} from "../../utils";
 
 /**
  * A generic modal
@@ -32,9 +35,11 @@ import {
  * @returns Element
  */
 const Modal: RefForwardingComponent<IModalRef, IModalProps> = ({
+    isScaleAnimatedOnlyOpen = true,
     isDisabledOverlay = false,
     isContentRequired = true,
     isOverlayVisible = true,
+    isScaleAnimated = false,
     alignContent = "center",
     isWorkWithPortal = true,
     isActive: isActiveProp,
@@ -44,14 +49,20 @@ const Modal: RefForwardingComponent<IModalRef, IModalProps> = ({
     contentStyle,
     overlayProps,
     customTheme,
+    portalName,
+    id: outID,
     children,
+    onClosed,
     style
 }, ref) => {
     const {
         colors
     } = NCoreUIKitTheme.useContext(customTheme);
 
-    const scaleAnim = useRef(new Animated.Value(isAnimated ? 0 : 1)).current;
+    const id = useRef(outID ? outID : uuid());
+
+    const scaleAnim = useRef(new Animated.Value(isAnimated && isScaleAnimated ? 0 : 1)).current;
+    const opacityAnim = useRef(new Animated.Value(isAnimated ? 0 : 1)).current;
 
     const [
         isActive,
@@ -60,14 +71,23 @@ const Modal: RefForwardingComponent<IModalRef, IModalProps> = ({
 
     useEffect(() => {
         if(isAnimated) {
-            Animated.timing(scaleAnim, {
-                easing: Easing.out(Easing.back(1.5)),
+            if(isScaleAnimated) {
+                Animated.timing(scaleAnim, {
+                    easing: Easing.out(Easing.back(1.5)),
+                    useNativeDriver: true,
+                    duration: 350,
+                    toValue: 1
+                }).start();
+            }
+
+            Animated.timing(opacityAnim, {
                 useNativeDriver: true,
+                easing: Easing.linear,
                 duration: 350,
                 toValue: 1
             }).start();
         }
-    }, []);
+    }, [isActive]);
 
     useEffect(() => {
         if(isActiveProp !== undefined) {
@@ -84,18 +104,35 @@ const Modal: RefForwardingComponent<IModalRef, IModalProps> = ({
         []
     );
 
-    const closeAnimation = (onClosed?: () => void) => {
+    const closeAnimation = (_onClosed?: (props: {
+        id: string;
+    }) => void) => {
         if(isAnimated) {
-            Animated.timing(scaleAnim, {
-                easing: Easing.in(Easing.ease),
+            if(isScaleAnimated && !isScaleAnimatedOnlyOpen) {
+                Animated.timing(scaleAnim, {
+                    easing: Easing.in(Easing.ease),
+                    useNativeDriver: true,
+                    duration: 250,
+                    toValue: 0
+                }).start();
+            }
+
+            Animated.timing(opacityAnim, {
                 useNativeDriver: true,
+                easing: Easing.linear,
                 duration: 250,
                 toValue: 0
             }).start(({
                 finished
             }) => {
                 if(finished) {
-                    if(onClosed) onClosed();
+                    if(_onClosed) _onClosed({
+                        id: id.current
+                    });
+
+                    if(onClosed) onClosed({
+                        id: id.current
+                    });
                 }
             });
         }
@@ -143,6 +180,7 @@ const Modal: RefForwardingComponent<IModalRef, IModalProps> = ({
                 {
                     justifyContent: alignContent === "center" ? "center" : undefined,
                     alignItems: alignContent === "center" ? "center" : "baseline",
+                    opacity: opacityAnim,
                     transform: [{
                         scale: scaleAnim
                     }]
@@ -170,7 +208,7 @@ const Modal: RefForwardingComponent<IModalRef, IModalProps> = ({
     };
 
     const renderWithPortal = () => {
-        return <Portal>
+        return <Portal name={portalName ? portalName : "modal-system"}>
             {renderContainer()}
         </Portal>;
     };

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

@@ -6,7 +6,7 @@ const stylesheet = StyleSheet.create({
     container: {
         position: "absolute",
         display: "flex",
-        zIndex: 99997,
+        zIndex: 99994,
         bottom: 0,
         right: 0,
         left: 0,
@@ -14,7 +14,7 @@ const stylesheet = StyleSheet.create({
     },
     overlay: {
         position: "absolute",
-        zIndex: 99998,
+        zIndex: 99995,
         bottom: 0,
         right: 0,
         left: 0,
@@ -22,7 +22,7 @@ const stylesheet = StyleSheet.create({
     },
     overlayContent: {
         position: "absolute",
-        zIndex: 99998,
+        zIndex: 99996,
         bottom: 0,
         right: 0,
         left: 0,
@@ -30,7 +30,7 @@ const stylesheet = StyleSheet.create({
     },
     content: {
         display: "contents",
-        zIndex: 99999
+        zIndex: 99997
     }
 });
 export default stylesheet;

+ 18 - 9
src/components/modal/type.ts

@@ -16,27 +16,36 @@ export type IModalRef = {
 export type ModalAlignContentProp = "center" | "free";
 
 export type ModalInternalProps = {
-    onOverlayPress?: (props: {
-        closeAnimation: (callback?: () => void) => void
-    }) => void;
     contentStyle?: StyleProp<ViewStyle>[] | StyleProp<ViewStyle>;
     style?: StyleProp<ViewStyle>[] | StyleProp<ViewStyle>;
     onContainerLayout?: (e: LayoutChangeEvent) => void;
+    customTheme?: {
+        gapPropagation?: NCoreUIKit.GapPropagationKey;
+        sharpness?: NCoreUIKit.SharpnessKey;
+        paletteKey?: NCoreUIKit.PaletteKey;
+        themeKey?: NCoreUIKit.ThemeKey;
+    };
+    onOverlayPress?: (props: {
+        closeAnimation: (onClosed?: (props: {
+            id: string;
+        }) => void) => void;
+    }) => void;
     alignContent?: ModalAlignContentProp;
+    isScaleAnimatedOnlyOpen?: boolean;
     isDisabledOverlay?: boolean;
     isContentRequired?: boolean;
     isOverlayVisible?: boolean;
     isWorkWithPortal?: boolean;
+    isScaleAnimated?: boolean;
     overlayProps?: ViewProps;
     isAnimated?: boolean;
     children?: ReactNode;
+    onClosed?: (props: {
+        id: string;
+    }) => void;
+    portalName?: string;
     isActive?: boolean;
-    customTheme?: {
-        gapPropagation?: NCoreUIKit.GapPropagationKey;
-        sharpness?: NCoreUIKit.SharpnessKey;
-        paletteKey?: NCoreUIKit.PaletteKey;
-        themeKey?: NCoreUIKit.ThemeKey;
-    };
+    id: string;
 };
 
 interface IModalProps extends ModalInternalProps {

+ 8 - 3
src/components/selectBox/index.tsx

@@ -23,7 +23,8 @@ import stylesheet, {
 } from "./stylesheet";
 import {
     NCoreUIKitLocalize,
-    NCoreUIKitTheme
+    NCoreUIKitTheme,
+    NCoreUIKitToast
 } from "../../core/hooks";
 import {
     type INCoreUIKitIconProps,
@@ -420,7 +421,9 @@ function SelectBox<T>({
                 const _minChoice = minChoice === undefined ? 0 : minChoice;
 
                 if(_minChoice > 0) {
-                    // TODO: make toast;
+                    NCoreUIKitToast.open({
+                        title: localize("minimum-a-item-selection-required")
+                    });
                 } else {
                     isProcessPerm = true;
                 }
@@ -442,7 +445,9 @@ function SelectBox<T>({
                 if(_selectedItems.length < maxChoice || maxChoice === -1) {
                     isProcessPerm = true;
                 } else {
-                    // TODO: make toast;
+                    NCoreUIKitToast.open({
+                        title: localize("maximum-selection-limit-has-been-reached")
+                    });
                 }
             } else {
                 _selectedItems = [];

+ 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;

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

@@ -0,0 +1,81 @@
+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;
+};
+
+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
+};

+ 272 - 0
src/components/toast/index.tsx

@@ -0,0 +1,272 @@
+import {
+    useEffect,
+    type FC,
+    useRef
+} from "react";
+import {
+    TouchableWithoutFeedback,
+    Animated,
+    Easing,
+    View
+} from "react-native";
+import type IToastProps from "./type";
+import stylesheet, {
+    getToastType,
+    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";
+
+const Toast: FC<IToastProps> = ({
+    isCloseOnPressActionButton = true,
+    closeAnimationDelay = 350,
+    openAnimationDelay = 200,
+    contentContainerStyle,
+    autoCloseDelay = 3000,
+    isCloseOnPress = true,
+    icon: CustomIcon,
+    type = "neutral",
+    isShowAction,
+    customTheme,
+    onClosed,
+    subTitle,
+    children,
+    action,
+    style,
+    title,
+    id
+}) => {
+    const {
+        radiuses,
+        colors,
+        spaces
+    } = NCoreUIKitTheme.useContext(customTheme);
+
+    const {
+        bottom
+    } = useSafeAreaInsets();
+
+    const TRANSFORM_DISTANCE = 75;
+
+    const transformAnim = useRef(new Animated.Value(TRANSFORM_DISTANCE)).current;
+    const opacityAnim = useRef(new Animated.Value(0)).current;
+
+    const currentType = getToastType({
+        type
+    });
+
+    const {
+        contentContainer: contentContainerDynamicStyle,
+        containerObject: containerObjectDynamicStyle,
+        iconContainer: iconContainerDynamicStyle,
+        container: containerDynamicStyle,
+        subTitle: subTitleDynamicStyle,
+        action: actionDynamicStyle,
+        title: titleDynamicStyle
+    } = useStyles({
+        safeAreaBottom: bottom,
+        currentType,
+        radiuses,
+        subTitle,
+        spaces,
+        colors,
+        type
+    });
+
+    useEffect(() => {
+        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);
+    }, []);
+
+    const closeAnimation = (_onClosed?: (props: {
+        id: string;
+    }) => void) => {
+        Animated.parallel([
+            Animated.timing(transformAnim, {
+                duration: closeAnimationDelay,
+                toValue: TRANSFORM_DISTANCE,
+                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={currentType.iconColor}
+                size={18}
+            />
+        </View>;
+    };
+
+    const renderContent = () => {
+        return <View
+            style={[
+                contentContainerStyle,
+                stylesheet.contentContainer,
+                contentContainerDynamicStyle
+            ]}
+        >
+            <Text
+                color={currentType.titleColor}
+                numberOfLines={3}
+                style={{
+                    ...stylesheet.title,
+                    ...titleDynamicStyle
+                }}
+            >
+                {title}
+            </Text>
+            {
+                subTitle ?
+                    <Text
+                        color={currentType.subTitleColor}
+                        variant="labelSmallSize"
+                        numberOfLines={2}
+                        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={() => {
+                if(action?.title) {
+                    return null;
+                }
+
+                return <XIcon
+                    color={colors.content.text[currentType.actionColor]}
+                    size={18}
+                />;
+            }}
+            style={{
+                ...action?.style,
+                ...actionDynamicStyle
+            }}
+            variant="ghost"
+            size="small"
+            type={type}
+        />;
+    };
+
+    const renderContainer = () => {
+        return <View
+            style={[
+                stylesheet.containerObject,
+                containerObjectDynamicStyle
+            ]}
+        >
+            {renderIcon()}
+            {renderContent()}
+            {renderAction()}
+        </View>;
+    };
+
+    return <Portal name="toast-system">
+        <Animated.View
+            style={[
+                style,
+                stylesheet.container,
+                containerDynamicStyle,
+                {
+                    opacity: opacityAnim,
+                    transform: [{
+                        translateY: transformAnim
+                    }]
+                }
+            ]}
+        >
+            <TouchableWithoutFeedback
+                onPress={() => {
+                    if(isCloseOnPress) {
+                        closeAnimation();
+                    }
+                }}
+            >
+                {children ? children : renderContainer()}
+            </TouchableWithoutFeedback>
+        </Animated.View>
+    </Portal>;
+};
+export default Toast;

+ 156 - 0
src/components/toast/stylesheet.ts

@@ -0,0 +1,156 @@
+import {
+    type TextStyle,
+    type ViewStyle,
+    StyleSheet
+} from "react-native";
+import type {
+    ToastDynamicStyleType,
+    ToastTypeConstantType,
+    ToastTypes,
+    ToastType
+} from "./type";
+import type {
+    Mutable
+} from "../../types";
+import {
+    windowWidth
+} from "../../utils";
+
+export const TOAST_TYPE_STYLES: Record<
+    ToastType,
+    {
+        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 getToastType = ({
+    type
+}: ToastTypeConstantType): ToastTypes => {
+    const currentType = TOAST_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
+    },
+    iconContainer: {
+        justifyContent: "center",
+        alignItems: "center"
+    },
+    title: {
+        textAlign: "left"
+    },
+    subTitle: {
+        textAlign: "left"
+    }
+});
+
+export const useStyles = ({
+    safeAreaBottom,
+    currentType,
+    radiuses,
+    subTitle,
+    colors,
+    spaces
+}: ToastDynamicStyleType) => {
+    const styles = {
+        container: {
+            backgroundColor: colors.content.container[currentType.containerColor],
+            maxWidth: windowWidth - (spaces.spacingMd * 2),
+            bottom: safeAreaBottom + 100,
+            borderRadius: radiuses.full
+        } 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>
+    };
+
+    if(subTitle) {
+        styles.container.borderRadius = radiuses.lg;
+    }
+
+    return styles;
+};
+export default stylesheet;

+ 79 - 0
src/components/toast/type.ts

@@ -0,0 +1,79 @@
+import {
+    type ReactNode
+} from "react";
+import {
+    type StyleProp,
+    type ViewStyle
+} from "react-native";
+import type {
+    NCoreUIKitIcon
+} from "../../types";
+
+export type ToastDynamicStyleType = {
+    radiuses: NCoreUIKit.ActivePalette["radiuses"];
+    spaces: NCoreUIKit.ActivePalette["spaces"];
+    colors: NCoreUIKit.ActivePalette["colors"];
+    currentType: ToastTypes;
+    safeAreaBottom: number;
+    subTitle?: string;
+    type: ToastType;
+};
+
+export type ToastTypes = {
+    containerColor: keyof NCoreUIKit.ContainerContentColors;
+    subTitleColor: keyof NCoreUIKit.TextContentColors;
+    actionColor: keyof NCoreUIKit.TextContentColors;
+    titleColor: keyof NCoreUIKit.TextContentColors;
+    iconColor: keyof NCoreUIKit.IconContentColors;
+};
+
+export type ToastTypeConstantType = {
+    type: ToastType;
+};
+
+export type ToastType = "primary" | "danger" | "warning" | "neutral" | "success" | "info";
+
+export type ToastInternalProps = {
+    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;
+    subTitle?: string;
+    type?: ToastType;
+    title: string;
+    id: string;
+    onClosed?: (props: {
+        id: string;
+    }) => void;
+    customTheme?: {
+        gapPropagation?: NCoreUIKit.GapPropagationKey;
+        sharpness?: NCoreUIKit.SharpnessKey;
+        paletteKey?: NCoreUIKit.PaletteKey;
+        themeKey?: NCoreUIKit.ThemeKey;
+    };
+};
+
+interface IToastProps extends ToastInternalProps {
+};
+
+export type {
+    IToastProps as default
+};

+ 121 - 0
src/context/bottomSheet.tsx

@@ -0,0 +1,121 @@
+import {
+    type ReactNode,
+    Fragment
+} from "react";
+import {
+    type BottomSheetContextType,
+    type BottomSheetDataType
+} from "../types/bottomSheet";
+import NCoreContext, {
+    type ConfigType
+} from "ncore-context";
+import BottomSheet from "../components/bottomSheet";
+import {
+    uuid
+} from "../utils";
+
+class NCoreUIKitBottomSheet extends NCoreContext<BottomSheetContextType, ConfigType<BottomSheetContextType>> {
+    constructor({
+        data = []
+    }: {
+        data?: Array<BottomSheetDataType>
+    }) {
+        super({
+            close: () => {},
+            open: () => "",
+            data: data
+        }, {
+            key: "NCoreUIKit-BottomSheetContext"
+        });
+    };
+
+    open = (dialogData: BottomSheetDataType) => {
+        const currentData = this.state.data;
+
+        const dialogID = dialogData.id ? dialogData.id : uuid();
+
+        currentData.push({
+            ...dialogData,
+            id: dialogID
+        });
+
+        this.setState({
+            data: currentData
+        });
+
+        return dialogID;
+    };
+
+    close = (props?: {
+        index?: number;
+        id?: string;
+    }) => {
+        const currentData = this.state.data;
+
+        if (props && props.id) {
+            const keyIndex = currentData.findIndex((bottomSheet) => bottomSheet.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: BottomSheetDataType) => {
+                return <BottomSheet
+                    key={`NCoreUIKit-BottomSheet-${item.id}`}
+                    id={item.id as string}
+                    isActive={true}
+                    onClosed={() => {
+                        if(item.onClosed) {
+                            item.onClosed({
+                                id: item.id as string
+                            });
+                        }
+
+                        if(item.isAutoClosed === undefined || item.isAutoClosed === true) {
+                            this.close({
+                                id: item.id
+                            });
+                        }
+                    }}
+                    {...item}
+                />;
+            })}
+        </Fragment>;
+    };
+}
+export default NCoreUIKitBottomSheet;

+ 120 - 0
src/context/dialog.tsx

@@ -0,0 +1,120 @@
+import {
+    type ReactNode,
+    Fragment
+} from "react";
+import {
+    type DialogContextType,
+    type DialogDataType
+} from "../types/dialog";
+import NCoreContext, {
+    type ConfigType
+} from "ncore-context";
+import Dialog from "../components/dialog";
+import {
+    uuid
+} from "../utils";
+
+class NCoreUIKitDialog extends NCoreContext<DialogContextType, ConfigType<DialogContextType>> {
+    constructor({
+        data = []
+    }: {
+        data?: Array<DialogDataType>
+    }) {
+        super({
+            close: () => {},
+            open: () => "",
+            data: data
+        }, {
+            key: "NCoreUIKit-DialogContext"
+        });
+    };
+
+    open = (dialogData: DialogDataType) => {
+        const currentData = this.state.data;
+
+        const dialogID = dialogData.id ? dialogData.id : uuid();
+
+        currentData.push({
+            ...dialogData,
+            id: dialogID
+        });
+
+        this.setState({
+            data: currentData
+        });
+
+        return dialogID;
+    };
+
+    close = (props?: {
+        index?: number;
+        id?: string;
+    }) => {
+        const currentData = this.state.data;
+
+        if (props && props.id) {
+            const keyIndex = currentData.findIndex((dialog) => dialog.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: DialogDataType) => {
+                return <Dialog
+                    key={`NCoreUIKit-Dialog-${item.id}`}
+                    id={item.id as string}
+                    onClosed={() => {
+                        if(item.onClosed) {
+                            item.onClosed({
+                                id: item.id as string
+                            });
+                        }
+
+                        if(item.isAutoClosed === undefined || item.isAutoClosed === true) {
+                            this.close({
+                                id: item.id
+                            });
+                        }
+                    }}
+                    {...item}
+                />;
+            })}
+        </Fragment>;
+    };
+}
+export default NCoreUIKitDialog;

+ 60 - 5
src/context/index.tsx

@@ -1,17 +1,28 @@
 import {
     type ReactNode
 } from "react";
+import NCoreUIKitBottomSheet from "./bottomSheet";
+import NCoreUIKitDialog from "./dialog";
 import NCoreUIKitLocalize from "./localize";
 import NCoreUIKitModal from "./modal";
+import NCoreUIKitSnackBar from "./snackBar";
 import NCoreUIKitTheme from "./theme";
+import NCoreUIKitToast from "./toast";
 import {
     type NCoreUIKitConfig
 } from "../types";
+import {
+    Host
+} from "../helpers/portalize";
 
 class CoreContext<T extends NCoreUIKitConfig> {
+    NCoreUIKitBottomSheet: NCoreUIKitBottomSheet;
     NCoreUIKitLocalize: NCoreUIKitLocalize<T>;
+    NCoreUIKitSnackBar: NCoreUIKitSnackBar;
     NCoreUIKitTheme: NCoreUIKitTheme<T>;
+    NCoreUIKitDialog: NCoreUIKitDialog;
     NCoreUIKitModal: NCoreUIKitModal;
+    NCoreUIKitToast: NCoreUIKitToast;
 
     constructor(initialState: T) {
         this.NCoreUIKitTheme = new NCoreUIKitTheme({
@@ -30,6 +41,22 @@ class CoreContext<T extends NCoreUIKitConfig> {
         this.NCoreUIKitModal = new NCoreUIKitModal({
             data: []
         });
+
+        this.NCoreUIKitToast = new NCoreUIKitToast({
+            data: []
+        });
+
+        this.NCoreUIKitSnackBar = new NCoreUIKitSnackBar({
+            data: []
+        });
+
+        this.NCoreUIKitDialog = new NCoreUIKitDialog({
+            data: []
+        });
+
+        this.NCoreUIKitBottomSheet = new NCoreUIKitBottomSheet({
+            data: []
+        });
     }
 
     Provider = ({
@@ -37,17 +64,45 @@ class CoreContext<T extends NCoreUIKitConfig> {
     }: {
         children: ReactNode
     }) => {
+        const BottomSheetContext = this.NCoreUIKitBottomSheet;
         const LocalizeContext = this.NCoreUIKitLocalize;
+        const SnackBarContext = this.NCoreUIKitSnackBar;
+        const DialogContext = this.NCoreUIKitDialog;
         const ModalContext = this.NCoreUIKitModal;
+        const ToastContext = this.NCoreUIKitToast;
         const ThemeContext = this.NCoreUIKitTheme;
 
         return <ThemeContext.Provider>
             <LocalizeContext.Provider>
-                <ModalContext.Provider>
-                    <ModalContext.Render>
-                        {children}
-                    </ModalContext.Render>
-                </ModalContext.Provider>
+                <Host name="snack-bar-system">
+                    <SnackBarContext.Provider>
+                        <SnackBarContext.Render>
+                            <Host name="toast-system">
+                                <Host name="modal-system">
+                                    <ModalContext.Provider>
+                                        <ModalContext.Render>
+                                            <DialogContext.Provider>
+                                                <DialogContext.Render>
+                                                    <ToastContext.Provider>
+                                                        <ToastContext.Render>
+                                                            <Host name="bottomSheet-system">
+                                                                <BottomSheetContext.Provider>
+                                                                    <BottomSheetContext.Render>
+                                                                        {children}
+                                                                    </BottomSheetContext.Render>
+                                                                </BottomSheetContext.Provider>
+                                                            </Host>
+                                                        </ToastContext.Render>
+                                                    </ToastContext.Provider>
+                                                </DialogContext.Render>
+                                            </DialogContext.Provider>
+                                        </ModalContext.Render>
+                                    </ModalContext.Provider>
+                                </Host>
+                            </Host>
+                        </SnackBarContext.Render>
+                    </SnackBarContext.Provider>
+                </Host>
             </LocalizeContext.Provider>
         </ThemeContext.Provider>;
     };

+ 25 - 15
src/context/modal.tsx

@@ -9,10 +9,10 @@ import {
 import NCoreContext, {
     type ConfigType
 } from "ncore-context";
-import {
-    Host
-} from "react-native-portalize";
 import Modal from "../components/modal";
+import {
+    uuid
+} from "../utils";
 
 class NCoreUIKitModal extends NCoreContext<ModalContextType, ConfigType<ModalContextType>> {
     constructor({
@@ -32,7 +32,12 @@ class NCoreUIKitModal extends NCoreContext<ModalContextType, ConfigType<ModalCon
     open = (modalData: ModalDataType) => {
         const currentData = this.state.data;
 
-        currentData.push(modalData);
+        const modalID = modalData.id ? modalData.id : uuid();
+
+        currentData.push({
+            ...modalData,
+            id: modalID
+        });
 
         this.setState({
             data: currentData
@@ -86,20 +91,25 @@ class NCoreUIKitModal extends NCoreContext<ModalContextType, ConfigType<ModalCon
         } = this.useContext();
 
         return <Fragment>
-            <Host>
-                {children}
-                {data.map((item: ModalDataType) => {
-                    return <Modal
-                        key={`NCoreUIKit-Modal-${item.id}`}
-                        onOverlayPress={item.onOverlayPress ? item.onOverlayPress : () => {
+            {children}
+            {data.map((item: ModalDataType) => {
+                return <Modal
+                    key={`NCoreUIKit-Modal-${item.id}`}
+                    id={item.id as string}
+                    onClosed={() => {
+                        if(item.onClosed) item.onClosed({
+                            id: item.id as string
+                        });
+
+                        if(item.isAutoClose === undefined || item.isAutoClose === true) {
                             this.close({
                                 id: item.id
                             });
-                        }}
-                        {...item}
-                    />;
-                })}
-            </Host>
+                        }
+                    }}
+                    {...item}
+                />;
+            })}
         </Fragment>;
     };
 }

+ 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;

+ 114 - 0
src/context/toast.tsx

@@ -0,0 +1,114 @@
+import {
+    type ReactNode,
+    Fragment
+} from "react";
+import {
+    type ToastContextType,
+    type ToastDataType
+} from "../types/toast";
+import NCoreContext, {
+    type ConfigType
+} from "ncore-context";
+import Toast from "../components/toast";
+import {
+    uuid
+} from "../utils";
+
+class NCoreUIKitToast extends NCoreContext<ToastContextType, ConfigType<ToastContextType>> {
+    constructor({
+        data = []
+    }: {
+        data?: Array<ToastDataType>
+    }) {
+        super({
+            close: () => {},
+            open: () => "",
+            data: data
+        }, {
+            key: "NCoreUIKit-ToastContext"
+        });
+    };
+
+    open = (toastData: ToastDataType) => {
+        const currentData = this.state.data;
+
+        const toastID = toastData.id ? toastData.id : uuid();
+
+        currentData.push({
+            ...toastData,
+            id: toastID
+        });
+
+        this.setState({
+            data: currentData
+        });
+
+        return toastID;
+    };
+
+    close = (props?: {
+        index?: number;
+        id?: string;
+    }) => {
+        const currentData = this.state.data;
+
+        if (props && props.id) {
+            const keyIndex = currentData.findIndex((toast) => toast.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: ToastDataType) => {
+                return <Toast
+                    key={`NCoreUIKit-Toast-${item.id}`}
+                    {...item}
+                    id={item.id as string}
+                    onClosed={(props) => {
+                        this.close({
+                            id: item.id
+                        });
+
+                        if(item.onClosed) item.onClosed(props);
+                    }}
+                />;
+            })}
+        </Fragment>;
+    };
+}
+export default NCoreUIKitToast;

+ 12 - 0
src/core/hooks.ts

@@ -6,16 +6,28 @@ import type {
     LocalizeType,
     ThemesType
 } from "../types";
+import type NCoreUIKitBottomSheetClass from "../context/bottomSheet";
 import type NCoreUIKitLocalizeClass from "../context/localize";
+import type NCoreUIKitSnackBarClass from "../context/snackBar";
+import type NCoreUIKitDialogClass from "../context/dialog";
 import type NCoreUIKitModalClass from "../context/modal";
+import type NCoreUIKitToastClass from "../context/toast";
 import type NCoreUIKitThemeClass from "../context/theme";
 
+export let NCoreUIKitBottomSheet: NCoreUIKitBottomSheetClass;
 export let NCoreUIKitLocalize: NCoreUIKitLocalizeClass<LocalizeType>;
 export let NCoreUIKitTheme: NCoreUIKitThemeClass<ThemesType>;
+export let NCoreUIKitSnackBar: NCoreUIKitSnackBarClass;
+export let NCoreUIKitDialog: NCoreUIKitDialogClass;
 export let NCoreUIKitModal: NCoreUIKitModalClass;
+export let NCoreUIKitToast: NCoreUIKitToastClass;
 
 export const initializeInstances = (NCoreUIKit: NCoreUIKitBase<NCoreUIKitConfig>) => {
+    NCoreUIKitBottomSheet = NCoreUIKit.NCoreUIKitContext.NCoreUIKitBottomSheet;
     NCoreUIKitLocalize = NCoreUIKit.NCoreUIKitContext.NCoreUIKitLocalize;
+    NCoreUIKitSnackBar = NCoreUIKit.NCoreUIKitContext.NCoreUIKitSnackBar;
+    NCoreUIKitDialog = NCoreUIKit.NCoreUIKitContext.NCoreUIKitDialog;
     NCoreUIKitTheme = NCoreUIKit.NCoreUIKitContext.NCoreUIKitTheme;
     NCoreUIKitModal = NCoreUIKit.NCoreUIKitContext.NCoreUIKitModal;
+    NCoreUIKitToast = NCoreUIKit.NCoreUIKitContext.NCoreUIKitToast;
 };

+ 4 - 4
src/core/index.tsx

@@ -29,11 +29,11 @@ export class NCoreUIKitBase<T extends NCoreUIKitConfig> {
     }) => {
         const NCoreUIKitContext = this.NCoreUIKitContext;
 
-        return <NCoreUIKitContext.Provider>
-            <SafeAreaProvider>
+        return <SafeAreaProvider>
+            <NCoreUIKitContext.Provider>
                 {children}
-            </SafeAreaProvider>
-        </NCoreUIKitContext.Provider>;
+            </NCoreUIKitContext.Provider>
+        </SafeAreaProvider>;
     };
 };
 

+ 53 - 0
src/helpers/portalize/Consumer.tsx

@@ -0,0 +1,53 @@
+import {
+    type ReactNode,
+    useEffect,
+    useRef
+} from "react";
+import {
+    type IProvider
+} from "./Host";
+
+interface IConsumerProps {
+    manager: IProvider | null;
+    children: ReactNode;
+    name?: string;
+};
+
+export const Consumer = ({
+    children,
+    manager,
+    name
+}: IConsumerProps): null => {
+    const key = useRef<string | undefined>(undefined);
+
+    const checkManager = (): void => {
+        if (!manager) {
+            throw new Error("No portal manager defined");
+        }
+    };
+
+    const handleInit = (): void => {
+        checkManager();
+        key.current = manager?.mount(children, name);
+    };
+
+    useEffect(() => {
+        checkManager();
+        manager?.update(key.current, children, name);
+    }, [
+        children,
+        manager,
+        name
+    ]);
+
+    useEffect(() => {
+        handleInit();
+
+        return (): void => {
+            checkManager();
+            manager?.unmount(key.current);
+        };
+    }, []);
+
+    return null;
+};

+ 122 - 0
src/helpers/portalize/Host.tsx

@@ -0,0 +1,122 @@
+import {
+    type ReactNode,
+    createContext,
+    useEffect,
+    useRef
+} from "react";
+import {
+    type ViewStyle,
+    View
+} from "react-native";
+import {
+    useKey
+} from "./hooks/useKey";
+import {
+    type IManagerHandles,
+    Manager
+} from "./Manager";
+import {
+    context
+} from "./context";
+
+interface IHostProps {
+    children: ReactNode;
+    style?: ViewStyle;
+    name?: string;
+}
+
+export interface IProvider {
+    update(key?: string, children?: ReactNode, name?: string): void;
+    mount(children: ReactNode, name?: string): string;
+    unmount(key?: string): void;
+    name?: string;
+}
+
+export const Context = createContext<IProvider | null>(null);
+
+export const Host = ({
+    children,
+    style,
+    name
+}: IHostProps): ReactNode => {
+    const managerRef = useRef<IManagerHandles>(null);
+
+    const queue: Array<{
+        type: "mount" | "update" | "unmount";
+        children?: ReactNode;
+        name?: string;
+        key: string;
+    }> = [];
+
+    const {
+        generateKey,
+        removeKey
+    } = useKey();
+
+    useEffect(() => {
+        while (queue.length && managerRef.current) {
+            const action = queue.pop();
+
+            if (action) {
+                switch (action.type) {
+                    case "mount":
+                        managerRef.current?.mount(action.key, action.children, action.name);
+                        break;
+                    case "update":
+                        managerRef.current?.update(action.key, action.children, action.name);
+                        break;
+                    case "unmount":
+                        managerRef.current?.unmount(action.key);
+                        break;
+                }
+            }
+        }
+    }, []);
+
+    const mount = (children: ReactNode, _name?: string): string => {
+        const key = generateKey();
+
+        const targetName = _name ?? name;
+
+        context.mount(key, children, targetName);
+
+        return key;
+    };
+
+    const update = (key: string, children: ReactNode, _name?: string): void => {
+        const targetName = _name ?? name;
+
+        context.update(key, children, targetName);
+    };
+
+    const unmount = (key: string): void => {
+        context.unmount(key);
+
+        removeKey(key);
+    };
+
+    return <Context.Provider value={{
+        unmount,
+        update,
+        mount,
+        name
+    }}>
+        <View
+            pointerEvents="box-none"
+            collapsable={false}
+            style={[
+                {
+                    flex: 1
+                },
+                style
+            ]}
+        >
+            {children}
+        </View>
+
+        <Manager
+            ref={managerRef}
+            name={name}
+        />
+    </Context.Provider>;
+};

+ 75 - 0
src/helpers/portalize/Manager.tsx

@@ -0,0 +1,75 @@
+import {
+    useImperativeHandle,
+    type ReactNode,
+    forwardRef,
+    useEffect,
+    useState
+} from "react";
+import {
+    StyleSheet,
+    View
+} from "react-native";
+import {
+    context
+} from "./context";
+
+export interface IManagerHandles {
+    update(key?: string, children?: ReactNode, name?: string): void;
+    mount(key: string, children: ReactNode, name?: string): void;
+    unmount(key?: string): void;
+}
+
+export const Manager = forwardRef(({
+    name
+}: {
+    name?: string;
+}, ref): Array<ReactNode> => {
+    const [
+        portals,
+        setPortals
+    ] = useState<Array<{
+        children: ReactNode;
+        name?: string;
+        key: string;
+    }>>([]);
+
+    useEffect(() => {
+        return context.subscribe((newPortals) => {
+            setPortals(newPortals);
+        });
+    }, []);
+
+    useImperativeHandle(
+        ref,
+        (): IManagerHandles => ({
+            unmount: context.unmount,
+            update: context.update,
+            mount: context.mount
+        }),
+    );
+
+    return portals
+        .filter(item => {
+            if (item.name) {
+                return item.name === name;
+            }
+
+            return !name;
+        })
+        .map((
+            {
+                children,
+                key
+            },
+            index: number
+        ) => (
+            <View
+                key={`NCoreUIKit-Portal-${key}-${index}`}
+                style={StyleSheet.absoluteFill}
+                pointerEvents="box-none"
+                collapsable={false}
+            >
+                {children}
+            </View>
+        ));
+});

+ 30 - 0
src/helpers/portalize/Portal.tsx

@@ -0,0 +1,30 @@
+import {
+    type ReactNode
+} from "react";
+import {
+    Consumer
+} from "./Consumer";
+import {
+    Context
+} from "./Host";
+
+interface IPortalProps {
+    children: ReactNode;
+    name?: string;
+}
+
+export const Portal = ({
+    children,
+    name
+}: IPortalProps): ReactNode => (
+    <Context.Consumer>
+        {(manager): ReactNode => {
+            return <Consumer
+                manager={manager}
+                name={name}
+            >
+                {children}
+            </Consumer>;
+        }}
+    </Context.Consumer>
+);

+ 49 - 0
src/helpers/portalize/context/index.ts

@@ -0,0 +1,49 @@
+import type {
+    ReactNode
+} from "react";
+
+type PortalItem = {
+    children: ReactNode;
+    name?: string;
+    key: string;
+};
+
+let portals: PortalItem[] = [];
+
+const listeners: Array<(portals: PortalItem[]) => void> = [];
+
+export const context = {
+    subscribe: (listener: (portals: PortalItem[]) => void) => {
+        listeners.push(listener);
+
+        return () => {
+            listeners.splice(listeners.indexOf(listener), 1);
+        };
+    },
+    mount: (key: string, children: ReactNode, name?: string) => {
+        portals = [
+            ...portals,
+            {
+                children,
+                name,
+                key
+            }
+        ];
+
+        listeners.forEach(l => l(portals));
+    },
+    update: (key: string, children: ReactNode, name?: string) => {
+        portals = portals.map(p => p.key === key ? {
+            ...p,
+            children,
+            name
+        } : p);
+
+        listeners.forEach(l => l(portals));
+    },
+    unmount: (key: string) => {
+        portals = portals.filter(p => p.key !== key);
+
+        listeners.forEach(l => l(portals));
+    }
+};

+ 49 - 0
src/helpers/portalize/hooks/useKey.ts

@@ -0,0 +1,49 @@
+import {
+    useRef
+} from "react";
+
+interface IUseKey {
+    removeKey(key: string): void;
+    generateKey(): string;
+}
+
+const keyGenerator = (): string => {
+    return `portalize_${Math.random().toString(36).substr(2, 16)}-${Math.random()
+        .toString(36)
+        .substr(2, 16)}-${Math.random().toString(36).substr(2, 16)}`;
+};
+
+export const useKey = (): IUseKey => {
+    const usedKeys = useRef<Array<string>>([]);
+
+    const generateKey = (): string => {
+        let foundUniqueKey = false;
+        let newKey = "";
+        let tries = 0;
+
+        while (!foundUniqueKey && tries < 3) {
+            tries++;
+            newKey = keyGenerator();
+
+            if (!usedKeys.current.includes(newKey)) {
+                foundUniqueKey = true;
+            }
+        }
+
+        if (!foundUniqueKey) {
+            newKey = `portalize_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
+        }
+
+        usedKeys.current.push(newKey);
+        return newKey;
+    };
+
+    const removeKey = (key: string): void => {
+        usedKeys.current = usedKeys.current.filter(k => k !== key);
+    };
+
+    return {
+        generateKey,
+        removeKey
+    };
+};

+ 15 - 0
src/helpers/portalize/index.tsx

@@ -0,0 +1,15 @@
+export {
+    Consumer
+} from "./Consumer";
+
+export {
+    Host
+} from "./Host";
+
+export {
+    Manager
+} from "./Manager";
+
+export {
+    Portal
+} from "./Portal";

+ 15 - 4
src/index.tsx

@@ -4,9 +4,13 @@ export {
 } from "./core";
 
 export {
+    NCoreUIKitBottomSheet,
     NCoreUIKitLocalize,
+    NCoreUIKitSnackBar,
+    NCoreUIKitDialog,
     NCoreUIKitModal,
-    NCoreUIKitTheme
+    NCoreUIKitTheme,
+    NCoreUIKitToast
 } from "./core/hooks";
 
 export {
@@ -17,15 +21,16 @@ export {
     SelectBox,
     CheckBox,
     Loading,
-    // Dialog,
+    Dialog,
     Button,
     Modal,
+    Toast,
     Text
 } from "./components";
 
 export type {
     IBottomSheetRef,
-    // IDialogRef,
+    IDialogRef,
     IModalRef
 } from "./components";
 
@@ -49,5 +54,11 @@ export type {
     ThemesType,
     LocaleType,
     ThemeType,
-    ModalType
+    ModalType,
+    Mutable
 } from "./types";
+
+export {
+    Portal,
+    Host
+} from "./helpers/portalize";

+ 23 - 0
src/types/bottomSheet.ts

@@ -0,0 +1,23 @@
+import type IBottomSheetProps from "../components/bottomSheet/type";
+
+export type BottomSheetType = {
+    data?: Array<BottomSheetDataType>;
+};
+
+export type BottomSheetDataType = Omit<IBottomSheetProps, "id"> & {
+    isAutoClosed?: boolean;
+    id?: string;
+};
+
+export type BottomSheetContextType = {
+    open: (dialogData: BottomSheetDataType) => string;
+    close: (props?: {
+        index?: number;
+        id?: string;
+    }) => void;
+    data: Array<BottomSheetDataType>;
+};
+
+export type BottomSheetStateContextType = {
+    data: Array<BottomSheetDataType>;
+};

+ 23 - 0
src/types/dialog.ts

@@ -0,0 +1,23 @@
+import type IDialogProps from "../components/dialog/type";
+
+export type DialogType = {
+    data?: Array<DialogDataType>;
+};
+
+export type DialogDataType = Omit<IDialogProps, "id"> & {
+    isAutoClosed?: boolean;
+    id?: string;
+};
+
+export type DialogContextType = {
+    open: (dialogData: DialogDataType) => string;
+    close: (props?: {
+        index?: number;
+        id?: string;
+    }) => void;
+    data: Array<DialogDataType>;
+};
+
+export type DialogStateContextType = {
+    data: Array<DialogDataType>;
+};

+ 3 - 2
src/types/modal.ts

@@ -6,8 +6,9 @@ export type ModalType = {
     data?: Array<ModalDataType>;
 };
 
-export type ModalDataType = ModalInternalProps & {
-    id: string;
+export type ModalDataType = Omit<ModalInternalProps, "id"> & {
+    isAutoClose?: boolean;
+    id?: string;
 };
 
 export type ModalContextType = {

+ 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>;
+};

+ 24 - 0
src/types/toast.ts

@@ -0,0 +1,24 @@
+import {
+    type ToastInternalProps
+} from "../components/toast/type";
+
+export type ToastType = {
+    data?: Array<ToastDataType>;
+};
+
+export type ToastDataType = Omit<ToastInternalProps, "id"> & {
+    id?: string;
+};
+
+export type ToastContextType = {
+    open: (toastData: ToastDataType) => string;
+    close: (props?: {
+        index?: number;
+        id?: string;
+    }) => void;
+    data: Array<ToastDataType>;
+};
+
+export type ToastStateContextType = {
+    data: Array<ToastDataType>;
+};

+ 12 - 8
src/variants/locales/default.json

@@ -3,11 +3,13 @@
         "locale": "tr-TR",
         "isRTL": false,
         "translations": {
-            "selected-options-with-count": "{{0}} items selected",
-            "select-an-option": "Select an option",
-            "select-all": "Select All",
+            "maximum-selection-limit-has-been-reached": "Maksimum seçim limitine ulaşıldı.",
+            "minimum-a-item-selection-required": "Minimum 1 öğe seçimi gereklidir.",
+            "selected-options-with-count": "{{0}} seçim yapıldı",
+            "select-an-option": "Seçim yapın",
+            "clean-all": "Tümünü Temizle",
+            "select-all": "Tümünü Seç",
             "is-optional": "Opsiyonel",
-            "clean-all": "Clean All",
             "cancel": "İptal",
             "search": "Ara",
             "ok": "Tamam"
@@ -17,11 +19,13 @@
         "locale": "en-US",
         "isRTL": false,
         "translations": {
-            "selected-options-with-count": "{{0}} seçim yapıldı",
-            "select-an-option": "Seçim yapın",
-            "clean-all": "Tümünü Temizle",
-            "select-all": "Tümünü Seç",
+            "maximum-selection-limit-has-been-reached": "Maximum selection limit has been reached.",
+            "minimum-a-item-selection-required": "Minimum 1 item selection required.",
+            "selected-options-with-count": "{{0}} items selected",
+            "select-an-option": "Select an option",
+            "select-all": "Select All",
             "is-optional": "Optional",
+            "clean-all": "Clean All",
             "cancel": "Cancel",
             "search": "Search",
             "ok": "Okey"

+ 0 - 13
yarn.lock

@@ -13187,7 +13187,6 @@ __metadata:
     react-native: "npm:0.83.2"
     react-native-builder-bob: "npm:0.40.13"
     react-native-monorepo-config: "npm:0.3.3"
-    react-native-portalize: "npm:^1.0.7"
     react-native-safe-area-context: "npm:^5.7.0"
     react-native-screens: "npm:^4.24.0"
     react-native-svg: "npm:^15.15.3"
@@ -13224,7 +13223,6 @@ __metadata:
     react: "npm:19.2.0"
     react-native: "npm:0.83.2"
     react-native-builder-bob: "npm:0.40.13"
-    react-native-portalize: "npm:1.0.7"
     react-native-safe-area-context: "npm:5.7.0"
     react-native-svg: "npm:15.15.3"
     release-it: "npm:19.0.4"
@@ -13236,7 +13234,6 @@ __metadata:
     ncore-context: ">= 1.0.5"
     react: "*"
     react-native: "*"
-    react-native-portalize: ">= 1.0.7"
     react-native-safe-area-context: ">= 5.7.0"
     react-native-svg: ">= 15.15.3"
   languageName: unknown
@@ -14787,16 +14784,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"react-native-portalize@npm:1.0.7, react-native-portalize@npm:^1.0.7":
-  version: 1.0.7
-  resolution: "react-native-portalize@npm:1.0.7"
-  peerDependencies:
-    react: "> 15.0.0"
-    react-native: "> 0.50.0"
-  checksum: 10c0/17ba66a92e5d73b9341a5a748219801ae1ebe110003fc640bb44df8661f579a292b8d5521b0b481ee1281ed66d9d554398d42bb4e84827137455ab980d143aec
-  languageName: node
-  linkType: hard
-
 "react-native-safe-area-context@npm:5.7.0, react-native-safe-area-context@npm:^5.7.0":
   version: 5.7.0
   resolution: "react-native-safe-area-context@npm:5.7.0"