fix folder component
This commit is contained in:
47
components/_ShareComponent/Button/ButtonCustom.tsx
Normal file
47
components/_ShareComponent/Button/ButtonCustom.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
// components/Button/Button.tsx
|
||||
|
||||
import React from "react";
|
||||
import { Text, TouchableOpacity } from "react-native";
|
||||
import buttonStyles from "./buttonStyles";
|
||||
|
||||
// Definisi props dengan TypeScript
|
||||
interface ButtonProps {
|
||||
onPress: () => void;
|
||||
title?: string;
|
||||
backgroundColor?: string;
|
||||
textColor?: string;
|
||||
radius?: number;
|
||||
disabled?: boolean;
|
||||
iconLeft?: React.ReactNode;
|
||||
}
|
||||
|
||||
const ButtonCustom: React.FC<ButtonProps> = ({
|
||||
onPress,
|
||||
title = "Button",
|
||||
backgroundColor = "#007AFF",
|
||||
textColor = "#FFFFFF",
|
||||
radius = 8,
|
||||
disabled = false,
|
||||
iconLeft,
|
||||
}) => {
|
||||
const styles = buttonStyles({
|
||||
backgroundColor,
|
||||
textColor,
|
||||
borderRadius: radius,
|
||||
});
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={[styles.button, disabled && styles.disabled]}
|
||||
onPress={onPress}
|
||||
disabled={disabled}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
{/* Render icon jika tersedia */}
|
||||
{iconLeft && iconLeft}
|
||||
<Text style={styles.buttonText}>{title}</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
export default ButtonCustom;
|
||||
31
components/_ShareComponent/Button/buttonStyles.ts
Normal file
31
components/_ShareComponent/Button/buttonStyles.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
// components/Button/buttonStyles.js
|
||||
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { StyleSheet } from "react-native";
|
||||
|
||||
export default function buttonStyles({
|
||||
backgroundColor = "#007AFF",
|
||||
textColor = "#FFFFFF",
|
||||
borderRadius = 8,
|
||||
}) {
|
||||
return StyleSheet.create({
|
||||
button: {
|
||||
backgroundColor,
|
||||
paddingVertical: 12,
|
||||
paddingHorizontal: 20,
|
||||
borderRadius,
|
||||
flexDirection: "row", // 👈 Tambahkan baris ini
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: 8,
|
||||
},
|
||||
buttonText: {
|
||||
color: textColor,
|
||||
fontSize: 16,
|
||||
fontWeight: "600",
|
||||
},
|
||||
disabled: {
|
||||
backgroundColor: MainColor.disabled,
|
||||
},
|
||||
});
|
||||
}
|
||||
100
components/_ShareComponent/TextInput/TextInputCustom.tsx
Normal file
100
components/_ShareComponent/TextInput/TextInputCustom.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
// components/TextInputCustom.tsx
|
||||
|
||||
import Ionicons from "@expo/vector-icons/Ionicons";
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
TextInput as RNTextInput,
|
||||
StyleProp,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
ViewStyle,
|
||||
} from "react-native";
|
||||
import { textInputStyles } from "./textInputStyles";
|
||||
|
||||
type IconType = React.ReactNode | string;
|
||||
|
||||
type Props = {
|
||||
iconLeft?: IconType;
|
||||
iconRight?: IconType;
|
||||
label?: string;
|
||||
required?: boolean;
|
||||
error?: string;
|
||||
secureTextEntry?: boolean;
|
||||
fontColor?: string;
|
||||
disabled?: boolean;
|
||||
borderRadius?: number;
|
||||
style?: StyleProp<ViewStyle>;
|
||||
} & Omit<React.ComponentProps<typeof RNTextInput>, "style">;
|
||||
|
||||
export const TextInputCustom = ({
|
||||
iconLeft,
|
||||
iconRight,
|
||||
label,
|
||||
required = false,
|
||||
error = "",
|
||||
secureTextEntry = false,
|
||||
fontColor = "#000",
|
||||
disabled = false,
|
||||
borderRadius = 8,
|
||||
style,
|
||||
...rest
|
||||
}: Props) => {
|
||||
const [isPasswordVisible, setIsPasswordVisible] = useState(false);
|
||||
|
||||
// Helper untuk render ikon
|
||||
const renderIcon = (icon: IconType) => {
|
||||
if (!icon) return null;
|
||||
return typeof icon === "string" ? (
|
||||
<Text style={textInputStyles.iconText}>{icon}</Text>
|
||||
) : (
|
||||
icon
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={textInputStyles.container}>
|
||||
{label && (
|
||||
<Text style={textInputStyles.label}>
|
||||
{label}
|
||||
{required && <Text style={textInputStyles.required}> *</Text>}
|
||||
</Text>
|
||||
)}
|
||||
<View
|
||||
style={[
|
||||
textInputStyles.inputContainer,
|
||||
disabled && textInputStyles.disabled,
|
||||
{ borderRadius },
|
||||
error ? textInputStyles.errorBorder : null,
|
||||
style,
|
||||
]}
|
||||
>
|
||||
{iconLeft && (
|
||||
<View style={textInputStyles.icon}>{renderIcon(iconLeft)}</View>
|
||||
)}
|
||||
<RNTextInput
|
||||
style={[textInputStyles.input, { color: fontColor }]}
|
||||
editable={!disabled}
|
||||
secureTextEntry={secureTextEntry && !isPasswordVisible}
|
||||
{...rest}
|
||||
/>
|
||||
{secureTextEntry && (
|
||||
<TouchableOpacity
|
||||
onPress={() => setIsPasswordVisible((prev) => !prev)}
|
||||
style={textInputStyles.icon}
|
||||
>
|
||||
<Ionicons
|
||||
name={isPasswordVisible ? "eye-off" : "eye"}
|
||||
size={20}
|
||||
color="#888"
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{iconRight && (
|
||||
<View style={textInputStyles.icon}>{renderIcon(iconRight)}</View>
|
||||
)}
|
||||
</View>
|
||||
{error ? <Text style={textInputStyles.errorMessage}>{error}</Text> : null}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
71
components/_ShareComponent/TextInput/textInputStyles.ts
Normal file
71
components/_ShareComponent/TextInput/textInputStyles.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
// components/text-input.styles.ts
|
||||
import { AccentColor, MainColor } from "@/constants/color-palet";
|
||||
import { StyleSheet } from "react-native";
|
||||
|
||||
export const textInputStyles = StyleSheet.create({
|
||||
// Container utama input (View luar)
|
||||
container: {
|
||||
marginBottom: 16,
|
||||
},
|
||||
|
||||
// Label di atas input
|
||||
label: {
|
||||
fontSize: 14,
|
||||
marginBottom: 6,
|
||||
fontWeight: "500",
|
||||
color: MainColor.white,
|
||||
},
|
||||
|
||||
// Tanda bintang merah untuk required
|
||||
required: {
|
||||
color: "red",
|
||||
},
|
||||
|
||||
// Pesan error di bawah input
|
||||
errorMessage: {
|
||||
marginTop: 4,
|
||||
fontSize: 12,
|
||||
color: MainColor.red,
|
||||
},
|
||||
|
||||
// Wrapper input (View pembungkus TextInput)
|
||||
inputContainer: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
borderWidth: 1,
|
||||
borderColor: AccentColor.white,
|
||||
backgroundColor: MainColor.login,
|
||||
paddingHorizontal: 12,
|
||||
height: 50,
|
||||
},
|
||||
|
||||
// Style saat disabled
|
||||
disabled: {
|
||||
backgroundColor: "#f9f9f9",
|
||||
borderColor: "#e0e0e0",
|
||||
},
|
||||
|
||||
// Input utama (TextInput)
|
||||
input: {
|
||||
flex: 1,
|
||||
fontSize: 16,
|
||||
paddingVertical: 0,
|
||||
},
|
||||
|
||||
// Ikon di kiri/kanan
|
||||
icon: {
|
||||
marginHorizontal: 4,
|
||||
justifyContent: "center",
|
||||
},
|
||||
|
||||
// Teks ikon jika berupa string
|
||||
iconText: {
|
||||
fontSize: 16,
|
||||
color: "#000",
|
||||
},
|
||||
|
||||
// Border merah jika ada error
|
||||
errorBorder: {
|
||||
borderColor: "red",
|
||||
},
|
||||
});
|
||||
@@ -1,35 +1,43 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { globalStyles } from "@/constants/global-styles";
|
||||
import { Styles } from "@/constants/global-styles";
|
||||
import { ImageBackground, ScrollView, View } from "react-native";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
|
||||
|
||||
interface ViewWrapperProps {
|
||||
children: React.ReactNode;
|
||||
withBackground?: boolean;
|
||||
}
|
||||
|
||||
const ViewWrapper = ({ children }: ViewWrapperProps) => {
|
||||
const ViewWrapper = ({
|
||||
children,
|
||||
withBackground = false,
|
||||
}: ViewWrapperProps) => {
|
||||
|
||||
const assetBackground = require("../../assets/images/main-background.png");
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
edges={[]}
|
||||
style={{
|
||||
flex: 1,
|
||||
// paddingTop: StatusBar.currentHeight,
|
||||
}}
|
||||
|
||||
>
|
||||
<ScrollView contentContainerStyle={{ flexGrow: 1 }} >
|
||||
<ImageBackground
|
||||
source={require("../../assets/images/main-background.png")}
|
||||
resizeMode="cover"
|
||||
style={globalStyles.imageBackground}
|
||||
>
|
||||
<View style={globalStyles.container}>{children}</View>
|
||||
</ImageBackground>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
<SafeAreaProvider>
|
||||
<SafeAreaView
|
||||
edges={[]}
|
||||
style={{
|
||||
flex: 1,
|
||||
// paddingTop: StatusBar.currentHeight,
|
||||
}}
|
||||
>
|
||||
<ScrollView contentContainerStyle={{ flexGrow: 1 }}>
|
||||
{withBackground ? (
|
||||
<ImageBackground
|
||||
source={assetBackground}
|
||||
resizeMode="cover"
|
||||
style={Styles.imageBackground}
|
||||
>
|
||||
<View style={Styles.containerWithBackground}>{children}</View>
|
||||
</ImageBackground>
|
||||
) : (
|
||||
<View style={Styles.container}>{children}</View>
|
||||
)}
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
</SafeAreaProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user