UNPKG

@hoddy-ui/next

Version:

Core rich react native components written in typescript, with support for expo-router

1,701 lines (1,676 loc) 63.4 kB
// ../src/theme/colors.ts var extraColors = {}; var setExtraColors = (c) => extraColors = c; function colors(theme) { const lightColors = { white: { 1: "#ffffff", 2: "#f7f7f7", 3: "#eeeeee", 4: "#dddddd", 5: "#bbbbbb", ...extraColors?.light?.white }, black: { 1: "#888888", 2: "#777777", 3: "#555555", 4: "#333333", 5: "#000000", ...extraColors?.light?.black } }; const darkColors = { black: { 1: "#ffffff", 2: "#f7f7f7", 3: "#eeeeee", 4: "#dddddd", 5: "#aaaaaa", ...extraColors?.dark?.black }, white: { 1: "#060606", 2: "#222222", 3: "#333333", 4: "#444444", 5: "#555555", ...extraColors?.dark?.white }, dark: { main: "#f2f3f4", light: "#ffffff", dark: "#dddddd", text: "#000000", ...extraColors?.dark?.dark }, light: { main: "#111111", light: "#555555", dark: "#333333", text: "#ffffff", ...extraColors?.dark?.light }, textSecondary: { main: "#666666", light: "#777777", dark: "#444444", text: "#ffffff", ...extraColors?.dark?.textSecondary }, primary: { main: "#ff8800", light: "#feffd3", dark: "#ffaa00", text: "#ffffff", ...extraColors?.light?.primary, ...extraColors?.dark?.primary } }; const dynamicColors = theme === "dark" ? darkColors : lightColors; return { ...extraColors[theme], primary: { main: "#ff8800", light: "#feffd3", dark: "#ffaa00", text: "#ffffff", ...extraColors?.light?.primary }, secondary: { main: "#ff1111", light: "#ff4433", dark: "#dd0000", text: "#ffffff", ...extraColors?.light?.secondary }, light: { main: "#ffffff", light: "#ffffff", dark: "#dddddd", text: "#000000", ...extraColors?.light?.light }, dark: { main: "#000000", light: "#777777", dark: "#111111", text: "#ffffff", ...extraColors?.light?.dark }, textSecondary: { main: "#aaaaaa", light: "#bbbbbb", dark: "#777777", text: "#112233", ...extraColors?.light?.textSecondary }, blue: { main: "#0099ff", light: "#3399ff", dark: "#002288", text: "#ffffff", ...extraColors?.light?.blue }, info: { main: "#0099ff", light: "#33aaff", dark: "#0088aa", text: "#ffffff", ...extraColors?.light?.info }, success: { main: "#00aa44", text: "#ffffff", light: "#55cc33", dark: "#006622", ...extraColors?.light?.success }, warning: { main: "#ffaa22", light: "#ffcc77", dark: "#ff9900", text: "#ffffff", ...extraColors?.light?.warning }, error: { main: "#dd2222", text: "#ffffff", light: "#ff4433", dark: "#aa2200", ...extraColors?.light?.error }, ...dynamicColors }; } // ../src/config/KeyManager.ts var config = { GOOGLE_MAP_API_KEY: "", EDGE_TO_EDGE: false }; function setConfig(key) { config = key; } function getConfig() { return config; } // ../src/config/index.ts function initialize(config2) { try { setConfig({ GOOGLE_MAP_API_KEY: config2.googleMapApiKey, DEFAULT_FONT_FAMILY: config2.fontFamily, EDGE_TO_EDGE: config2.edgeToEdge ?? false }); if (config2.colors) setExtraColors(config2.colors); } catch (error) { console.error("Error reading the config file:", error); } } // components/AdaptiveStatusBarNext.tsx import { useFocusEffect } from "expo-router"; import React5, { useState as useState2 } from "react"; import { Platform as Platform3, StatusBar } from "react-native"; // ../src/hooks.ts import { useContext } from "react"; import { Dimensions, Platform as Platform2 } from "react-native"; import { vs } from "react-native-size-matters"; // ../src/theme/index.tsx import AsyncStorage from "@react-native-async-storage/async-storage"; import * as NavigationBar from "expo-navigation-bar"; import * as SystemUI from "expo-system-ui"; import React4, { createContext, useEffect as useEffect2, useReducer } from "react"; import { Platform, useColorScheme } from "react-native"; import { SafeAreaProvider } from "react-native-safe-area-context"; // ../src/Components/FlashMessage.tsx import React3, { useEffect, useState } from "react"; import { LayoutAnimation, TouchableOpacity, View } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { ScaledSheet } from "react-native-size-matters"; // ../src/Components/Typography.tsx import React2, { forwardRef } from "react"; import { StyleSheet, Text } from "react-native"; import { moderateScale, verticalScale } from "react-native-size-matters"; var Typography = forwardRef( ({ children, color = "dark", style = {}, textCase = null, variant = "body1", align = "left", gutterBottom = 0, adjustsFontSizeToFit, fontWeight = 400, fontFamily, // NEW PROP ADDED ...props }, ref) => { const colors2 = useColors(); const fontSize = { h1: moderateScale(42), h2: moderateScale(37), h3: moderateScale(32), h4: moderateScale(27), h5: moderateScale(22), h6: moderateScale(17), body1: moderateScale(15), body2: moderateScale(12), caption: moderateScale(10) }; const styles2 = StyleSheet.create({ text: { fontSize: fontSize[variant], marginBottom: verticalScale(gutterBottom) || 0, color: colors2[color]?.main || color, textTransform: textCase, alignItems: "center", textAlign: align, fontWeight, fontFamily: fontFamily || getConfig().DEFAULT_FONT_FAMILY || void 0 // Use custom font if provided, else default } }); return /* @__PURE__ */ React2.createElement( Text, { ref, adjustsFontSizeToFit, style: [styles2.text, style], ...props }, children ); } ); var Typography_default = Typography; // ../src/Components/FlashMessage.tsx var showFlashMessage = () => { }; var FlashMessage = () => { const { top } = useSafeAreaInsets(); const [message, setMessage] = useState(null); const [show, setShow] = useState(false); const colors2 = useColors(); const type = message?.type || "success"; showFlashMessage = (msg) => { setMessage(msg); setTimeout(() => { setShow(true); }, 50); setTimeout(() => { setShow(false); setTimeout(() => { setMessage(null); }, 500); }, msg.duration || 3e3); }; useEffect(() => { LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); }, [show]); const styles2 = ScaledSheet.create({ root: { position: "absolute", top: show ? 0 : -200, zIndex: 1e3, left: 0, paddingTop: top + 10, paddingHorizontal: "15@ms", backgroundColor: colors2[type].main, width: "100%", borderBottomLeftRadius: 10, borderBottomRightRadius: 10, paddingBottom: "15@ms" }, action: { borderRadius: 20, marginTop: "10@vs", flexDirection: "row", justifyContent: "center", paddingHorizontal: "20@ms", paddingVertical: "8@vs", backgroundColor: "#fff3" } }); return /* @__PURE__ */ React3.createElement(View, { style: styles2.root }, /* @__PURE__ */ React3.createElement(View, { style: { flexDirection: "row" } }, /* @__PURE__ */ React3.createElement(View, { style: { flex: 1, marginRight: 10 } }, message?.title && /* @__PURE__ */ React3.createElement( Typography_default, { variant: "h6", fontWeight: 600, gutterBottom: 3, style: { color: "#fff" } }, message?.title ), /* @__PURE__ */ React3.createElement(Typography_default, { style: { color: "#fff" } }, message?.message))), message?.actions?.map((cur, i) => /* @__PURE__ */ React3.createElement(TouchableOpacity, { key: i, style: styles2.action, onPress: cur.onPress }, /* @__PURE__ */ React3.createElement(Typography_default, { fontWeight: 700, style: { color: "#fff" } }, cur.title)))); }; var FlashMessage_default = FlashMessage; // ../src/theme/index.tsx var UIThemeContext = createContext({ themeState: { mode: "default", value: "light" } }); function themeReducer(state, { type, payload }) { switch (type) { case "dark": return { mode: "dark", value: "dark" }; case "default": return { mode: "default", value: payload }; case "light": return { mode: "light", value: "light" }; default: return state; } } var ConfigureSystemUI = () => { const theme = useTheme(); const colors2 = useColors(); useEffect2(() => { const config2 = getConfig(); if (colors2) { SystemUI.setBackgroundColorAsync(colors2.white[1]); if (Platform.OS === "android" && !config2.EDGE_TO_EDGE) { NavigationBar.setBackgroundColorAsync(colors2.white[1]); if (theme === "dark") { NavigationBar.setButtonStyleAsync("light"); } else { NavigationBar.setButtonStyleAsync("dark"); } } } }, [colors2, theme]); return /* @__PURE__ */ React4.createElement(React4.Fragment, null); }; var UIThemeProvider = ({ children }) => { const [themeState, themeDispatch] = useReducer(themeReducer, { mode: "default", value: "light" }); const colorScheme = useColorScheme(); React4.useEffect(() => { AsyncStorage.getItem("theme").then((val) => { if (val) { if (val === "default") { themeDispatch({ type: "default", payload: colorScheme }); } else themeDispatch({ type: val }); } else { themeDispatch({ type: "default", payload: colorScheme }); } }); }, [colorScheme]); return /* @__PURE__ */ React4.createElement(SafeAreaProvider, null, /* @__PURE__ */ React4.createElement( UIThemeContext.Provider, { value: { themeState, themeDispatch } }, children, /* @__PURE__ */ React4.createElement(FlashMessage_default, null), /* @__PURE__ */ React4.createElement(ConfigureSystemUI, null) )); }; // ../src/hooks.ts var useColors = () => { const { themeState } = useContext(UIThemeContext); return colors(themeState.value); }; var useTheme = () => { const { themeState } = useContext(UIThemeContext); return themeState.value; }; var useNavScreenOptions = (type) => { const colors2 = useColors(); const theme = useTheme(); const options = { stack: { headerShown: false, headerStyle: { backgroundColor: colors2.white[1] }, headerShadowVisible: false, contentStyle: { backgroundColor: colors2.white[1] }, headerTitleStyle: { color: colors2.black[1] }, headerTintColor: Platform2.OS === "android" ? colors2.black[1] : colors2.blue.light }, tab: { headerShown: false, headerTintColor: colors2.dark.main, tabBarStyle: { borderTopColor: theme === "dark" ? colors2.light.main : colors2.white[2], borderTopWidth: 1, // shadowColor: "#000", // shadowOffset: { height: -3, width: 0 }, // shadowRadius: 7, // shadowOpacity: 0.1, backgroundColor: colors2.white[1] }, tabBarActiveTintColor: colors2.blue.main, tabBarInactiveTintColor: colors2.textSecondary.main, tabBarLabelStyle: { // fontSize: ms(12), } }, drawer: { headerShown: false, drawerActiveTintColor: colors2.primary.main, drawerInactiveTintColor: colors2.textSecondary.main, sceneContainerStyle: { backgroundColor: colors2.white[2] }, drawerStyle: { backgroundColor: colors2.white[1] }, headerStyle: { backgroundColor: colors2.white[1] }, headerTitleStyle: { color: colors2.dark.main } } }; if (Platform2.OS === "android") { options.tab.tabBarStyle.height = Dimensions.get("screen").height * 0.08; options.tab.tabBarStyle.paddingBottom = vs(15); } return options[type]; }; // components/AdaptiveStatusBarNext.tsx var AdaptiveStatusBar = ({ translucent = false }) => { const [focused, setFocused] = useState2(false); const colors2 = useColors(); const theme = useTheme(); const statusbarHandler = () => { StatusBar.setBarStyle(theme === "dark" ? "light-content" : "dark-content"); if (Platform3.OS === "android") { StatusBar.setBackgroundColor( translucent ? "transparent" : colors2.white[1] ); StatusBar.setTranslucent(true); } }; useFocusEffect( React5.useCallback(() => { statusbarHandler(); }, [theme]) ); React5.useEffect(() => { statusbarHandler(); }, [theme]); return /* @__PURE__ */ React5.createElement(React5.Fragment, null); }; var AdaptiveStatusBarNext_default = AdaptiveStatusBar; // ../src/Components/AlertX.tsx import { MaterialIcons } from "@expo/vector-icons"; import React6 from "react"; import { View as View2 } from "react-native"; import { ScaledSheet as ScaledSheet2 } from "react-native-size-matters"; var AlertX = ({ type = "info", variant = "contained", title, gutterBottom = 0, body, style = {} }) => { const colors2 = useColors(); const styles2 = ScaledSheet2.create({ container: { padding: 20, paddingTop: 10, paddingBottom: 10, borderRadius: 8, alignItems: "center", flexDirection: "row", marginBottom: gutterBottom + "@ms", backgroundColor: colors2[type].main + (variant === "contained" ? "" : "3") }, title: { color: variant === "contained" ? "#fff" : colors2[type].main }, body: { color: variant === "contained" ? "#fff" : colors2[type].main } }); return /* @__PURE__ */ React6.createElement(View2, { style: { ...styles2.container, ...style } }, /* @__PURE__ */ React6.createElement(View2, { style: { width: "80%" } }, /* @__PURE__ */ React6.createElement(Typography_default, { style: styles2.title, gutterBottom: 3, fontWeight: 700 }, title), body && /* @__PURE__ */ React6.createElement(Typography_default, { fontWeight: 700, variant: "body2", style: styles2.body }, body)), /* @__PURE__ */ React6.createElement(View2, { style: { marginLeft: "auto" } }, /* @__PURE__ */ React6.createElement( MaterialIcons, { color: variant === "contained" ? "#fff" : colors2[type].main, size: 36, name: type === "success" ? "check" : type } ))); }; var AlertX_default = AlertX; // ../src/Components/Avatar.tsx import { AntDesign } from "@expo/vector-icons"; import React7 from "react"; import { Image, View as View3 } from "react-native"; import { ScaledSheet as ScaledSheet3 } from "react-native-size-matters"; var Avatar = ({ color = "dark", label, variant = "contained", source, size = 48, style = {} }) => { const colors2 = useColors(); const styles2 = ScaledSheet3.create({ root: { borderRadius: 150, height: size + "@ms", width: size + "@ms", alignItems: "center", justifyContent: "center", overflow: "hidden", borderWidth: variant === "outlined" ? 5 : 0, borderColor: variant === "outlined" ? "#fff" : "#0000", backgroundColor: variant === "outlined" ? null : label ? colors2[color].main : colors2.white[4], ...style }, image: { height: "110%", width: "110%" } }); return /* @__PURE__ */ React7.createElement(View3, { style: styles2.root }, source ? /* @__PURE__ */ React7.createElement(Image, { resizeMode: "cover", style: styles2.image, source }) : label ? /* @__PURE__ */ React7.createElement(Typography_default, { style: { color: colors2[color].text } }, label[0]) : /* @__PURE__ */ React7.createElement(AntDesign, { name: "user", color: "#fff", size: Math.round(size / 1.5) })); }; var Avatar_default = Avatar; // ../src/Components/Button.tsx import { Ionicons, MaterialIcons as MaterialIcons2 } from "@expo/vector-icons"; import React8, { forwardRef as forwardRef2 } from "react"; import { ActivityIndicator, Text as Text2, TouchableOpacity as TouchableOpacity2 } from "react-native"; import { ScaledSheet as ScaledSheet4, moderateScale as moderateScale2 } from "react-native-size-matters"; var LinkButton = ({ title, style = {}, color = "blue", fontSize = 12, fontWeight = "400", disabled, onPress = () => { } }) => { const colors2 = useColors(); const styles2 = ScaledSheet4.create({ text: { fontSize: moderateScale2(fontSize), fontWeight, fontFamily: getConfig().DEFAULT_FONT_FAMILY || "System", color: disabled ? "#777" : colors2[color].main } }); return /* @__PURE__ */ React8.createElement(TouchableOpacity2, { onPress, disabled }, /* @__PURE__ */ React8.createElement(Text2, { style: { ...styles2.text, ...style } }, title)); }; var IconButton = ({ style = {}, color = "dark", disabled, icon, elevation, bg = false, size = 24, containerStyles = {}, onPress = () => { }, iconType = "material" }) => { const colors2 = useColors(); const theme = useTheme(); const bgColor = theme === "light" ? "#fff" : "#222"; const styles2 = ScaledSheet4.create({ container: { alignSelf: "flex-start", flexGrow: 0, backgroundColor: bg ? bgColor : elevation > 0 ? bgColor : null, padding: "5@ms", shadowColor: "#000", shadowOpacity: 0.1, shadowOffset: { height: 1, width: 0 }, height: bg ? size + 20 + "@ms" : void 0, width: bg ? size + 20 + "@ms" : void 0, alignItems: "center", justifyContent: "center", shadowRadius: elevation, elevation, borderRadius: size * 5 }, text: { color: disabled ? "#777" : colors2[color].main } }); const IconComp = { material: MaterialIcons2, ion: Ionicons }[iconType]; return /* @__PURE__ */ React8.createElement( TouchableOpacity2, { onPress, activeOpacity: 0.3, style: { ...styles2.container, ...containerStyles } }, /* @__PURE__ */ React8.createElement(IconComp, { style: { ...styles2.text, ...style }, name: icon, size }) ); }; var Button = forwardRef2( ({ elevation = 0, onPress = () => { }, disabled = false, title, loading, size = "normal", rounded = false, gutterBottom, style = {}, fullWidth = false, translucent = false, color = "primary", variant = "contained", start, end }, ref) => { const colors2 = useColors(); const styles2 = ScaledSheet4.create({ con: { flexDirection: "row", alignItems: "center", alignSelf: "flex-start", justifyContent: "center", backgroundColor: variant === "text" || variant === "outlined" ? null : translucent ? translucent === "dark" ? colors2.white[3] + "22" : colors2.black[3] + "22" : loading ? colors2[color].light : disabled ? colors2.white[4] : colors2[color].main, borderRadius: rounded ? 30 : 10, elevation: variant === "text" ? 0 : elevation, paddingVertical: size === "small" ? 8 : size === "large" ? "15@ms" : "13@ms", paddingHorizontal: size === "small" ? "10@ms" : "18@ms", borderColor: colors2[color].main, borderWidth: variant === "outlined" ? 1 : 0, shadowColor: "#000", shadowRadius: elevation, marginBottom: gutterBottom, shadowOffset: { height: elevation / 2, width: 0 }, shadowOpacity: variant === "text" ? 0 : 0.3, width: fullWidth ? "100%" : null, ...style }, text: { color: disabled ? variant === "text" || variant === "outlined" ? colors2.black[1] : colors2[color].text : colors2[color][variant === "text" || variant === "outlined" ? "main" : "text"], fontWeight: variant === "outlined" ? "700" : "500", fontSize: size === "small" ? "12@ms" : "16@ms", fontFamily: getConfig().DEFAULT_FONT_FAMILY || "System" } }); return /* @__PURE__ */ React8.createElement( TouchableOpacity2, { ref, onPress, disabled, style: styles2.con }, start, loading && /* @__PURE__ */ React8.createElement( ActivityIndicator, { size: "small", color: colors2[color].text, style: { marginRight: 10 } } ), /* @__PURE__ */ React8.createElement(Text2, { style: styles2.text }, title), end ); } ); var Button_default = Button; // ../src/Components/Checkbox.tsx import { MaterialCommunityIcons } from "@expo/vector-icons"; import React9 from "react"; import { TouchableOpacity as TouchableOpacity3, View as View4 } from "react-native"; import { ScaledSheet as ScaledSheet5 } from "react-native-size-matters"; var CheckBox = ({ color = "primary", checked, size = 24, label, style = {}, onChange }) => { const iconName = checked ? "checkbox-marked" : "checkbox-blank-outline"; const colors2 = useColors(); const styles2 = ScaledSheet5.create({ container: { alignItems: "center", flexDirection: "row", ...style } }); return /* @__PURE__ */ React9.createElement(View4, { style: styles2.container }, /* @__PURE__ */ React9.createElement(TouchableOpacity3, { onPress: onChange }, /* @__PURE__ */ React9.createElement( MaterialCommunityIcons, { name: iconName, size, color: colors2[color].main } )), label); }; // ../src/Components/FormWrapper.tsx import React10 from "react"; import { Keyboard, KeyboardAvoidingView, Platform as Platform4, ScrollView, TouchableWithoutFeedback } from "react-native"; import { ScaledSheet as ScaledSheet6 } from "react-native-size-matters"; var FormWrapper = ({ children, behavior = Platform4.OS === "ios" ? "padding" : "height", contentContainerStyle, mode = "scroll", keyboardVerticalOffset = 10, style = {}, onScroll }) => { const styles2 = ScaledSheet6.create({ root: { width: "100%", flex: 1, ...style } }); return mode === "static" ? /* @__PURE__ */ React10.createElement(TouchableWithoutFeedback, { onPress: Keyboard.dismiss, accessible: false }, /* @__PURE__ */ React10.createElement( KeyboardAvoidingView, { style: styles2.root, behavior, contentContainerStyle: styles2.root, keyboardVerticalOffset }, children )) : /* @__PURE__ */ React10.createElement( KeyboardAvoidingView, { behavior, style: styles2.root, keyboardVerticalOffset }, /* @__PURE__ */ React10.createElement( ScrollView, { onScroll, showsVerticalScrollIndicator: false, scrollEventThrottle: 40, keyboardDismissMode: "interactive", contentContainerStyle, keyboardShouldPersistTaps: "handled" }, children ) ); }; // ../src/Components/StarRating.tsx import { Ionicons as Ionicons2 } from "@expo/vector-icons"; import * as Haptics from "expo-haptics"; import { useEffect as useEffect3, useState as useState4 } from "react"; import { ActivityIndicator as ActivityIndicator2, TextInput, TouchableOpacity as TouchableOpacity4, View as View6 } from "react-native"; import { ScaledSheet as ScaledSheet8 } from "react-native-size-matters"; // ../src/Components/Popup.tsx import { Keyboard as Keyboard2, KeyboardAvoidingView as KeyboardAvoidingView2, Modal, Platform as Platform5, Pressable, StyleSheet as StyleSheet2, TouchableWithoutFeedback as TouchableWithoutFeedback2, View as View5 } from "react-native"; import React11, { useState as useState3 } from "react"; import { ScaledSheet as ScaledSheet7 } from "react-native-size-matters"; var Popup = ({ title, sheet, bare = false, keyboardVerticalOffset, children, open, onClose = () => { }, style }) => { const theme = useTheme(); const colors2 = useColors(); const [show, setShow] = useState3(open); const [showSecondary, setShowSecondary] = useState3(false); const styles2 = ScaledSheet7.create({ root: { height: "100%", width: "100%", justifyContent: sheet ? "flex-end" : "center" }, avoidingView: { minHeight: typeof sheet === "number" ? sheet : void 0, maxHeight: "80%", zIndex: 1e3, alignSelf: "center", maxWidth: sheet ? void 0 : "90%", width: sheet ? "100%" : void 0 }, container: { paddingBottom: sheet ? "30@ms" : 0, backgroundColor: theme === "dark" ? "#111" : colors2.white[2], borderTopLeftRadius: 20, borderTopRightRadius: 20, borderBottomRightRadius: sheet ? 0 : 20, borderBottomLeftRadius: sheet ? 0 : 20, width: "100%", ...style }, content: { paddingHorizontal: bare ? void 0 : "15@ms" // flex: 1, }, title: { flexDirection: "row", alignItems: "center", justifyContent: "center", height: "50@ms" }, titleIcon: { position: "absolute", left: "15@ms" }, backdrop: { position: "absolute", height: "100%", zIndex: -1, width: "100%", backgroundColor: "#000b" } }); React11.useEffect(() => { if (open) { setShow(open); setTimeout(() => { setShowSecondary(open); }, 500); } else { closeAction(); } }, [open]); const closeAction = () => { setShowSecondary(false); setTimeout(() => { setShow(false); onClose(); }, 300); }; return /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement( Modal, { transparent: true, animationType: "fade", statusBarTranslucent: true, visible: show, onRequestClose: closeAction }, /* @__PURE__ */ React11.createElement(View5, { style: styles2.backdrop }), /* @__PURE__ */ React11.createElement(UIThemeProvider, null, /* @__PURE__ */ React11.createElement( Modal, { transparent: true, animationType: "slide", statusBarTranslucent: true, visible: showSecondary, onRequestClose: closeAction }, /* @__PURE__ */ React11.createElement(TouchableWithoutFeedback2, { onPress: Keyboard2.dismiss }, /* @__PURE__ */ React11.createElement(View5, { style: styles2.root }, open && /* @__PURE__ */ React11.createElement( Pressable, { style: StyleSheet2.absoluteFill, onPress: closeAction } ), /* @__PURE__ */ React11.createElement( KeyboardAvoidingView2, { style: styles2.avoidingView, keyboardVerticalOffset, behavior: Platform5.OS === "ios" ? "position" : "padding" }, /* @__PURE__ */ React11.createElement(View5, { style: styles2.container }, !bare && /* @__PURE__ */ React11.createElement(View5, { style: styles2.title }, /* @__PURE__ */ React11.createElement(View5, { style: styles2.titleIcon }, /* @__PURE__ */ React11.createElement( IconButton, { size: 20, icon: "close", onPress: closeAction } )), /* @__PURE__ */ React11.createElement(Typography_default, { align: "center", fontWeight: 500 }, title)), /* @__PURE__ */ React11.createElement(View5, { style: styles2.content }, children)) ))) )) )); }; // ../src/Components/StarRating.tsx var RatingStars = ({ rating = 0, size = 16 }) => { const colors2 = useColors(); const styles2 = ScaledSheet8.create({ root: { flexDirection: "row", alignItems: "center" } }); return /* @__PURE__ */ React.createElement(View6, { style: styles2.root }, [...Array(Math.floor(rating))].map((_, index) => /* @__PURE__ */ React.createElement(Ionicons2, { key: index, name: "star", size, color: "#FFD700" })), [...Array(5 - Math.floor(rating))].map((_, index) => /* @__PURE__ */ React.createElement( Ionicons2, { key: index, name: "star", size, color: colors2.textSecondary.light } ))); }; var RatingInput = ({ onSubmit: _onSubmit, rating = 0, size = 16 }) => { const [showReviewsModal, setShowReviewsModal] = useState4(false); const [rate, setRate] = useState4(0); const colors2 = useColors(); const [loading, setLoading] = useState4(false); const [review, setReview] = useState4(""); const styles2 = ScaledSheet8.create({ root: { flexDirection: "row", alignItems: "center" }, inputCon: { marginBottom: "20@vs", backgroundColor: colors2.white[3], padding: "15@ms", borderRadius: 20 }, input: { fontSize: "16@ms", color: colors2.dark.main, height: "100@vs" } }); useEffect3(() => { setRate(rating); }, [rating]); const onRate = (index) => { setRate(index + 1); Haptics.selectionAsync(); setTimeout(() => { setShowReviewsModal(true); }, 500); }; const onSubmit = async () => { setLoading(true); setShowReviewsModal(false); _onSubmit && await _onSubmit({ rating: rate, review }); setLoading(false); }; return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(View6, { style: styles2.root }, loading ? /* @__PURE__ */ React.createElement(ActivityIndicator2, null) : [...Array(5)].map((_, index) => /* @__PURE__ */ React.createElement( TouchableOpacity4, { key: index, activeOpacity: 0.9, onPress: () => { onRate(index); } }, /* @__PURE__ */ React.createElement( Ionicons2, { style: { marginLeft: 10 }, name: index < rate ? "star" : "star-outline", size, color: colors2.primary.light } ) ))), /* @__PURE__ */ React.createElement( Popup, { sheet: true, open: showReviewsModal, onClose: () => { setShowReviewsModal(false); } }, /* @__PURE__ */ React.createElement( View6, { style: { alignItems: "center", marginBottom: 5 } }, /* @__PURE__ */ React.createElement(RatingStars, { rating: rate, size: 24 }) ), /* @__PURE__ */ React.createElement( Typography_default, { align: "center", fontWeight: 700, variant: "h5", gutterBottom: 20 }, "Add to your review" ), /* @__PURE__ */ React.createElement(View6, { style: styles2.inputCon }, /* @__PURE__ */ React.createElement( TextInput, { style: styles2.input, multiline: true, value: review, onChangeText: (text) => setReview(text), placeholder: "Type review here.." } )), /* @__PURE__ */ React.createElement( Button_default, { gutterBottom: 40, title: "Submit Review", loading, disabled: loading, onPress: () => { onSubmit(); } } ) )); }; // ../src/Components/Grid.tsx import { View as View7 } from "react-native"; import React12 from "react"; import { ScaledSheet as ScaledSheet9 } from "react-native-size-matters"; var GridItem = ({ children, col = 2, alignItems, spacing = 1, style = {} }) => { const styles2 = ScaledSheet9.create({ gridItem: { width: 100 / col + "%", padding: spacing * 10 + "@ms", alignItems } }); return /* @__PURE__ */ React12.createElement(View7, { children, style: [styles2.gridItem, style] }); }; var Grid = ({ children, spacing = 1, style = {} }) => { const styles2 = ScaledSheet9.create({ grid: { flexWrap: "wrap", margin: -spacing * 10 + "@ms", flexDirection: "row" } }); return /* @__PURE__ */ React12.createElement(View7, { children, style: [styles2.grid, style] }); }; // ../src/Components/Locator.tsx import { Ionicons as Ionicons4 } from "@expo/vector-icons"; import React16, { useEffect as useEffect4, useState as useState7 } from "react"; import { Alert, TouchableOpacity as TouchableOpacity8, View as View11 } from "react-native"; // ../src/Components/List.tsx import { MaterialIcons as MaterialIcons3 } from "@expo/vector-icons"; import React13 from "react"; import { TouchableOpacity as TouchableOpacity5, View as View8 } from "react-native"; import { ScaledSheet as ScaledSheet10 } from "react-native-size-matters"; var ListItem = ({ link = false, divider = false, onPress, index = 1, style = {}, children }) => { const colors2 = useColors(); const styles2 = ScaledSheet10.create({ root: { flexDirection: "row", alignItems: "center", paddingHorizontal: "10@s", borderBottomColor: colors2.white[2], borderBottomWidth: divider ? 1 : 0, paddingVertical: "10@vs" } }); return /* @__PURE__ */ React13.createElement( View8, null, /* @__PURE__ */ React13.createElement(TouchableOpacity5, { disabled: Boolean(!onPress), onPress }, /* @__PURE__ */ React13.createElement(View8, { style: { ...styles2.root, ...style } }, children, link && /* @__PURE__ */ React13.createElement( MaterialIcons3, { color: colors2.white[5], style: { marginLeft: "auto" }, name: "arrow-forward-ios", size: 15 } ))) ); }; // ../src/Components/TextField.tsx import { Ionicons as Ionicons3, MaterialIcons as MaterialIcons5 } from "@expo/vector-icons"; import React15, { useRef, useState as useState6 } from "react"; import { Animated, TextInput as TextInput2, TouchableOpacity as TouchableOpacity7, View as View10 } from "react-native"; import { ScaledSheet as ScaledSheet12, moderateScale as moderateScale3, ms, verticalScale as verticalScale2 } from "react-native-size-matters"; // ../src/Components/SelectMenu.tsx import { MaterialIcons as MaterialIcons4 } from "@expo/vector-icons"; import React14, { useCallback, useState as useState5 } from "react"; import { FlatList, Modal as Modal2, TouchableOpacity as TouchableOpacity6, View as View9 } from "react-native"; import { useSafeAreaInsets as useSafeAreaInsets2 } from "react-native-safe-area-context"; import { ScaledSheet as ScaledSheet11 } from "react-native-size-matters"; var SelectMenu = ({ open = false, onClose, value, options = [], onChange, disableAutoClose = false, label, secondary, helperText }) => { const colors2 = useColors(); const { bottom } = useSafeAreaInsets2(); const [search, setSearch] = useState5(""); const styles2 = ScaledSheet11.create({ root: { backgroundColor: colors2.white[1], flex: 1 }, content: { flex: 1, paddingHorizontal: "10@ms" }, header: { paddingTop: "80@ms", marginBottom: "20@vs" }, option: { paddingHorizontal: "10@s", paddingVertical: "10@vs", borderRadius: 8, flexDirection: "row", alignItems: "center", marginBottom: "10@vs" }, footer: { paddingBottom: bottom, paddingHorizontal: "15@ms", paddingTop: "15@ms" } }); const renderItem = useCallback( ({ item }) => /* @__PURE__ */ React14.createElement( TouchableOpacity6, { style: { ...styles2.option, backgroundColor: item.value === value ? colors2.blue.light + "22" : colors2.white[2] }, onPress: () => { onChange(item.value); if (!disableAutoClose) onClose(); }, key: item.label }, item.start && /* @__PURE__ */ React14.createElement(View9, { style: { marginRight: 10 } }, item.start), /* @__PURE__ */ React14.createElement(View9, { style: { flex: 1 } }, /* @__PURE__ */ React14.createElement( Typography_default, { style: { color: item.value === value ? colors2.blue.light : colors2.black[2] } }, item.label ), item.secondary ? /* @__PURE__ */ React14.createElement( Typography_default, { variant: "body2", style: { marginTop: 2, color: item.value === value ? colors2.blue.light : colors2.white[5] } }, item.secondary ) : null), value === item.value && /* @__PURE__ */ React14.createElement( MaterialIcons4, { name: "check", color: colors2.blue.light, size: 24, style: { marginLeft: "auto" } } ) ), [value, colors2] ); return /* @__PURE__ */ React14.createElement(Modal2, { visible: open, animationType: "slide", onRequestClose: onClose }, /* @__PURE__ */ React14.createElement(View9, { style: styles2.root }, /* @__PURE__ */ React14.createElement(View9, { style: styles2.content }, /* @__PURE__ */ React14.createElement(View9, { style: styles2.header }, /* @__PURE__ */ React14.createElement(Typography_default, { variant: "h5", gutterBottom: 5, fontWeight: 700 }, label), helperText ? /* @__PURE__ */ React14.createElement(Typography_default, { variant: "body2", color: "textSecondary" }, helperText) : null, /* @__PURE__ */ React14.createElement( TextField_default, { label: "Search", value: search, type: "search", onChangeText: setSearch, variant: "outlined" } )), /* @__PURE__ */ React14.createElement( FlatList, { removeClippedSubviews: true, keyExtractor: (item) => item.value, renderItem, data: options.filter( (item) => search.length > 1 ? item.label.toLowerCase().indexOf(search.toLowerCase()) > -1 : item ).sort((a, b) => a.label.localeCompare(b.label)) } )), /* @__PURE__ */ React14.createElement(View9, { style: styles2.footer }, /* @__PURE__ */ React14.createElement( Button_default, { color: "error", variant: "outlined", fullWidth: true, title: "Close", onPress: onClose } )))); }; var SelectMenu_default = SelectMenu; // ../src/Components/TextField.tsx var TextField = ({ label, keyboardType, variant, color = "primary", value, type, helperText, onChangeText, onSubmitEditing = () => { }, onFocus = () => { }, onBlur = () => { }, error, start, size = "normal", rounded, disabled = false, style = {}, inputStyles = {}, gutterBottom = 0, end, options, ...props }) => { const colors2 = useColors(); const [focused, setFocused] = useState6(false); const height = moderateScale3(variant === "text" ? 50 : 45) * (size === "large" ? 1.2 : size === "small" ? 0.8 : 1); const labelAnim = useRef( new Animated.Value(height / moderateScale3(variant === "text" ? 2.5 : 3.2)) ).current; React15.useEffect(() => { if (focused || value) { Animated.timing(labelAnim, { toValue: verticalScale2(variant === "text" ? 2 : 4), duration: 300, useNativeDriver: false }).start(); } else { Animated.timing(labelAnim, { toValue: height / moderateScale3(variant === "text" ? 2.5 : 3.2), duration: 300, useNativeDriver: false }).start(); } }, [focused, value]); const styles2 = ScaledSheet12.create({ root: { marginBottom: gutterBottom + "@vs", width: "100%", ...style }, container: { height, overflow: "hidden", backgroundColor: variant === "outlined" || variant === "text" ? "#fff0" : focused ? colors2.white[3] : colors2.white[4], flexDirection: "row", borderColor: error ? colors2.error.main : focused ? colors2[color].main : colors2.textSecondary.main, borderWidth: error ? 1 : variant === "outlined" ? focused ? 2 : 0.5 : 0, borderBottomWidth: variant === "text" ? 0.5 : void 0, width: "100%", borderRadius: variant === "text" ? 0 : rounded ? 30 : 7, alignItems: "center", ...inputStyles }, input: { fontSize: "14@s", flex: 1, alignSelf: "stretch", paddingLeft: variant === "text" ? 0 : moderateScale3(15), paddingRight: moderateScale3(10), paddingTop: "11@vs", fontFamily: getConfig().DEFAULT_FONT_FAMILY || "System", color: colors2.black[1], zIndex: 10 // backgroundColor: "#284", }, inputText: { fontSize: "14@ms", flex: 1, paddingLeft: variant === "text" ? 0 : moderateScale3(15), paddingTop: "13@ms" }, label: { fontFamily: getConfig().DEFAULT_FONT_FAMILY || "System", position: "absolute", left: variant === "text" ? 0 : moderateScale3(15), fontSize: focused || value ? "10@s" : "13@s", color: focused ? colors2[color].main : colors2.textSecondary.main }, helperText: { paddingHorizontal: "15@s", flex: 1, color: focused ? colors2[color].dark : colors2.textSecondary.main, paddingTop: "4@ms" }, error: { paddingLeft: 10, paddingRight: 10, paddingTop: 5, flexDirection: "row", alignItems: "center" }, errorText: { fontSize: 12, marginLeft: 10 } }); const formProps = type === "email" ? { textContentType: "emailAddress", keyboardType: "email-address", autoCapitalize: "none", autoCompleteType: "email" } : type === "number" ? { keyboardType: "numeric" } : type === "tel" ? { textContentType: "telephoneNumber", keyboardType: "phone-pad" } : type === "search" ? { keyboardType: "web-search", returnKeyType: "search", autoCapitalize: "none" } : type === "password" ? { secureTextEntry: true, autoCompleteType: "password", autoCapitalize: "none", textContentType: "password" } : {}; return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(View10, { style: styles2.root }, /* @__PURE__ */ React15.createElement( TouchableOpacity7, { onPress: () => setFocused(true), style: styles2.container }, /* @__PURE__ */ React15.createElement(Animated.Text, { style: { ...styles2.label, top: labelAnim } }, label), start, options ? /* @__PURE__ */ React15.createElement( View10, { style: { flex: 1, alignItems: "center", flexDirection: "row" } }, options.find((cur) => cur.value === value)?.start && /* @__PURE__ */ React15.createElement( View10, { style: { paddingTop: variant !== "outlined" ? ms(13) : 0, paddingRight: 10 } }, options.find((cur) => cur.value === value)?.start ), /* @__PURE__ */ React15.createElement(Typography_default, { style: styles2.inputText }, options.find((cur) => cur.value === value)?.label) ) : /* @__PURE__ */ React15.createElement( TextInput2, { onFocus: () => { onFocus(); setFocused(true); }, onBlur: () => { onBlur(); setFocused(false); }, value, onChangeText, keyboardType, editable: !disabled, selectTextOnFocus: !disabled, onSubmitEditing, placeholderTextColor: colors2.textSecondary.main, ...formProps, ...props, style: styles2.input } ), end && /* @__PURE__ */ React15.createElement( View10, { style: { marginRight: 20, paddingTop: variant === "text" ? ms(13) : 0 } }, end ), options && /* @__PURE__ */ React15.createElement( View10, { style: { marginRight: variant === "text" ? 0 : 20, paddingTop: variant === "text" ? ms(13) : 0 } }, /* @__PURE__ */ React15.createElement( Ionicons3, { name: "chevron-down", color: colors2.textSecondary.main, size: 24 } ) ) ), helperText && /* @__PURE__ */ React15.createElement( Typography_default, { color: "textSecondary", style: styles2.helperText, variant: "caption" }, helperText ), error && /* @__PURE__ */ React15.createElement(View10, { style: styles2.error }, /* @__PURE__ */ React15.createElement(MaterialIcons5, { name: "error", color: colors2.error.main, size: 16 }), /* @__PURE__ */ React15.createElement(Typography_default, { style: styles2.errorText, color: "error" }, error))), options && /* @__PURE__ */ React15.createElement( SelectMenu_default, { options, value, open: focused, onClose: () => setFocused(false), label, helperText, onChange: onChangeText } )); }; var TextField2 = React15.forwardRef( ({ label, keyboardType, color = "primary", value, type, helperText, onChangeText, onSubmitEditing = () => { }, onFocus = () => { }, onBlur = () => { }, error, start, rounded, disabled = false, style = {}, inputStyles = {}, gutterBottom = 8, placeholder, end, options, multiline, ...props }, ref) => { const colors2 = useColors(); const [focused, _setFocused] = useState6(false); const [showPassword, setShowPassword] = useState6(false); const height = moderateScale3( multiline ? 50 + (props.numberOfLines || 1) * 18 : 50 ); const setFocused = (value2) => { _setFocused(value2); }; const styles2 = ScaledSheet12.create({ root: { marginBottom: gutterBottom + "@vs", ...style }, container: { height, overflow: "hidden", flexDirection: "row", borderColor: error ? colors2.error.main : focused ? colors2[color].main : colors2.white[4], borderWidth: error ? 1 : focused ? 2 : 1, width: "100%", borderRadius: rounded ? 30 : 10, alignItems: multiline ? "flex-start" : "center", paddingVertical: multiline ? 10 : 0, ...inputStyles }, input: { fontSize: "14@s", flex: 1, alignSelf: "stretch", paddingLeft: moderateScale3(10), paddingRight: moderateScale3(10), color: colors2.dark.main, zIndex: 10 // backgroundColor: "#284", }, inputText: { fontSize: "14@ms", color: colors2.dark.main, paddingLeft: moderateScale3(10) }, placeholder: { fontSize: "14@ms", color: colors2.textSecondary.light, paddingLeft: moderateScale3(10) }, label: {}, helperText: { paddingHorizontal: "15@s", color: focused ? colors2[color].dark : "#fffa", paddingTop: "4@ms" }, error: { paddingLeft: 10, paddingRight: 10, paddingTop: 5, flexDirection: "row", alignItems: "center" }, errorText: { fontSize: 12, marginLeft: 10 } }); const formProps = type === "email" ? { textContentType: "emailAddress", keyboardType: "email-address", autoCapitalize: "none", autoCompleteType: "email" } : type === "number" ? { keyboardType: "numeric" } : type === "tel" ? { textContentType: "telephoneNumber", keyboardType: "phone-pad" } : type === "search" ? { keyboardType: "web-search", returnKeyType: "search", autoCapitalize: "none" } : type === "password" ? { secureTextEntry: !showPassword, autoCompleteType: "password", autoCapitalize: "none", textContentType: "password" } : {}; return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(View10, { style: styles2.root }, label && /* @__PURE__ */ React15.createElement(Typography_default, { variant: "body1", color: "textSecondary", gutterBottom: 7 }, label), /* @__PURE__ */ React15.createElement( TouchableOpacity7, { onPress: () => setFocused(true), style: styles2.container }, /* @__PURE__ */ React15.createElement(View10, { style: { marginTop: multiline ? 5 : 0 } }, start), options ? /* @__PURE__ */ React15.createElement(React15.Fragment, null, value ? /* @__PURE__ */ React15.createElement(Typography_default, { style: styles2.inputText }, options.find((cur) => cur.value === value)?.label) : /* @__PURE__ */ React15.createElement(Typography_default, { style: styles2.placeholder }, placeholder), /* @__PURE__ */ React15.createElement( Ionicons3, { name: "chevron-down", size: 24, style: { marginLeft: "auto", marginRight: 15 }, color: colors2.dark.light } )) : /* @__PURE__ */ React15.createElement( TextInput2, { ref, onFocus: () => { onFocus(); setFocused(true); }, onBlur: () => { onBlur(); setFocused(false); }, value, onChangeText, key: showPassword ? "show" : "hide", keyboardType, placeholderTextColor: colors2.textSecondary.light, editable: !disabled, placeholder, selectTextOnFocus: !disabled, onSubmitEditing, multiline, textAlignVertical: multiline ? "top" : "center", ...formProps, ...props, style: styles2.input } ), end ? /* @__PURE__ */ React15.createElement(View10, { style: { marginRight: 20 } }, end) : type === "password" && /* @__PURE__ */ React15.createElement( TouchableOpacity7, { style: { marginRight: 20 }, onPress: () => setShowPassword(!s