thêm toast, thêm logic cho phần ButtonCreateNewHaulOrTrip
This commit is contained in:
159
components/IconButton.tsx
Normal file
159
components/IconButton.tsx
Normal file
@@ -0,0 +1,159 @@
|
||||
import React from "react";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
GestureResponderEvent,
|
||||
StyleProp,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
ViewStyle,
|
||||
} from "react-native";
|
||||
|
||||
type ButtonType = "primary" | "default" | "dashed" | "text" | "link" | "danger";
|
||||
type ButtonShape = "default" | "circle" | "round";
|
||||
type ButtonSize = "small" | "middle" | "large";
|
||||
|
||||
export interface IconButtonProps {
|
||||
type?: ButtonType;
|
||||
shape?: ButtonShape;
|
||||
size?: ButtonSize;
|
||||
icon?: React.ReactNode; // render an icon component, e.g. <AntDesign name="plus" />
|
||||
loading?: boolean;
|
||||
disabled?: boolean;
|
||||
onPress?: (e?: GestureResponderEvent) => void;
|
||||
children?: React.ReactNode; // label text
|
||||
style?: StyleProp<ViewStyle>;
|
||||
block?: boolean; // full width
|
||||
activeOpacity?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* IconButton
|
||||
* A lightweight Button component inspired by Ant Design Button API, tuned for React Native.
|
||||
* Accepts an `icon` prop as a React node for maximum flexibility.
|
||||
*/
|
||||
const IconButton: React.FC<IconButtonProps> = ({
|
||||
type = "default",
|
||||
shape = "default",
|
||||
size = "middle",
|
||||
icon,
|
||||
loading = false,
|
||||
disabled = false,
|
||||
onPress,
|
||||
children,
|
||||
style,
|
||||
block = false,
|
||||
activeOpacity = 0.8,
|
||||
}) => {
|
||||
const sizeMap = {
|
||||
small: { height: 32, fontSize: 14, paddingHorizontal: 10 },
|
||||
middle: { height: 40, fontSize: 16, paddingHorizontal: 14 },
|
||||
large: { height: 48, fontSize: 18, paddingHorizontal: 18 },
|
||||
} as const;
|
||||
|
||||
const colors: Record<
|
||||
ButtonType,
|
||||
{ backgroundColor?: string; textColor: string; borderColor?: string }
|
||||
> = {
|
||||
primary: { backgroundColor: "#4ecdc4", textColor: "#fff" },
|
||||
default: {
|
||||
backgroundColor: "#f2f2f2",
|
||||
textColor: "#111",
|
||||
borderColor: "#e6e6e6",
|
||||
},
|
||||
dashed: {
|
||||
backgroundColor: "#fff",
|
||||
textColor: "#111",
|
||||
borderColor: "#d9d9d9",
|
||||
},
|
||||
text: { backgroundColor: "transparent", textColor: "#111" },
|
||||
link: { backgroundColor: "transparent", textColor: "#4ecdc4" },
|
||||
danger: { backgroundColor: "#e74c3c", textColor: "#fff" },
|
||||
};
|
||||
|
||||
const sz = sizeMap[size];
|
||||
const color = colors[type];
|
||||
|
||||
const isCircle = shape === "circle";
|
||||
const isRound = shape === "round";
|
||||
|
||||
const handlePress = (e: GestureResponderEvent) => {
|
||||
if (disabled || loading) return;
|
||||
onPress?.(e);
|
||||
};
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
activeOpacity={activeOpacity}
|
||||
onPress={handlePress}
|
||||
disabled={disabled || loading}
|
||||
style={[
|
||||
styles.button,
|
||||
{
|
||||
height: sz.height,
|
||||
paddingHorizontal: isCircle ? 0 : sz.paddingHorizontal,
|
||||
backgroundColor: color.backgroundColor ?? "transparent",
|
||||
borderColor: color.borderColor ?? "transparent",
|
||||
borderWidth: type === "dashed" ? 1 : color.borderColor ? 1 : 0,
|
||||
width: isCircle ? sz.height : block ? "100%" : undefined,
|
||||
borderRadius: isCircle ? sz.height / 2 : isRound ? 999 : 8,
|
||||
opacity: disabled ? 0.6 : 1,
|
||||
},
|
||||
type === "dashed" ? { borderStyle: "dashed" } : null,
|
||||
style,
|
||||
]}
|
||||
>
|
||||
<View style={styles.content}>
|
||||
{loading ? (
|
||||
<ActivityIndicator
|
||||
size={"small"}
|
||||
color={color.textColor}
|
||||
style={styles.iconContainer}
|
||||
/>
|
||||
) : icon ? (
|
||||
<View style={styles.iconContainer}>{icon}</View>
|
||||
) : null}
|
||||
|
||||
{children ? (
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={[
|
||||
styles.text,
|
||||
{
|
||||
color: color.textColor,
|
||||
fontSize: sz.fontSize,
|
||||
marginLeft: icon || loading ? 6 : 0,
|
||||
},
|
||||
]}
|
||||
>
|
||||
{children}
|
||||
</Text>
|
||||
) : null}
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
borderRadius: 8,
|
||||
borderColor: "transparent",
|
||||
},
|
||||
content: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
},
|
||||
iconContainer: {
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
text: {
|
||||
fontWeight: "600",
|
||||
},
|
||||
});
|
||||
|
||||
export default IconButton;
|
||||
Reference in New Issue
Block a user