mirror of
https://github.com/Stef-00012/Zipline-Android-App.git
synced 2025-05-11 18:35:58 +02:00
215 lines
4.5 KiB
TypeScript
215 lines
4.5 KiB
TypeScript
import { MaterialIcons } from "@expo/vector-icons";
|
|
import { useState, useRef } from "react";
|
|
import Button from "@/components/Button";
|
|
import {
|
|
View,
|
|
Text,
|
|
TouchableOpacity,
|
|
Dimensions,
|
|
Modal,
|
|
type StyleProp,
|
|
type ViewStyle,
|
|
Pressable,
|
|
type DimensionValue,
|
|
ScrollView,
|
|
type ColorValue,
|
|
} from "react-native";
|
|
|
|
interface Item {
|
|
name: string;
|
|
id: string;
|
|
color?: ColorValue;
|
|
iconColor?: ColorValue;
|
|
disabled?: boolean;
|
|
icon?: keyof typeof MaterialIcons.glyphMap;
|
|
onPress: () => Promise<void> | void;
|
|
}
|
|
|
|
interface DropdownPosition {
|
|
top: number;
|
|
left: number;
|
|
}
|
|
|
|
interface Props {
|
|
data: Array<Item>;
|
|
|
|
containerStyle?: StyleProp<ViewStyle>;
|
|
|
|
width?: DimensionValue;
|
|
height?: DimensionValue;
|
|
iconColor?: ColorValue;
|
|
iconSize?: number;
|
|
icon: keyof typeof MaterialIcons.glyphMap;
|
|
margin?: {
|
|
top?: DimensionValue;
|
|
bottom?: DimensionValue;
|
|
left?: DimensionValue;
|
|
right?: DimensionValue;
|
|
};
|
|
dropdown?: {
|
|
width?: number;
|
|
maxHeight?: number;
|
|
margin?: {
|
|
top?: DimensionValue;
|
|
bottom?: DimensionValue;
|
|
left?: DimensionValue;
|
|
right?: DimensionValue;
|
|
};
|
|
};
|
|
}
|
|
|
|
const minimumMargin = 15;
|
|
|
|
export default function Dropdown({
|
|
data,
|
|
containerStyle,
|
|
height,
|
|
width,
|
|
icon,
|
|
iconSize = 25,
|
|
iconColor = "#575DB5",
|
|
dropdown,
|
|
margin = {},
|
|
}: Props) {
|
|
const [visible, setVisible] = useState(false);
|
|
const [dropdownPosition, setDropdownPosition] = useState<DropdownPosition>({
|
|
top: 0,
|
|
left: 0,
|
|
});
|
|
const dropdownButtonRef = useRef<View>(null);
|
|
|
|
const screen = Dimensions.get("window");
|
|
|
|
const screenWidth = screen.width;
|
|
const dropdownWidth = dropdown?.width || screenWidth * 0.4;
|
|
|
|
return (
|
|
<View
|
|
style={[
|
|
{
|
|
position: "relative",
|
|
width: width,
|
|
height: height,
|
|
marginTop: margin.top,
|
|
marginBottom: margin.bottom,
|
|
marginLeft: margin.left,
|
|
marginRight: margin.right,
|
|
},
|
|
containerStyle,
|
|
]}
|
|
>
|
|
<Pressable
|
|
android_ripple={{
|
|
color: "#464953",
|
|
}}
|
|
ref={dropdownButtonRef}
|
|
style={{
|
|
borderWidth: 2,
|
|
borderColor: "#222c47",
|
|
borderRadius: 7,
|
|
}}
|
|
onPress={() => {
|
|
if (visible) {
|
|
setVisible(false);
|
|
} else {
|
|
dropdownButtonRef.current?.measure(
|
|
(
|
|
_fx: number,
|
|
_fy: number,
|
|
_elementWidth: number,
|
|
elementHeight: number,
|
|
px: number,
|
|
py: number,
|
|
) => {
|
|
let left = px;
|
|
const spaceBelow = screen.height - (py + elementHeight);
|
|
const spaceAbove = py;
|
|
const dropdownHeight =
|
|
(data.length * 50 > (dropdown?.maxHeight || 325)
|
|
? dropdown?.maxHeight || 325
|
|
: data.length * 50) +
|
|
(typeof height === "number" ? height : 40) +
|
|
minimumMargin;
|
|
|
|
let top = py + elementHeight;
|
|
if (spaceAbove > spaceBelow && spaceAbove > dropdownHeight) {
|
|
top = py - dropdownHeight;
|
|
}
|
|
|
|
if (left < minimumMargin) {
|
|
left = minimumMargin;
|
|
} else if (left + dropdownWidth > screenWidth - minimumMargin) {
|
|
left = screenWidth - dropdownWidth - minimumMargin;
|
|
}
|
|
|
|
setDropdownPosition({ top: top, left: left });
|
|
setVisible(true);
|
|
},
|
|
);
|
|
}
|
|
}}
|
|
>
|
|
<MaterialIcons name={icon} size={iconSize} color={iconColor} />
|
|
</Pressable>
|
|
|
|
<Modal visible={visible} transparent animationType="none">
|
|
<TouchableOpacity
|
|
style={{
|
|
width: "100%",
|
|
height: "100%",
|
|
backgroundColor: "#0000004d",
|
|
}}
|
|
activeOpacity={1}
|
|
onPress={() => setVisible(false)}
|
|
>
|
|
<ScrollView
|
|
style={[
|
|
{
|
|
position: "absolute",
|
|
borderRadius: 8,
|
|
overflow: "hidden",
|
|
shadowColor: "#000",
|
|
shadowOffset: {
|
|
width: 0,
|
|
height: 4,
|
|
},
|
|
shadowOpacity: 0.25,
|
|
shadowRadius: 8,
|
|
elevation: 8,
|
|
maxHeight: dropdown?.maxHeight || 325,
|
|
},
|
|
{
|
|
backgroundColor: "#1a202c",
|
|
borderColor: "#2d3748",
|
|
borderWidth: 1,
|
|
},
|
|
{
|
|
top: dropdownPosition.top,
|
|
left: dropdownPosition.left,
|
|
width: dropdownWidth,
|
|
},
|
|
]}
|
|
>
|
|
{data.map((item) => (
|
|
<Button
|
|
disabled={item.disabled}
|
|
position="left"
|
|
bold={false}
|
|
text={item.name}
|
|
icon={item.icon}
|
|
color="#191b27"
|
|
textColor={item.color}
|
|
onPress={() => {
|
|
item.onPress();
|
|
setVisible(false);
|
|
}}
|
|
key={item.id}
|
|
iconColor={item.iconColor}
|
|
/>
|
|
))}
|
|
</ScrollView>
|
|
</TouchableOpacity>
|
|
</Modal>
|
|
</View>
|
|
);
|
|
}
|