@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
JavaScript
// ../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