浏览代码

Merge branch 'devleop' of nibgat-community/ncore-ui-kit-mobile into main

Furkan Atakan BOZKURT 2 月之前
父节点
当前提交
da674163fc

+ 8 - 1
example/src/index.tsx

@@ -5,6 +5,7 @@ import {
 import {
     setupNCoreUIKit,
     NCoreUIKitTheme,
+    TextInput,
     Button,
     Text
 } from "ncore-ui-kit-mobile";
@@ -31,12 +32,18 @@ const App = () => {
         ]}
     >
         <Text>Result: </Text>
+        <TextInput
+            title="Bi dene daha bombe."
+            initialValue="dsfsdfdsf"
+            hintText="asfasfasf"
+            isDisabled={false}
+        />
         <Button
             onPress={() => {
             }}
             type="success"
             title="Ahmet"
-            variant="ghost"
+            variant="filled"
         />
     </View>;
 };

+ 3 - 2
package.json

@@ -70,11 +70,12 @@
     "devDependencies": {
         "@react-native/babel-preset": "0.83.0",
         "@release-it/conventional-changelog": "10.0.1",
-        "@types/copyfiles": "^2",
+        "@types/copyfiles": "2",
         "@types/eslint-plugin-jsx-a11y": "6",
         "@types/react": "19.2.14",
+        "@types/react-native": "0.73.0",
         "babel-plugin-module-resolver": "5.0.2",
-        "copyfiles": "^2.4.1",
+        "copyfiles": "2.4.1",
         "del-cli": "6.0.0",
         "eslint": "9.37.0",
         "eslint-import-resolver-typescript": "4.4.4",

+ 3 - 1
src/components/button/index.tsx

@@ -40,7 +40,8 @@ const Button: FC<IButtonProps> = ({
     isLoading,
     onPress,
     title,
-    style
+    style,
+    ...props
 }) => {
     const {
         typography,
@@ -168,6 +169,7 @@ const Button: FC<IButtonProps> = ({
 
     return (
         <TouchableOpacity
+            {...props}
             onPress={isDisabled || isLoading ? () => null : onPress}
             disabled={isDisabled || isLoading}
             style={[

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

@@ -1,4 +1,5 @@
 import {
+    type ButtonProps,
     type ViewStyle,
     type StyleProp,
     type TextStyle
@@ -76,7 +77,7 @@ export type ButtonVariant = "filled" | "outline" | "ghost";
 
 export type ButtonSize = "small" | "medium" | "large";
 
-interface IButtonProps {
+interface IButtonProps extends Omit<ButtonProps, "title"> {
     displayBehaviourWhileLoading?: ButtonDisplayBehaviourWhileLoading;
     titleStyle?: StyleProp<TextStyle>[] | StyleProp<TextStyle>;
     style?: StyleProp<ViewStyle>[] | StyleProp<ViewStyle>;

+ 7 - 2
src/components/index.ts

@@ -5,6 +5,11 @@ export {
 export {
     default as Button
 } from "./button";
+
+export {
+    default as PageContainer
+} from "./pageContainer";
+
 /*
 export {
     default as Dialog
@@ -25,11 +30,11 @@ export type {
 export {
     default as Loading
 } from "./loading";
-/*
+
 export {
     default as TextInput
 } from "./textInput";
-
+/*
 export {
     default as SelectBox
 } from "./selectBox";

+ 82 - 0
src/components/pageContainer/index.tsx

@@ -0,0 +1,82 @@
+import {
+    type FC
+} from "react";
+import {
+    ScrollView,
+    View
+} from "react-native";
+import type IPageContainerProps from "./type";
+import stylesheet from "./stylesheet";
+import {
+    NCoreUIKitTheme
+} from "../../core/hooks";
+
+const PageContainer: FC<IPageContainerProps> = ({
+    backgroundColor = "default" as keyof NCoreUIKit.ContainerContentColors,
+    isScrollable = false,
+    scrollViewStyle,
+    scrollViewProps,
+    children,
+    style,
+    ...props
+}) => {
+    const {
+        spaces
+    } = NCoreUIKitTheme.useContext();
+
+    const renderScrollview = () => {
+        if(style) {
+            console.log("Hey!. You make wrong things. If you must be use isScrollable={true}, you must be use scrollViewStyle. Do not use style prop for this case.");
+        }
+
+        if(props) {
+            console.log("Hey!. You make wrong things. If you must be use isScrollable={true}, you must be use scrollViewProps. Do not use default view props for this case.");
+        }
+
+        return <ScrollView
+            {...scrollViewProps}
+            contentContainerStyle={[
+                {
+                    padding: spaces.spacingMd
+                },
+                scrollViewProps?.contentContainerStyle
+            ]}
+            style={[
+                {
+                    backgroundColor: backgroundColor
+                },
+                stylesheet.container,
+                scrollViewStyle
+            ]}
+        >
+            {children}
+        </ScrollView>;
+    };
+
+    const renderView = () => {
+        if(scrollViewStyle) {
+            console.log("Hey!. You make wrong things. If you must be use isScrollable={false}, you must be use style. Do not use scrollViewStyle prop for this case.");
+        }
+
+        if(scrollViewProps) {
+            console.log("Hey!. You make wrong things. If you must be use isScrollable={false}, you musn't use scrollViewProps.");
+        }
+
+        return <View
+            {...props}
+            style={[
+                {
+                    backgroundColor: backgroundColor,
+                    padding: spaces.spacingMd
+                },
+                stylesheet.container,
+                style
+            ]}
+        >
+            {children}
+        </View>;
+    };
+
+    return isScrollable ? renderScrollview() : renderView();
+};
+export default PageContainer;

+ 10 - 0
src/components/pageContainer/stylesheet.ts

@@ -0,0 +1,10 @@
+import {
+    StyleSheet
+} from "react-native";
+
+const stylesheet = StyleSheet.create({
+    container: {
+        flex: 1
+    }
+});
+export default stylesheet;

+ 20 - 0
src/components/pageContainer/type.ts

@@ -0,0 +1,20 @@
+import {
+    type ReactNode
+} from "react";
+import type {
+    ScrollViewProps,
+    StyleProp,
+    ViewStyle
+} from "react-native";
+
+interface IPageContainerProps {
+    backgroundColor?: keyof NCoreUIKit.ContainerContentColors;
+    scrollViewStyle?: StyleProp<ScrollViewProps["style"]>;
+    scrollViewProps?: ScrollViewProps;
+    style?: StyleProp<ViewStyle>;
+    isScrollable?: boolean;
+    children?: ReactNode;
+}
+export type {
+    IPageContainerProps as default
+};

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

@@ -2,11 +2,12 @@ import {
     type ReactNode
 } from "react";
 import {
+    type TextProps,
     type TextStyle,
     type StyleProp
 } from "react-native";
 
-interface ITextProps {
+interface ITextProps extends TextProps {
     style?: StyleProp<TextStyle>[] | StyleProp<TextStyle>;
     color?: keyof NCoreUIKit.TextContentColors;
     variant?: keyof NCoreUIKit.Typography;

+ 504 - 0
src/components/textInput/index.tsx

@@ -0,0 +1,504 @@
+import {
+    useImperativeHandle,
+    forwardRef,
+    useState,
+    useRef
+} from "react";
+import {
+    TextInput as NativeTextInput,
+    TouchableOpacity,
+    View
+} from "react-native";
+import type ITextInputProps from "./type";
+import {
+    type TextInputInstance,
+    type ITextInputRef,
+    type TextInputType
+} from "./type";
+import stylesheet, {
+    getTextInputType,
+    useStyles
+} from "./stylesheet";
+import {
+    NCoreUIKitLocalize,
+    NCoreUIKitTheme
+} from "../../core/hooks";
+import {
+    type RefForwardingComponent,
+    type INCoreUIKitIconProps,
+    type NCoreUIKitIcon
+} from "../../types";
+import type ITextProps from "../text/type";
+import {
+    BadgeQuestionMarkIcon,
+    BadgeSuccessIcon,
+    BadgeDangerIcon,
+    BadgeAlertIcon,
+    BadgeInfoIcon,
+    EyeOpenedIcon,
+    EyeClosedIcon,
+    CleanIcon
+} from "../../assets/svg";
+import Text from "../text";
+
+const TextInputTypeIcon: Record<Exclude<TextInputType, "default">, NCoreUIKitIcon> = {
+    "question": BadgeQuestionMarkIcon,
+    "success": BadgeSuccessIcon,
+    "warning": BadgeAlertIcon,
+    "danger": BadgeDangerIcon,
+    "info": BadgeInfoIcon
+};
+
+const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
+    rightIcon: RightIconComponentProp,
+    hintTextIcon: HintTextIconProp,
+    spreadBehaviour = "baseline",
+    isShowHideTextButton = true,
+    icon: IconComponentProp,
+    hintTextContainerStyle,
+    isCleanEnabled = false,
+    contentContainerStyle,
+    subTitle = "Optional",
+    onFocus: onFocusProp,
+    isRequired = false,
+    isDisabled = false,
+    onBlur: onBlurProp,
+    hideTextIconStyle,
+    variant = "text",
+    type = "default",
+    rightIconOnPress,
+    rightIconStyle,
+    isShowSubTitle,
+    cleanIconStyle,
+    onChangeText,
+    initialValue,
+    placeholder,
+    iconOnPress,
+    isOptional,
+    validation,
+    inputStyle,
+    iconStyle,
+    hintText,
+    style,
+    title,
+    ...props
+}, ref) => {
+    const {
+        inlineSpaces,
+        typography,
+        radiuses,
+        borders,
+        spaces,
+        colors
+    } = NCoreUIKitTheme.useContext();
+
+    const {
+        localize
+    } = NCoreUIKitLocalize.useContext();
+
+    const currentType = getTextInputType({
+        type
+    });
+
+    const {
+        hideTextIconContainer: hideTextIconContainerDynamicStyle,
+        hintTextIcon: hintTextIconDynamicStyle,
+        cleanButton: cleanButtonDynamicStyle,
+        rightIcon: rightIconDynamicStyle,
+        container: containerDynamicStyle,
+        hintText: hintTextDynamicStyle,
+        required: requiredDynamicStyle,
+        subTitle: subTitleDynamicStyle,
+        content: contentDynamicStyle,
+        overlay: overlayDynamicStyle,
+        title: titleDynamicStyle,
+        input: inputDynamicStyle,
+        icon: iconDynamicStyle
+    } = useStyles({
+        icon: IconComponentProp ? true : false,
+        spreadBehaviour,
+        inlineSpaces,
+        currentType,
+        isDisabled,
+        typography,
+        radiuses,
+        borders,
+        spaces,
+        colors,
+        title,
+        type
+    });
+
+    const inputRef = useRef<TextInputInstance | null>(null);
+
+    const styleType = type === "default" ? "neutral" : type === "question" ? "neutral" : type === "danger" ? "error" : type;
+
+    const [
+        value,
+        setValue
+    ] = useState(initialValue ? initialValue : "");
+
+    const [
+        hideValue,
+        setHideValue
+    ] = useState(true);
+
+    useImperativeHandle(
+        ref,
+        () => ({
+            updateValue,
+            cleanText,
+            focus,
+            blur
+        }),
+        []
+    );
+
+    const titleProps: ITextProps = {
+        color: currentType.titleColor,
+        variant: "bodyLargeSize"
+    };
+
+    const iconProps: INCoreUIKitIconProps = {
+        size: Number(typography.labelLargeSize.fontSize) + 6,
+        color: currentType.iconColor
+    };
+
+    if(isDisabled) {
+        iconProps.color = "disabled";
+    }
+
+    const blur = () => {
+        inputRef.current?.blur();
+    };
+
+    const focus = () => {
+        inputRef.current?.focus();
+    };
+
+    const cleanText = () => {
+        setValue("");
+        inputRef.current?.clear();
+        if(onChangeText) {
+            onChangeText("");
+        }
+    };
+
+    const updateValue = (text: string) => {
+        setValue(text);
+        inputRef.current?.setNativeProps({
+            text: text
+        });
+    };
+
+    const onFocus = () => {
+        if(onFocusProp) onFocusProp();
+    };
+
+    const onBlur = () => {
+        if(onBlurProp) onBlurProp();
+    };
+
+    const toggleValueVisibility = () => {
+        setHideValue(prevState => !prevState);
+    };
+
+    const renderCleanButton = () => {
+        if(isDisabled) {
+            return null;
+        }
+
+        if(variant !== "text") {
+            return null;
+        }
+
+        if(!isCleanEnabled || !value.length) {
+            return null;
+        }
+
+        return <View
+            style={[
+                cleanIconStyle,
+                stylesheet.cleanButton,
+                cleanButtonDynamicStyle
+            ]}
+            onClick={() => {
+                if(onChangeText) {
+                    onChangeText("");
+                }
+                setValue("");
+            }}
+        >
+            <CleanIcon
+                color="mid"
+                size={20}
+            />
+        </View>;
+    };
+
+    const renderIcon = () => {
+        if (!IconComponentProp) {
+            return null;
+        }
+
+        return <View
+            onClick={iconOnPress}
+            style={[
+                iconStyle,
+                stylesheet.icon,
+                iconDynamicStyle
+            ]}
+        >
+            <IconComponentProp
+                color={iconProps.color}
+                size={iconProps.size}
+            />
+        </View>;
+    };
+
+    const renderRightIcon = () => {
+        if (!RightIconComponentProp) {
+            return null;
+        }
+
+        if(isShowHideTextButton && variant === "hidden") {
+            return null;
+        }
+
+        if(isCleanEnabled && value.length > 0 && variant === "text") {
+            return null;
+        }
+
+        return <View
+            onClick={rightIconOnPress}
+            style={[
+                rightIconStyle,
+                stylesheet.rightIcon,
+                rightIconDynamicStyle
+            ]}
+        >
+            <RightIconComponentProp
+                color={iconProps.color}
+                size={iconProps.size}
+            />
+        </View>;
+    };
+
+    const renderHideTextIcon = () => {
+        if(!isShowHideTextButton) {
+            return null;
+        }
+
+        if (variant !== "hidden") {
+            return null;
+        }
+
+        return <View
+            onClick={toggleValueVisibility}
+            style={[
+                hideTextIconStyle,
+                stylesheet.hideTextIconContainer,
+                hideTextIconContainerDynamicStyle
+            ]}
+        >
+            {hideValue ?
+                <EyeOpenedIcon
+                    color={iconProps.color}
+                    size={20}
+                /> :
+                <EyeClosedIcon
+                    color={iconProps.color}
+                    size={20}
+                />
+            }
+        </View>;
+    };
+
+    const renderHintIcon = () => {
+        if(!type) {
+            return null;
+        }
+
+        if(HintTextIconProp) {
+            return <HintTextIconProp
+                color={isDisabled ? "disabled" : currentType.hideTextIconColor}
+                size={20}
+                style={[
+                    stylesheet.hintTextIcon,
+                    hintTextIconDynamicStyle
+                ]}
+            />;
+        }
+
+        const CurrentHintIcon = TextInputTypeIcon[type === "default" ? "question" : type];
+
+        return <CurrentHintIcon
+            customColor={isDisabled ? colors.system.state.content.disabled[styleType] : undefined}
+            color={currentType.hideTextIconColor}
+            size={20}
+            style={[
+                stylesheet.hintTextIcon,
+                hintTextIconDynamicStyle
+            ]}
+        />;
+    };
+
+    const renderHintText = () => {
+        if (!hintText) {
+            return null;
+        }
+
+        return <View
+            style={[
+                hintTextContainerStyle,
+                stylesheet.hintText,
+                hintTextDynamicStyle
+            ]}
+        >
+            {renderHintIcon()}
+            <Text
+                customColor={isDisabled ? colors.system.state.content.disabled[styleType] : undefined}
+                color={currentType.hideTextColor}
+                variant="labelSmallSize"
+            >
+                {hintText}
+            </Text>
+        </View>;
+    };
+
+    const renderRequired = () => {
+        if(!isRequired) {
+            return null;
+        }
+
+        return <Text
+            color="danger"
+            style={[
+                stylesheet.required,
+                requiredDynamicStyle
+            ]}
+        >*</Text>;
+    };
+
+    const renderSubtitle = () => {
+        if(!isShowSubTitle && !isOptional) {
+            return null;
+        }
+
+        return <Text
+            variant="labelLargeSize"
+            color={titleProps.color}
+            style={[
+                stylesheet.subTitle,
+                subTitleDynamicStyle
+            ]}
+        >
+            ( {isOptional ? localize("is-optional") : subTitle} )
+        </Text>;
+    };
+
+    const renderTitle = () => {
+        if (!title) {
+            return null;
+        }
+
+        return <Text
+            {...titleProps}
+            variant={titleProps.variant}
+            color={titleProps.color}
+            style={[
+                stylesheet.title,
+                titleDynamicStyle
+            ]}
+        >
+            {renderRequired()}
+            {title}
+            {renderSubtitle()}
+        </Text>;
+    };
+
+    const renderInput = () => {
+        return <NativeTextInput
+            {...props}
+            placeholderTextColor={currentType.placeholderColor}
+            secureTextEntry={variant === "hidden" && hideValue}
+            underlineColorAndroid="rgba(255,255,255,0)"
+            placeholder={placeholder}
+            allowFontScaling={false}
+            editable={!isDisabled}
+            multiline={false}
+            onFocus={onFocus}
+            onBlur={onBlur}
+            ref={inputRef}
+            value={value}
+            onChangeText={(text) => {
+                const inputValue = text.replace(/\n/g, "");
+
+                if (inputValue === "") {
+                    setValue("");
+                    if(onChangeText) onChangeText("");
+                    return;
+                }
+
+                if (validation) {
+                    if (validation(inputValue)) {
+                        setValue(inputValue);
+                        if(onChangeText) onChangeText(inputValue);
+                    }
+                } else {
+                    setValue(inputValue);
+                    if(onChangeText) onChangeText(inputValue);
+                }
+            }}
+            style={[
+                inputStyle,
+                stylesheet.input,
+                inputDynamicStyle
+            ]}
+        />;
+    };
+
+    const renderOverlay = () => {
+        return <View
+            style={[
+                stylesheet.overlay,
+                overlayDynamicStyle
+            ]}
+        />;
+    };
+
+    return <TouchableOpacity
+        disabled={isDisabled}
+        style={[
+            style,
+            stylesheet.container,
+            containerDynamicStyle
+        ]}
+        onPress={() => {
+            if(!isDisabled) inputRef.current?.focus();
+        }}
+    >
+        {renderTitle()}
+
+        <View
+            style={[
+                contentContainerStyle,
+                stylesheet.content,
+                contentDynamicStyle
+            ]}
+        >
+            {renderOverlay()}
+
+            {renderIcon()}
+
+            {renderInput()}
+
+            {renderCleanButton()}
+            {renderHideTextIcon()}
+            {renderRightIcon()}
+        </View>
+
+        {renderHintText()}
+    </TouchableOpacity>;
+};
+export default forwardRef(TextInput);

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

@@ -0,0 +1,260 @@
+import {
+    type ViewStyle,
+    type TextStyle,
+    StyleSheet
+} from "react-native";
+import {
+    type TextInputDynamicStyleType,
+    type TextInputTypes,
+    type TextInputType
+} from "./type";
+import type {
+    Mutable
+} from "../../types";
+
+export const TEXT_INPUT_TYPE_STYLES: Record<
+    TextInputType,
+    TextInputTypes
+> = {
+    default: {
+        focusBorderColor: "emphasized",
+        borderColor: "emphasized",
+        hideTextIconColor: "mid",
+        placeholderColor: "low",
+        containerColor: "mid",
+        hideTextColor: "mid",
+        titleColor: "high",
+        inputColor: "mid",
+        iconColor: "mid"
+    },
+    danger: {
+        placeholderColor: "dangerLow",
+        hideTextIconColor: "danger",
+        focusBorderColor: "danger",
+        containerColor: "danger",
+        hideTextColor: "danger",
+        borderColor: "danger",
+        titleColor: "danger",
+        inputColor: "danger",
+        iconColor: "danger"
+    },
+    success: {
+        placeholderColor: "successLow",
+        hideTextIconColor: "success",
+        focusBorderColor: "success",
+        containerColor: "success",
+        hideTextColor: "success",
+        borderColor: "success",
+        titleColor: "success",
+        inputColor: "success",
+        iconColor: "success"
+    },
+    warning: {
+        placeholderColor: "warningLow",
+        hideTextIconColor: "warning",
+        focusBorderColor: "warning",
+        containerColor: "warning",
+        hideTextColor: "warning",
+        borderColor: "warning",
+        titleColor: "warning",
+        inputColor: "warning",
+        iconColor: "warning"
+    },
+    info: {
+        placeholderColor: "infoLow",
+        hideTextIconColor: "info",
+        focusBorderColor: "info",
+        containerColor: "info",
+        hideTextColor: "info",
+        borderColor: "info",
+        titleColor: "info",
+        inputColor: "info",
+        iconColor: "info"
+    },
+    question: {
+        focusBorderColor: "emphasized",
+        borderColor: "emphasized",
+        hideTextIconColor: "mid",
+        placeholderColor: "low",
+        containerColor: "mid",
+        hideTextColor: "mid",
+        titleColor: "mid",
+        inputColor: "mid",
+        iconColor: "mid"
+    }
+};
+
+export const getTextInputType = ({
+    type
+}: {
+    type: TextInputType;
+}) => {
+    const currentType = TEXT_INPUT_TYPE_STYLES[type];
+
+    return currentType;
+};
+// TODO: PLACECHOLDER CODE ADD.
+const stylesheet = StyleSheet.create({
+    container: {
+        flexDirection: "column",
+        boxSizing: "border-box",
+        display: "flex"
+    },
+    content: {
+        boxSizing: "border-box",
+        flexDirection: "row",
+        borderStyle: "solid",
+        alignItems: "center",
+        position: "relative",
+        display: "flex"
+    },
+    input: {
+        backgroundColor: "transparent",
+        textAlignVertical: "center",
+        borderColor: "transparent",
+        paddingBottom: 0,
+        paddingRight: 0,
+        paddingLeft: 0,
+        borderWidth: 0,
+        paddingTop: 0,
+        minHeight: 20,
+        width: "100%",
+        zIndex: 99
+    },
+    cleanButton: {
+        justifyContent: "center",
+        alignItems: "center",
+        alignSelf: "center",
+        display: "flex",
+        zIndex: 99
+    },
+    hideTextIconContainer: {
+        justifyContent: "center",
+        alignItems: "center",
+        alignSelf: "center",
+        display: "flex",
+        zIndex: 99,
+        height: 18
+    },
+    title: {
+    },
+    icon: {
+        justifyContent: "center",
+        alignContent: "center",
+        alignItems: "center",
+        display: "flex",
+        zIndex: 99
+    },
+    required: {
+    },
+    hintTextIcon: {
+    },
+    hintText: {
+        flexDirection: "row",
+        alignItems: "center",
+        display: "flex"
+    },
+    subTitle: {
+    },
+    overlay: {
+        position: "absolute",
+        zIndex: 98,
+        bottom: 0,
+        right: 0,
+        left: 0,
+        top: 0
+    },
+    rightIcon: {
+        justifyContent: "center",
+        alignItems: "center",
+        alignSelf: "center",
+        display: "flex",
+        zIndex: 99
+    }
+});
+
+export const useStyles = ({
+    spreadBehaviour,
+    inlineSpaces,
+    currentType,
+    typography,
+    isDisabled,
+    radiuses,
+    borders,
+    colors,
+    spaces,
+    type
+}: TextInputDynamicStyleType) => {
+    const styleType = type === "danger" ? "error" : type === "question" ? "neutral" : type;
+
+    const styles = {
+        container: {
+        } as Mutable<ViewStyle>,
+        content: {
+            backgroundColor: colors.content.container[currentType.containerColor],
+            borderColor: colors.content.container[currentType.containerColor],
+            paddingBottom: spaces.spacingMd,
+            paddingRight: spaces.spacingMd,
+            borderRadius: radiuses.actions,
+            paddingLeft: spaces.spacingMd,
+            paddingTop: spaces.spacingMd,
+            borderWidth: borders.line
+        } as Mutable<ViewStyle>,
+        input: {
+            ...typography.labelLargeSize,
+            color: colors.content.text[currentType.inputColor]
+        } as Mutable<TextStyle>,
+        cleanButton: {
+            marginLeft: spaces.spacingSm
+        } as Mutable<ViewStyle>,
+        hideTextIconContainer: {
+            marginLeft: spaces.spacingSm
+        } as Mutable<ViewStyle>,
+        title: {
+            marginBottom: spaces.spacingSm
+        } as Mutable<ViewStyle>,
+        icon: {
+            marginRight: spaces.spacingSm
+        } as Mutable<ViewStyle>,
+        required: {
+            marginRight: inlineSpaces.required
+        } as Mutable<ViewStyle>,
+        hintTextIcon: {
+            marginRight: spaces.spacingXs
+        } as Mutable<ViewStyle>,
+        hintText: {
+            marginTop: spaces.spacingSm
+        } as Mutable<TextStyle>,
+        subTitle: {
+            marginLeft: inlineSpaces.subTitle
+        } as Mutable<TextStyle>,
+        overlay: {
+            borderRadius: radiuses.actions - 1
+        } as Mutable<ViewStyle>,
+        rightIcon: {
+            marginLeft: spaces.spacingSm
+        } as Mutable<ViewStyle>
+    };
+
+    if(isDisabled) {
+        const disableStyleType = styleType === "default" ? "neutral" : styleType;
+
+        styles.overlay.backgroundColor = colors.system.state.overlay.disabled[disableStyleType];
+        styles.container.borderColor = colors.system.state.overlay.disabled[disableStyleType];
+
+        styles.input.color = colors.content.text.disabled;
+    }
+
+    if (spreadBehaviour === "baseline") {
+        styles.container.alignSelf = spreadBehaviour;
+        styles.container.width = "auto";
+    }
+
+    if (spreadBehaviour === "stretch") {
+        styles.container.justifyContent = "center";
+        styles.container.width = "100%";
+    }
+
+    return styles;
+};
+export default stylesheet;

+ 90 - 0
src/components/textInput/type.ts

@@ -0,0 +1,90 @@
+import {
+    type TextInputProps,
+    type StyleProp,
+    type ViewStyle,
+    type TextStyle,
+    TextInput
+} from "react-native";
+import {
+    type NCoreUIKitIcon
+} from "../../types";
+
+export type ITextInputRef = {
+    updateValue: (text: string) => void;
+    cleanText: () => void;
+    focus: () => void;
+    blur: () => void;
+};
+
+export type TextInputDynamicStyleType = {
+    inlineSpaces: NCoreUIKit.ActivePalette["inlineSpaces"];
+    typography: NCoreUIKit.ActivePalette["typography"];
+    radiuses: NCoreUIKit.ActivePalette["radiuses"];
+    spreadBehaviour?: TextInputSpreadBehaviour;
+    spaces: NCoreUIKit.ActivePalette["spaces"];
+    colors: NCoreUIKit.ActivePalette["colors"];
+    currentType: TextInputTypes;
+    borders: NCoreUIKit.Borders;
+    isDisabled?: boolean;
+    type: TextInputType;
+    title?: string;
+    icon?: boolean;
+};
+
+export type TextInputTypes = {
+    containerColor: keyof NCoreUIKit.ContainerContentColors;
+    focusBorderColor: keyof NCoreUIKit.BorderContentColors;
+    hideTextIconColor: keyof NCoreUIKit.IconContentColors;
+    placeholderColor: keyof NCoreUIKit.TextContentColors;
+    hideTextColor: keyof NCoreUIKit.TextContentColors;
+    borderColor: keyof NCoreUIKit.BorderContentColors;
+    inputColor: keyof NCoreUIKit.TextContentColors;
+    titleColor: keyof NCoreUIKit.TextContentColors;
+    iconColor: keyof NCoreUIKit.IconContentColors;
+};
+
+export type TextInputInstance = NonNullable<React.ComponentRef<typeof TextInput>>;
+
+export type TextInputType = "default" | "danger" | "warning" | "question" | "success" | "info";
+
+export type TextInputSpreadBehaviour = "baseline" | "stretch" | "free";
+
+export type TextInputVariant = "text" | "hidden";
+
+interface ITextInputProps extends TextInputProps {
+    spreadBehaviour?: TextInputSpreadBehaviour;
+    onChangeText?: (value: string) => void;
+    validation?: (text: string) => boolean;
+    hintTextContainerStyle?: ViewStyle;
+    contentContainerStyle?: ViewStyle;
+    inputStyle?: StyleProp<TextStyle>;
+    isShowHideTextButton?: boolean;
+    hideTextIconStyle?: ViewStyle;
+    rightIconOnPress?: () => void;
+    hintTextIcon?: NCoreUIKitIcon;
+    cleanIconStyle?: ViewStyle;
+    rightIconStyle?: ViewStyle;
+    rightIcon?: NCoreUIKitIcon;
+    variant?: TextInputVariant;
+    isShowSubTitle?: boolean;
+    isCleanEnabled?: boolean;
+    iconOnPress?: () => void;
+    initialValue?: string;
+    iconStyle?: ViewStyle;
+    icon?: NCoreUIKitIcon;
+    placeholder?: string;
+    isRequired?: boolean;
+    isDisabled?: boolean;
+    isOptional?: boolean;
+    onFocus?: () => void;
+    type?: TextInputType;
+    onBlur?: () => void;
+    hintText?: string;
+    subTitle?: string;
+    style?: ViewStyle;
+    title?: string;
+    id?: string;
+};
+export type {
+    ITextInputProps as default
+};

+ 2 - 1
src/index.tsx

@@ -9,7 +9,8 @@ export {
 } from "./core/hooks";
 
 export {
-    // TextInput,
+    PageContainer,
+    TextInput,
     Loading,
     // Dialog,
     Button,

+ 1 - 1
src/variants/themes/default.json

@@ -664,4 +664,4 @@
             }
         }
     ]
-}
+}

+ 2 - 1
yarn.lock

@@ -4302,7 +4302,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@types/react-native@npm:0.73.0":
+"@types/react-native@npm:0.73.0, @types/react-native@npm:^0.73.0":
   version: 0.73.0
   resolution: "@types/react-native@npm:0.73.0"
   dependencies:
@@ -13072,6 +13072,7 @@ __metadata:
     "@types/copyfiles": "npm:^2"
     "@types/eslint-plugin-jsx-a11y": "npm:6"
     "@types/react": "npm:19.2.14"
+    "@types/react-native": "npm:^0.73.0"
     babel-plugin-module-resolver: "npm:5.0.2"
     copyfiles: "npm:^2.4.1"
     del-cli: "npm:6.0.0"