@hoddy-ui/core 1.0.5 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/Components/Checkbox.tsx +36 -0
- package/src/Components/FlashMessage.tsx +57 -0
- package/src/Components/FormWrapper.tsx +58 -0
- package/src/Components/Grid.tsx +33 -0
- package/src/Components/List.tsx +98 -0
- package/src/Components/Locator.tsx +225 -0
- package/src/Components/Popup.tsx +99 -0
- package/src/Components/SelectMenu.tsx +89 -75
- package/src/Components/TextField.tsx +51 -19
- package/src/config/KeyManager.ts +13 -0
- package/src/config/index.ts +39 -0
- package/src/hooks.ts +2 -2
- package/src/theme/colors.ts +25 -12
- package/src/types.ts +9 -4
package/package.json
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Pressable, StyleSheet, Text, View } from "react-native";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { MaterialCommunityIcons } from "@expo/vector-icons";
|
|
4
|
+
|
|
5
|
+
const CheckBox = (props: any) => {
|
|
6
|
+
const iconName = props.isChecked
|
|
7
|
+
? "checkbox-marked"
|
|
8
|
+
: "checkbox-blank-outline";
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<View style={styles.container}>
|
|
12
|
+
<Pressable onPress={props.onPress}>
|
|
13
|
+
<MaterialCommunityIcons name={iconName} size={24} color="#0195FF" />
|
|
14
|
+
</Pressable>
|
|
15
|
+
</View>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default CheckBox;
|
|
20
|
+
|
|
21
|
+
const styles = StyleSheet.create({
|
|
22
|
+
container: {
|
|
23
|
+
justifyContent: "flex-start",
|
|
24
|
+
alignItems: "center",
|
|
25
|
+
flexDirection: "row",
|
|
26
|
+
width: 20,
|
|
27
|
+
marginTop: 5,
|
|
28
|
+
marginRight: 10,
|
|
29
|
+
},
|
|
30
|
+
title: {
|
|
31
|
+
fontSize: 16,
|
|
32
|
+
color: "#000",
|
|
33
|
+
marginLeft: 5,
|
|
34
|
+
fontWeight: "600",
|
|
35
|
+
},
|
|
36
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import { View } from "react-native";
|
|
3
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
4
|
+
import { ScaledSheet } from "react-native-size-matters";
|
|
5
|
+
import { useColors } from "../hooks";
|
|
6
|
+
import { FlashMessageProps } from "../types";
|
|
7
|
+
import Typography from "./Typography";
|
|
8
|
+
|
|
9
|
+
const FlashMessage: React.FC<FlashMessageProps> = ({
|
|
10
|
+
title,
|
|
11
|
+
message,
|
|
12
|
+
type,
|
|
13
|
+
}) => {
|
|
14
|
+
const { top } = useSafeAreaInsets();
|
|
15
|
+
const colors = useColors();
|
|
16
|
+
const [show, setShow] = useState(false);
|
|
17
|
+
const styles = ScaledSheet.create({
|
|
18
|
+
root: {
|
|
19
|
+
position: "absolute",
|
|
20
|
+
top: 0,
|
|
21
|
+
zIndex: 1000,
|
|
22
|
+
left: 0,
|
|
23
|
+
paddingTop: top + 10,
|
|
24
|
+
paddingHorizontal: "15@ms",
|
|
25
|
+
backgroundColor: colors[type].main,
|
|
26
|
+
width: "100%",
|
|
27
|
+
paddingBottom: "10@ms",
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (message) setShow(true);
|
|
32
|
+
setTimeout(() => {
|
|
33
|
+
setShow(false);
|
|
34
|
+
}, 2000);
|
|
35
|
+
}, [message]);
|
|
36
|
+
return show ? (
|
|
37
|
+
<View style={styles.root}>
|
|
38
|
+
{title && (
|
|
39
|
+
<Typography
|
|
40
|
+
variant="body2"
|
|
41
|
+
fontWeight={600}
|
|
42
|
+
gutterBottom={3}
|
|
43
|
+
style={{ color: "#fff" }}
|
|
44
|
+
>
|
|
45
|
+
{title}
|
|
46
|
+
</Typography>
|
|
47
|
+
)}
|
|
48
|
+
<Typography fontWeight={700} style={{ color: "#fff" }}>
|
|
49
|
+
{message}
|
|
50
|
+
</Typography>
|
|
51
|
+
</View>
|
|
52
|
+
) : (
|
|
53
|
+
<></>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export default FlashMessage;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Keyboard,
|
|
4
|
+
KeyboardAvoidingView,
|
|
5
|
+
ScrollView,
|
|
6
|
+
TouchableWithoutFeedback,
|
|
7
|
+
View,
|
|
8
|
+
} from "react-native";
|
|
9
|
+
import { ScaledSheet } from "react-native-size-matters";
|
|
10
|
+
import { FormWrapperProps } from "../types";
|
|
11
|
+
const FormWrapper: React.FC<FormWrapperProps> = ({
|
|
12
|
+
children,
|
|
13
|
+
behavior = "position",
|
|
14
|
+
contentContainerStyle,
|
|
15
|
+
mode = "scroll",
|
|
16
|
+
keyboardVerticalOffset = 50,
|
|
17
|
+
style = {},
|
|
18
|
+
onScroll,
|
|
19
|
+
}) => {
|
|
20
|
+
const styles = ScaledSheet.create({
|
|
21
|
+
root: {
|
|
22
|
+
width: "100%",
|
|
23
|
+
flex: 1,
|
|
24
|
+
...style,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
return mode === "static" ? (
|
|
28
|
+
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
|
|
29
|
+
<KeyboardAvoidingView
|
|
30
|
+
style={styles.root}
|
|
31
|
+
behavior={behavior}
|
|
32
|
+
contentContainerStyle={styles.root}
|
|
33
|
+
keyboardVerticalOffset={keyboardVerticalOffset}
|
|
34
|
+
>
|
|
35
|
+
{children}
|
|
36
|
+
</KeyboardAvoidingView>
|
|
37
|
+
</TouchableWithoutFeedback>
|
|
38
|
+
) : (
|
|
39
|
+
<ScrollView
|
|
40
|
+
onScroll={onScroll}
|
|
41
|
+
showsVerticalScrollIndicator={false}
|
|
42
|
+
scrollEventThrottle={40}
|
|
43
|
+
keyboardDismissMode="interactive"
|
|
44
|
+
contentContainerStyle={contentContainerStyle}
|
|
45
|
+
keyboardShouldPersistTaps="handled"
|
|
46
|
+
>
|
|
47
|
+
<KeyboardAvoidingView
|
|
48
|
+
behavior={behavior}
|
|
49
|
+
style={styles.root}
|
|
50
|
+
keyboardVerticalOffset={keyboardVerticalOffset}
|
|
51
|
+
>
|
|
52
|
+
{children}
|
|
53
|
+
</KeyboardAvoidingView>
|
|
54
|
+
</ScrollView>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default FormWrapper;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { View, Text } from "react-native";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { ScaledSheet } from "react-native-size-matters";
|
|
4
|
+
import { GridItemProps, GridProps } from "../types";
|
|
5
|
+
|
|
6
|
+
export const GridItem: React.FC<GridItemProps> = ({
|
|
7
|
+
children,
|
|
8
|
+
col = 2,
|
|
9
|
+
alignItems,
|
|
10
|
+
spacing = 1,
|
|
11
|
+
style = {},
|
|
12
|
+
}) => {
|
|
13
|
+
const styles = ScaledSheet.create({
|
|
14
|
+
gridItem: {
|
|
15
|
+
width: 100 / col + "%",
|
|
16
|
+
padding: spacing * 10 + "@ms",
|
|
17
|
+
alignItems: alignItems,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
return <View children={children} style={[styles.gridItem, style]} />;
|
|
21
|
+
};
|
|
22
|
+
const Grid: React.FC<GridProps> = ({ children, spacing = 1, style = {} }) => {
|
|
23
|
+
const styles = ScaledSheet.create({
|
|
24
|
+
grid: {
|
|
25
|
+
flexWrap: "wrap",
|
|
26
|
+
marginHorizontal: -spacing * 10 + "@ms",
|
|
27
|
+
flexDirection: "row",
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
return <View children={children} style={[styles.grid, style]} />;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default Grid;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { MaterialIcons } from "@expo/vector-icons";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { TouchableOpacity, View } from "react-native";
|
|
4
|
+
import { ScaledSheet } from "react-native-size-matters";
|
|
5
|
+
import { useColors } from "../hooks";
|
|
6
|
+
import { ListItemProps, ListItemTextProps, ListProps } from "../types";
|
|
7
|
+
import Typography from "./Typography";
|
|
8
|
+
|
|
9
|
+
export const ListItemText: React.FC<ListItemTextProps> = ({
|
|
10
|
+
primary,
|
|
11
|
+
divider,
|
|
12
|
+
primaryProps = {},
|
|
13
|
+
secondaryProps = {},
|
|
14
|
+
secondary,
|
|
15
|
+
style = {},
|
|
16
|
+
}) => {
|
|
17
|
+
const colors = useColors();
|
|
18
|
+
const styles = ScaledSheet.create({
|
|
19
|
+
container: {
|
|
20
|
+
borderBottomColor: colors.white[4],
|
|
21
|
+
borderBottomWidth: divider ? 1 : 0,
|
|
22
|
+
paddingVertical: 0,
|
|
23
|
+
flexGrow: 1,
|
|
24
|
+
...style,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
return (
|
|
28
|
+
<View style={styles.container}>
|
|
29
|
+
{primary && (
|
|
30
|
+
<Typography
|
|
31
|
+
style={{ alignItems: "center" }}
|
|
32
|
+
variant="body1"
|
|
33
|
+
gutterBottom={2}
|
|
34
|
+
{...primaryProps}
|
|
35
|
+
>
|
|
36
|
+
{primary}
|
|
37
|
+
</Typography>
|
|
38
|
+
)}
|
|
39
|
+
{secondary && (
|
|
40
|
+
<Typography variant="body2" color="textSecondary" {...secondaryProps}>
|
|
41
|
+
{secondary}
|
|
42
|
+
</Typography>
|
|
43
|
+
)}
|
|
44
|
+
</View>
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
export const ListItem: React.FC<ListItemProps> = ({
|
|
48
|
+
link = false,
|
|
49
|
+
divider = false,
|
|
50
|
+
onPress,
|
|
51
|
+
index = 1,
|
|
52
|
+
style = {},
|
|
53
|
+
children,
|
|
54
|
+
}) => {
|
|
55
|
+
const colors = useColors();
|
|
56
|
+
|
|
57
|
+
const styles: any = ScaledSheet.create({
|
|
58
|
+
root: {
|
|
59
|
+
flexDirection: "row",
|
|
60
|
+
alignItems: "center",
|
|
61
|
+
paddingHorizontal: "10@s",
|
|
62
|
+
borderBottomColor: colors.white[4],
|
|
63
|
+
borderBottomWidth: divider ? 1 : 0,
|
|
64
|
+
paddingVertical: "10@vs",
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
return (
|
|
68
|
+
<View
|
|
69
|
+
|
|
70
|
+
// layout={Layout.springify()}
|
|
71
|
+
// exiting={SlideOutDown.delay(index * 100)}
|
|
72
|
+
// entering={SlideInUp.delay(index * 100)}
|
|
73
|
+
>
|
|
74
|
+
<TouchableOpacity disabled={Boolean(!onPress)} onPress={onPress}>
|
|
75
|
+
<View style={{ ...styles.root, ...style }}>
|
|
76
|
+
{children}
|
|
77
|
+
{link && (
|
|
78
|
+
<MaterialIcons
|
|
79
|
+
color={colors.white[5]}
|
|
80
|
+
name="arrow-forward-ios"
|
|
81
|
+
size={15}
|
|
82
|
+
/>
|
|
83
|
+
)}
|
|
84
|
+
</View>
|
|
85
|
+
</TouchableOpacity>
|
|
86
|
+
</View>
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
export const List: React.FC<ListProps> = ({ style = {}, children }) => {
|
|
90
|
+
const styles = ScaledSheet.create({
|
|
91
|
+
root: {
|
|
92
|
+
flex: 1,
|
|
93
|
+
paddingHorizontal: "20@ms",
|
|
94
|
+
...style,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
return <View style={styles.root}>{children}</View>;
|
|
98
|
+
};
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { Ionicons } from "@expo/vector-icons";
|
|
2
|
+
import React, { useState } from "react";
|
|
3
|
+
import { Alert, TouchableOpacity, View } from "react-native";
|
|
4
|
+
import { ListItem } from "./List";
|
|
5
|
+
import TextField from "./TextField";
|
|
6
|
+
|
|
7
|
+
import * as Location from "expo-location";
|
|
8
|
+
import { ScaledSheet } from "react-native-size-matters";
|
|
9
|
+
import { useColors } from "../hooks";
|
|
10
|
+
import { LocatorProps } from "../types";
|
|
11
|
+
|
|
12
|
+
// import { GOOGLE_MAP_API } from "../../api/config";
|
|
13
|
+
import Typography from "./Typography";
|
|
14
|
+
import { GOOGLE_MAP_API_KEY } from "../../api/config";
|
|
15
|
+
|
|
16
|
+
Location.setGoogleApiKey(GOOGLE_MAP_API_KEY);
|
|
17
|
+
|
|
18
|
+
type predictionType = {
|
|
19
|
+
id: string;
|
|
20
|
+
description: string;
|
|
21
|
+
};
|
|
22
|
+
export const getPredictionsFromCoords = async (coords: any) => {
|
|
23
|
+
if (!coords) return [];
|
|
24
|
+
const res = await (
|
|
25
|
+
await fetch(
|
|
26
|
+
`https://maps.googleapis.com/maps/api/geocode/json?radius=200&latlng=${coords.latitude},${coords.longitude}&key=${GOOGLE_MAP_API_KEY}`
|
|
27
|
+
)
|
|
28
|
+
).json();
|
|
29
|
+
|
|
30
|
+
const p = [];
|
|
31
|
+
|
|
32
|
+
for (let key in res.results) {
|
|
33
|
+
const { formatted_address: description, place_id } = res.results[key];
|
|
34
|
+
p.push({
|
|
35
|
+
description,
|
|
36
|
+
id: place_id,
|
|
37
|
+
latLng: { lst: coords.latitude, lng: coords.longitude },
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return p;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const Locator: React.FC<LocatorProps> = ({
|
|
45
|
+
variant = "contained",
|
|
46
|
+
onLocationSelected,
|
|
47
|
+
label,
|
|
48
|
+
error,
|
|
49
|
+
location = {
|
|
50
|
+
description: null,
|
|
51
|
+
},
|
|
52
|
+
renderInput,
|
|
53
|
+
gutterBottom = 0,
|
|
54
|
+
helperText,
|
|
55
|
+
float = true,
|
|
56
|
+
country = "ng",
|
|
57
|
+
}) => {
|
|
58
|
+
const [changed, setChanged] = useState(false);
|
|
59
|
+
const [value, setValue] = useState("");
|
|
60
|
+
const [prediction, setPrediction] = useState<predictionType[]>([]);
|
|
61
|
+
const colors = useColors();
|
|
62
|
+
const styles: any = ScaledSheet.create({
|
|
63
|
+
list: {
|
|
64
|
+
backgroundColor: colors.white[2],
|
|
65
|
+
elevation: 10,
|
|
66
|
+
shadowColor: "#000",
|
|
67
|
+
shadowOpacity: 0.1,
|
|
68
|
+
shadowRadius: float ? 15 : 0,
|
|
69
|
+
shadowOffset: {
|
|
70
|
+
height: 10,
|
|
71
|
+
},
|
|
72
|
+
borderRadius: 10,
|
|
73
|
+
marginBottom: 10,
|
|
74
|
+
width: "100%",
|
|
75
|
+
zIndex: 1000,
|
|
76
|
+
marginTop: float ? 2 : "15@ms",
|
|
77
|
+
top: float ? "100%" : undefined,
|
|
78
|
+
position: float ? "absolute" : "relative",
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
const search = async (query: string) => {
|
|
82
|
+
const endpoint = `https://maps.googleapis.com/maps/api/place/autocomplete/json?input=${query}&components=country:${country}&radius=20000&location=6.465422,3.406448&key=${GOOGLE_MAP_API_KEY}`;
|
|
83
|
+
const res = await (await fetch(endpoint)).json();
|
|
84
|
+
const p = [];
|
|
85
|
+
for (let key in res.predictions) {
|
|
86
|
+
const { description, place_id } = res.predictions[key];
|
|
87
|
+
p.push({
|
|
88
|
+
description,
|
|
89
|
+
id: place_id,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
setPrediction(p);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const locateMe = () => {
|
|
96
|
+
// Alert.alert(
|
|
97
|
+
// "Use my location",
|
|
98
|
+
// "Auto fill this input with my current location",
|
|
99
|
+
// [{ text: "Cancel" }, { text: "Use Location", onPress: () => getLoc() }]
|
|
100
|
+
// );
|
|
101
|
+
const getLoc = async () => {
|
|
102
|
+
const { status } = await Location.requestForegroundPermissionsAsync();
|
|
103
|
+
if (status !== "granted")
|
|
104
|
+
return Alert.alert(
|
|
105
|
+
"Error",
|
|
106
|
+
"Permission to access location was denied! "
|
|
107
|
+
);
|
|
108
|
+
try {
|
|
109
|
+
let { coords } = await Location.getCurrentPositionAsync({
|
|
110
|
+
accuracy: Location.LocationAccuracy.High,
|
|
111
|
+
});
|
|
112
|
+
const p = await getPredictionsFromCoords(coords);
|
|
113
|
+
setPrediction(p);
|
|
114
|
+
} catch (err) {
|
|
115
|
+
console.log(err);
|
|
116
|
+
Alert.alert(
|
|
117
|
+
"Can't access your location",
|
|
118
|
+
"Make sure your location settings are turned on and you are connected to the internet. "
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
getLoc();
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const clear = () => {
|
|
126
|
+
setPrediction([]);
|
|
127
|
+
setValue("");
|
|
128
|
+
onLocationSelected(null);
|
|
129
|
+
setChanged(false);
|
|
130
|
+
};
|
|
131
|
+
const locationPressed = async (loc: predictionType) => {
|
|
132
|
+
setValue(loc.description);
|
|
133
|
+
const res = await (
|
|
134
|
+
await fetch(
|
|
135
|
+
`https://maps.googleapis.com/maps/api/place/details/json?place_id=${loc.id}&fields=formatted_address%2Cgeometry&key=${GOOGLE_MAP_API_KEY}`
|
|
136
|
+
)
|
|
137
|
+
).json();
|
|
138
|
+
onLocationSelected({
|
|
139
|
+
latitude: res.result?.geometry.location.lat,
|
|
140
|
+
longitude: res.result?.geometry.location.lng,
|
|
141
|
+
description: loc.description,
|
|
142
|
+
});
|
|
143
|
+
setChanged(false);
|
|
144
|
+
setPrediction([]);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<View style={{ zIndex: 100 }}>
|
|
149
|
+
{renderInput ? (
|
|
150
|
+
renderInput({
|
|
151
|
+
onFocus: () => search(value),
|
|
152
|
+
onBlur: () => setPrediction([]),
|
|
153
|
+
value: changed ? value : location?.description || value,
|
|
154
|
+
onChangeText: (val) => {
|
|
155
|
+
setChanged(true);
|
|
156
|
+
setValue(val);
|
|
157
|
+
search(val);
|
|
158
|
+
},
|
|
159
|
+
clear,
|
|
160
|
+
locateMe,
|
|
161
|
+
})
|
|
162
|
+
) : (
|
|
163
|
+
<TextField
|
|
164
|
+
label={label}
|
|
165
|
+
onChangeText={(val) => {
|
|
166
|
+
setChanged(true);
|
|
167
|
+
setValue(val);
|
|
168
|
+
search(val);
|
|
169
|
+
}}
|
|
170
|
+
onBlur={() => {
|
|
171
|
+
setPrediction([]);
|
|
172
|
+
}}
|
|
173
|
+
onFocus={() => {
|
|
174
|
+
search(value);
|
|
175
|
+
}}
|
|
176
|
+
value={changed ? value : location?.description || value}
|
|
177
|
+
gutterBottom={gutterBottom}
|
|
178
|
+
error={error}
|
|
179
|
+
helperText={helperText}
|
|
180
|
+
variant={variant}
|
|
181
|
+
end={
|
|
182
|
+
<View style={{ flexDirection: "row" }}>
|
|
183
|
+
<TouchableOpacity onPress={locateMe} style={{ marginRight: 10 }}>
|
|
184
|
+
<Ionicons
|
|
185
|
+
color={colors.primary.main}
|
|
186
|
+
size={18}
|
|
187
|
+
name="location"
|
|
188
|
+
/>
|
|
189
|
+
</TouchableOpacity>
|
|
190
|
+
<TouchableOpacity onPress={clear}>
|
|
191
|
+
<Ionicons color={colors.dark.main} size={18} name="close" />
|
|
192
|
+
</TouchableOpacity>
|
|
193
|
+
</View>
|
|
194
|
+
}
|
|
195
|
+
/>
|
|
196
|
+
)}
|
|
197
|
+
|
|
198
|
+
{prediction.length > 0 && (
|
|
199
|
+
<View style={styles.list}>
|
|
200
|
+
{prediction.map(
|
|
201
|
+
(cur, i) =>
|
|
202
|
+
i < 5 && (
|
|
203
|
+
<ListItem
|
|
204
|
+
divider={i < prediction.length - 1}
|
|
205
|
+
key={cur.id}
|
|
206
|
+
link
|
|
207
|
+
onPress={() => locationPressed(cur)}
|
|
208
|
+
>
|
|
209
|
+
<Ionicons
|
|
210
|
+
name="location-outline"
|
|
211
|
+
style={{ marginRight: 10 }}
|
|
212
|
+
size={16}
|
|
213
|
+
color={colors.textSecondary.main}
|
|
214
|
+
/>
|
|
215
|
+
<Typography style={{ flex: 1 }}>{cur.description}</Typography>
|
|
216
|
+
</ListItem>
|
|
217
|
+
)
|
|
218
|
+
)}
|
|
219
|
+
</View>
|
|
220
|
+
)}
|
|
221
|
+
</View>
|
|
222
|
+
);
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
export default Locator;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Modal, Pressable, StyleSheet, View } from "react-native";
|
|
2
|
+
|
|
3
|
+
import React, { useState } from "react";
|
|
4
|
+
import { ScaledSheet } from "react-native-size-matters";
|
|
5
|
+
import { useColors } from "../hooks";
|
|
6
|
+
import { PopupProps } from "../types";
|
|
7
|
+
import { IconButton } from "./Button";
|
|
8
|
+
import Typography from "./Typography";
|
|
9
|
+
|
|
10
|
+
const Popup: React.FC<PopupProps> = ({
|
|
11
|
+
title,
|
|
12
|
+
sheet,
|
|
13
|
+
bare = false,
|
|
14
|
+
children,
|
|
15
|
+
open,
|
|
16
|
+
onClose = () => {},
|
|
17
|
+
}) => {
|
|
18
|
+
const colors = useColors();
|
|
19
|
+
const [show, setShow] = useState(open);
|
|
20
|
+
|
|
21
|
+
const styles: any = ScaledSheet.create({
|
|
22
|
+
container: {
|
|
23
|
+
marginTop: sheet ? "auto" : "50%",
|
|
24
|
+
paddingBottom: sheet ? "30@ms" : 0,
|
|
25
|
+
minHeight: sheet,
|
|
26
|
+
maxHeight: "80%",
|
|
27
|
+
backgroundColor: colors.white[2],
|
|
28
|
+
borderTopLeftRadius: 20,
|
|
29
|
+
borderTopRightRadius: 20,
|
|
30
|
+
borderBottomRightRadius: sheet ? 0 : 20,
|
|
31
|
+
borderBottomLeftRadius: sheet ? 0 : 20,
|
|
32
|
+
borderColor: colors.white[5],
|
|
33
|
+
borderWidth: 0,
|
|
34
|
+
alignSelf: "center",
|
|
35
|
+
maxWidth: sheet ? undefined : "90%",
|
|
36
|
+
width: sheet ? "100%" : undefined,
|
|
37
|
+
},
|
|
38
|
+
content: {
|
|
39
|
+
paddingHorizontal: bare ? undefined : "10@ms",
|
|
40
|
+
// flex: 1,
|
|
41
|
+
},
|
|
42
|
+
title: {
|
|
43
|
+
flexDirection: "row",
|
|
44
|
+
alignItems: "center",
|
|
45
|
+
paddingVertical: "5@ms",
|
|
46
|
+
paddingHorizontal: "10@ms",
|
|
47
|
+
marginBottom: "10@ms",
|
|
48
|
+
},
|
|
49
|
+
backdrop: {
|
|
50
|
+
position: "absolute",
|
|
51
|
+
height: "100%",
|
|
52
|
+
width: "100%",
|
|
53
|
+
zIndex: 10000,
|
|
54
|
+
backgroundColor: "#000b",
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
React.useEffect(() => {
|
|
59
|
+
setShow(open);
|
|
60
|
+
}, [open]);
|
|
61
|
+
|
|
62
|
+
const closeAction = () => {
|
|
63
|
+
setShow(false);
|
|
64
|
+
onClose();
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<>
|
|
69
|
+
{open && <Pressable style={styles.backdrop} />}
|
|
70
|
+
<Modal
|
|
71
|
+
transparent
|
|
72
|
+
animationType="slide"
|
|
73
|
+
visible={show}
|
|
74
|
+
onRequestClose={() => setShow(false)}
|
|
75
|
+
>
|
|
76
|
+
{open && (
|
|
77
|
+
<Pressable style={StyleSheet.absoluteFill} onPress={closeAction} />
|
|
78
|
+
)}
|
|
79
|
+
|
|
80
|
+
<View style={styles.container}>
|
|
81
|
+
{!bare && (
|
|
82
|
+
<View style={styles.title}>
|
|
83
|
+
<IconButton size={20} icon="close" onPress={closeAction} />
|
|
84
|
+
<View style={{ flex: 1 }}>
|
|
85
|
+
<Typography color="textSecondary" align="center">
|
|
86
|
+
{title}
|
|
87
|
+
</Typography>
|
|
88
|
+
</View>
|
|
89
|
+
</View>
|
|
90
|
+
)}
|
|
91
|
+
|
|
92
|
+
<View style={styles.content}>{children}</View>
|
|
93
|
+
</View>
|
|
94
|
+
</Modal>
|
|
95
|
+
</>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export default Popup;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { View, Modal, TouchableOpacity, ScrollView } from "react-native";
|
|
3
|
-
import { ScaledSheet } from "react-native-size-matters";
|
|
4
|
-
import Typography from "./Typography";
|
|
5
1
|
import { MaterialIcons } from "@expo/vector-icons";
|
|
6
|
-
import
|
|
2
|
+
import React, { useCallback, useState } from "react";
|
|
3
|
+
import { FlatList, Modal, TouchableOpacity, View } from "react-native";
|
|
4
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
5
|
+
import { ScaledSheet } from "react-native-size-matters";
|
|
7
6
|
import { useColors } from "../hooks";
|
|
8
7
|
import { SelectMenuProps } from "../types";
|
|
9
|
-
import
|
|
8
|
+
import Button from "./Button";
|
|
9
|
+
import TextField from "./TextField";
|
|
10
|
+
import Typography from "./Typography";
|
|
10
11
|
|
|
11
12
|
const SelectMenu: React.FC<SelectMenuProps> = ({
|
|
12
13
|
open = false,
|
|
@@ -21,6 +22,8 @@ const SelectMenu: React.FC<SelectMenuProps> = ({
|
|
|
21
22
|
}) => {
|
|
22
23
|
const colors = useColors();
|
|
23
24
|
const { bottom } = useSafeAreaInsets();
|
|
25
|
+
|
|
26
|
+
const [search, setSearch] = useState("");
|
|
24
27
|
const styles: any = ScaledSheet.create({
|
|
25
28
|
root: {
|
|
26
29
|
backgroundColor: colors.white[1],
|
|
@@ -35,7 +38,6 @@ const SelectMenu: React.FC<SelectMenuProps> = ({
|
|
|
35
38
|
marginBottom: "20@vs",
|
|
36
39
|
},
|
|
37
40
|
|
|
38
|
-
options: {},
|
|
39
41
|
option: {
|
|
40
42
|
paddingHorizontal: "10@s",
|
|
41
43
|
paddingVertical: "10@vs",
|
|
@@ -50,77 +52,89 @@ const SelectMenu: React.FC<SelectMenuProps> = ({
|
|
|
50
52
|
paddingTop: "15@ms",
|
|
51
53
|
},
|
|
52
54
|
});
|
|
55
|
+
|
|
56
|
+
const renderItem = useCallback(
|
|
57
|
+
({ item }: any) => (
|
|
58
|
+
<TouchableOpacity
|
|
59
|
+
style={{
|
|
60
|
+
...styles.option,
|
|
61
|
+
backgroundColor:
|
|
62
|
+
item.value === value ? colors.blue.light + "2" : colors.white[2],
|
|
63
|
+
}}
|
|
64
|
+
onPress={() => {
|
|
65
|
+
onChange(item.value);
|
|
66
|
+
if (!disableAutoClose) onClose();
|
|
67
|
+
}}
|
|
68
|
+
key={item.label}
|
|
69
|
+
>
|
|
70
|
+
{item.start && <View style={{ marginRight: 10 }}>{item.start}</View>}
|
|
71
|
+
<View style={{ flex: 1 }}>
|
|
72
|
+
<Typography
|
|
73
|
+
style={{
|
|
74
|
+
color: item.value === value ? colors.blue.light : colors.black[2],
|
|
75
|
+
}}
|
|
76
|
+
>
|
|
77
|
+
{item.label}
|
|
78
|
+
</Typography>
|
|
79
|
+
{item.secondary ? (
|
|
80
|
+
<Typography
|
|
81
|
+
variant="body2"
|
|
82
|
+
style={{
|
|
83
|
+
marginTop: 2,
|
|
84
|
+
color:
|
|
85
|
+
item.value === value ? colors.blue.light : colors.white[5],
|
|
86
|
+
}}
|
|
87
|
+
>
|
|
88
|
+
{item.secondary}
|
|
89
|
+
</Typography>
|
|
90
|
+
) : null}
|
|
91
|
+
</View>
|
|
92
|
+
{value === item.value && (
|
|
93
|
+
<MaterialIcons
|
|
94
|
+
name="check"
|
|
95
|
+
color={colors.blue.light}
|
|
96
|
+
size={24}
|
|
97
|
+
style={{ marginLeft: "auto" }}
|
|
98
|
+
/>
|
|
99
|
+
)}
|
|
100
|
+
</TouchableOpacity>
|
|
101
|
+
),
|
|
102
|
+
[value, colors]
|
|
103
|
+
);
|
|
53
104
|
return (
|
|
54
105
|
<Modal visible={open} animationType="slide" onRequestClose={onClose}>
|
|
55
106
|
<View style={styles.root}>
|
|
56
|
-
<View style={
|
|
57
|
-
<
|
|
58
|
-
<
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
{helperText
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
style={{
|
|
88
|
-
color:
|
|
89
|
-
cur.value === value
|
|
90
|
-
? colors.blue.light
|
|
91
|
-
: colors.black[2],
|
|
92
|
-
}}
|
|
93
|
-
>
|
|
94
|
-
{cur.label}
|
|
95
|
-
</Typography>
|
|
96
|
-
{cur.secondary ? (
|
|
97
|
-
<Typography
|
|
98
|
-
variant="body2"
|
|
99
|
-
style={{
|
|
100
|
-
marginTop: 2,
|
|
101
|
-
color:
|
|
102
|
-
cur.value === value
|
|
103
|
-
? colors.blue.light
|
|
104
|
-
: colors.white[5],
|
|
105
|
-
}}
|
|
106
|
-
>
|
|
107
|
-
{cur.secondary}
|
|
108
|
-
</Typography>
|
|
109
|
-
) : null}
|
|
110
|
-
</View>
|
|
111
|
-
{value === cur.value && (
|
|
112
|
-
<MaterialIcons
|
|
113
|
-
name="check"
|
|
114
|
-
color={colors.blue.light}
|
|
115
|
-
size={24}
|
|
116
|
-
style={{ marginLeft: "auto" }}
|
|
117
|
-
/>
|
|
118
|
-
)}
|
|
119
|
-
</TouchableOpacity>
|
|
120
|
-
))}
|
|
121
|
-
</View>
|
|
122
|
-
</View>
|
|
123
|
-
</ScrollView>
|
|
107
|
+
<View style={styles.content}>
|
|
108
|
+
<View style={styles.header}>
|
|
109
|
+
<Typography variant="h5" gutterBottom={5} fontWeight={700}>
|
|
110
|
+
{label}
|
|
111
|
+
</Typography>
|
|
112
|
+
{helperText ? (
|
|
113
|
+
<Typography variant="body2" color="textSecondary">
|
|
114
|
+
{helperText}
|
|
115
|
+
</Typography>
|
|
116
|
+
) : null}
|
|
117
|
+
|
|
118
|
+
<TextField
|
|
119
|
+
label="Search"
|
|
120
|
+
value={search}
|
|
121
|
+
type="search"
|
|
122
|
+
onChangeText={setSearch}
|
|
123
|
+
variant="outlined"
|
|
124
|
+
/>
|
|
125
|
+
</View>
|
|
126
|
+
<FlatList
|
|
127
|
+
removeClippedSubviews
|
|
128
|
+
keyExtractor={(item) => item.value}
|
|
129
|
+
renderItem={renderItem}
|
|
130
|
+
data={options
|
|
131
|
+
.filter((item) =>
|
|
132
|
+
search.length > 1
|
|
133
|
+
? item.label.toLowerCase().indexOf(search.toLowerCase()) > -1
|
|
134
|
+
: item
|
|
135
|
+
)
|
|
136
|
+
.sort((a, b) => a.label.localeCompare(b.label))}
|
|
137
|
+
/>
|
|
124
138
|
</View>
|
|
125
139
|
<View style={styles.footer}>
|
|
126
140
|
<Button
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Ionicons, MaterialIcons } from "@expo/vector-icons";
|
|
2
|
-
import React, { useRef, useState } from "react";
|
|
2
|
+
import React, { startTransition, useRef, useState } from "react";
|
|
3
3
|
import { Animated, TextInput, TouchableOpacity, View } from "react-native";
|
|
4
4
|
import {
|
|
5
5
|
ScaledSheet,
|
|
6
6
|
moderateScale,
|
|
7
|
+
ms,
|
|
7
8
|
verticalScale,
|
|
8
9
|
} from "react-native-size-matters";
|
|
9
10
|
import { useColors } from "../hooks";
|
|
@@ -15,7 +16,7 @@ const TextField: React.FC<TextFieldProps> = ({
|
|
|
15
16
|
label,
|
|
16
17
|
keyboardType,
|
|
17
18
|
variant,
|
|
18
|
-
color = "
|
|
19
|
+
color = "primary",
|
|
19
20
|
value,
|
|
20
21
|
type,
|
|
21
22
|
helperText,
|
|
@@ -44,13 +45,13 @@ const TextField: React.FC<TextFieldProps> = ({
|
|
|
44
45
|
React.useEffect(() => {
|
|
45
46
|
if (focused || value) {
|
|
46
47
|
Animated.timing(labelAnim, {
|
|
47
|
-
toValue: variant === "
|
|
48
|
+
toValue: verticalScale(variant === "text" ? 2 : 4),
|
|
48
49
|
duration: 300,
|
|
49
50
|
useNativeDriver: false,
|
|
50
51
|
}).start();
|
|
51
52
|
} else {
|
|
52
53
|
Animated.timing(labelAnim, {
|
|
53
|
-
toValue: height / moderateScale(variant === "text" ? 2 : 3.2),
|
|
54
|
+
toValue: height / moderateScale(variant === "text" ? 2.5 : 3.2),
|
|
54
55
|
duration: 300,
|
|
55
56
|
useNativeDriver: false,
|
|
56
57
|
}).start();
|
|
@@ -77,9 +78,9 @@ const TextField: React.FC<TextFieldProps> = ({
|
|
|
77
78
|
? colors.error.main
|
|
78
79
|
: focused
|
|
79
80
|
? colors[color].main
|
|
80
|
-
: colors.
|
|
81
|
-
borderWidth: error ? 1 : variant === "outlined" ? (focused ? 2 :
|
|
82
|
-
borderBottomWidth: variant === "text" ? 0.5 :
|
|
81
|
+
: colors.textSecondary.main,
|
|
82
|
+
borderWidth: error ? 1 : variant === "outlined" ? (focused ? 2 : 0.5) : 0,
|
|
83
|
+
borderBottomWidth: variant === "text" ? 0.5 : undefined,
|
|
83
84
|
width: "100%",
|
|
84
85
|
borderRadius: variant === "text" ? 0 : rounded ? 30 : 7,
|
|
85
86
|
alignItems: "center",
|
|
@@ -89,27 +90,29 @@ const TextField: React.FC<TextFieldProps> = ({
|
|
|
89
90
|
fontSize: "14@s",
|
|
90
91
|
flex: 1,
|
|
91
92
|
alignSelf: "stretch",
|
|
92
|
-
paddingLeft: moderateScale(15),
|
|
93
|
+
paddingLeft: variant === "text" ? 0 : moderateScale(15),
|
|
93
94
|
paddingRight: moderateScale(10),
|
|
94
|
-
paddingTop:
|
|
95
|
+
paddingTop: "11@vs",
|
|
95
96
|
color: colors.black[1],
|
|
96
97
|
zIndex: 10,
|
|
97
98
|
// backgroundColor: "#284",
|
|
98
99
|
},
|
|
99
100
|
inputText: {
|
|
100
101
|
fontSize: "14@ms",
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
flex: 1,
|
|
103
|
+
paddingLeft: variant === "text" ? 0 : moderateScale(15),
|
|
104
|
+
paddingTop: "13@ms",
|
|
103
105
|
},
|
|
104
106
|
label: {
|
|
105
107
|
position: "absolute",
|
|
106
|
-
left: moderateScale(15),
|
|
108
|
+
left: variant === "text" ? 0 : moderateScale(15),
|
|
107
109
|
fontSize: focused || value ? "10@s" : "13@s",
|
|
108
|
-
color: focused ? colors[color].main : colors.
|
|
110
|
+
color: focused ? colors[color].main : colors.textSecondary.main,
|
|
109
111
|
},
|
|
110
112
|
helperText: {
|
|
111
113
|
paddingHorizontal: "15@s",
|
|
112
|
-
|
|
114
|
+
flex: 1,
|
|
115
|
+
color: focused ? colors[color].dark : colors.textSecondary.main,
|
|
113
116
|
paddingTop: "4@ms",
|
|
114
117
|
},
|
|
115
118
|
error: {
|
|
@@ -167,9 +170,24 @@ const TextField: React.FC<TextFieldProps> = ({
|
|
|
167
170
|
</Animated.Text>
|
|
168
171
|
{start}
|
|
169
172
|
{options ? (
|
|
170
|
-
<
|
|
171
|
-
{
|
|
172
|
-
|
|
173
|
+
<View
|
|
174
|
+
style={{ flex: 1, alignItems: "center", flexDirection: "row" }}
|
|
175
|
+
>
|
|
176
|
+
{options.find((cur) => cur.value === value)?.start && (
|
|
177
|
+
<View
|
|
178
|
+
style={{
|
|
179
|
+
paddingTop: variant !== "outlined" ? ms(13) : 0,
|
|
180
|
+
paddingRight: 10,
|
|
181
|
+
}}
|
|
182
|
+
>
|
|
183
|
+
{options.find((cur) => cur.value === value)?.start}
|
|
184
|
+
</View>
|
|
185
|
+
)}
|
|
186
|
+
|
|
187
|
+
<Typography style={styles.inputText}>
|
|
188
|
+
{options.find((cur) => cur.value === value)?.label}
|
|
189
|
+
</Typography>
|
|
190
|
+
</View>
|
|
173
191
|
) : (
|
|
174
192
|
<TextInput
|
|
175
193
|
onFocus={() => {
|
|
@@ -192,6 +210,15 @@ const TextField: React.FC<TextFieldProps> = ({
|
|
|
192
210
|
/>
|
|
193
211
|
)}
|
|
194
212
|
{end && <View style={{ marginRight: 20 }}>{end}</View>}
|
|
213
|
+
{options && (
|
|
214
|
+
<View style={{ marginRight: 20 }}>
|
|
215
|
+
<Ionicons
|
|
216
|
+
name="chevron-down"
|
|
217
|
+
color={colors.textSecondary.main}
|
|
218
|
+
size={24}
|
|
219
|
+
/>
|
|
220
|
+
</View>
|
|
221
|
+
)}
|
|
195
222
|
</TouchableOpacity>
|
|
196
223
|
{helperText && (
|
|
197
224
|
<Typography
|
|
@@ -250,12 +277,18 @@ export const TextField2: React.FC<TextFieldProps> = ({
|
|
|
250
277
|
...props
|
|
251
278
|
}) => {
|
|
252
279
|
const colors = useColors();
|
|
253
|
-
const [focused,
|
|
280
|
+
const [focused, _setFocused] = useState(false);
|
|
254
281
|
|
|
255
282
|
const labelAnim = useRef(new Animated.Value(0)).current;
|
|
256
283
|
|
|
257
284
|
const height = moderateScale(50);
|
|
258
285
|
|
|
286
|
+
const setFocused = (value: boolean) => {
|
|
287
|
+
startTransition(() => {
|
|
288
|
+
_setFocused(value);
|
|
289
|
+
});
|
|
290
|
+
};
|
|
291
|
+
|
|
259
292
|
React.useEffect(() => {
|
|
260
293
|
if (focused || value) {
|
|
261
294
|
Animated.timing(labelAnim, {
|
|
@@ -374,7 +407,6 @@ export const TextField2: React.FC<TextFieldProps> = ({
|
|
|
374
407
|
<Typography style={styles.inputText}>
|
|
375
408
|
{options.find((cur) => cur.value === value)?.label}
|
|
376
409
|
</Typography>
|
|
377
|
-
|
|
378
410
|
<Ionicons
|
|
379
411
|
name="chevron-down"
|
|
380
412
|
size={24}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// import * as fs from "fs";
|
|
2
|
+
import { setApiKey } from "./KeyManager";
|
|
3
|
+
|
|
4
|
+
type configProps = {
|
|
5
|
+
googleMapApiKey?: string;
|
|
6
|
+
colors?: {
|
|
7
|
+
primary?: {
|
|
8
|
+
mains: string;
|
|
9
|
+
light: string;
|
|
10
|
+
dark: string;
|
|
11
|
+
text: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function initialize(config: configProps): void {
|
|
17
|
+
try {
|
|
18
|
+
setApiKey({
|
|
19
|
+
GOOGLE_MAP_API_KEY: config.googleMapApiKey,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
console.log("Got key from frontend", config.googleMapApiKey);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error("Error reading the config file:", error);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// export function loadConfig(): void {
|
|
28
|
+
// try {
|
|
29
|
+
// const configData = fs.readFileSync("./hui-config.json", "utf-8");
|
|
30
|
+
// const config: configProps = JSON.parse(configData);
|
|
31
|
+
// setApiKey({
|
|
32
|
+
// GOOGLE_MAP_API_KEY: config.googleMapApiKey,
|
|
33
|
+
// });
|
|
34
|
+
|
|
35
|
+
// console.log("Got key from frontend", config.googleMapApiKey);
|
|
36
|
+
// } catch (error) {
|
|
37
|
+
// console.error("Error reading the config file:", error);
|
|
38
|
+
// }
|
|
39
|
+
// }
|
package/src/hooks.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useContext } from "react";
|
|
2
2
|
import { Platform } from "react-native";
|
|
3
|
-
import {
|
|
4
|
-
import colors from "./theme/colors";
|
|
3
|
+
import { vs } from "react-native-size-matters";
|
|
5
4
|
import { UIThemeContext } from "./theme";
|
|
5
|
+
import colors from "./theme/colors";
|
|
6
6
|
|
|
7
7
|
export const useColors = () => {
|
|
8
8
|
const { themeState } = useContext(UIThemeContext);
|
package/src/theme/colors.ts
CHANGED
|
@@ -26,7 +26,7 @@ const darkColors = {
|
|
|
26
26
|
5: "#aaa",
|
|
27
27
|
},
|
|
28
28
|
white: {
|
|
29
|
-
1: "#
|
|
29
|
+
1: "#000",
|
|
30
30
|
2: "#222",
|
|
31
31
|
3: "#444",
|
|
32
32
|
4: "#333",
|
|
@@ -39,17 +39,17 @@ const darkColors = {
|
|
|
39
39
|
text: "#000",
|
|
40
40
|
},
|
|
41
41
|
light: {
|
|
42
|
-
main: "#
|
|
42
|
+
main: "#111",
|
|
43
43
|
light: "#555",
|
|
44
44
|
dark: "#333",
|
|
45
45
|
text: "#fff",
|
|
46
46
|
},
|
|
47
|
-
|
|
47
|
+
grey: {
|
|
48
|
+
dark: "#d0d8d8",
|
|
49
|
+
main: "#e4e0e4",
|
|
50
|
+
},
|
|
48
51
|
textSecondary: {
|
|
49
|
-
main: "#
|
|
50
|
-
light: "#aaa",
|
|
51
|
-
dark: "#555",
|
|
52
|
-
text: "#fff",
|
|
52
|
+
main: "#666",
|
|
53
53
|
},
|
|
54
54
|
secondary: {
|
|
55
55
|
main: "#a00",
|
|
@@ -69,11 +69,11 @@ export default function colors(theme: ThemeTypes) {
|
|
|
69
69
|
const dynamicColors = theme === "dark" ? darkColors : lightColors;
|
|
70
70
|
return {
|
|
71
71
|
primary: {
|
|
72
|
-
main: "#
|
|
72
|
+
main: "#f80",
|
|
73
73
|
light: "#FEFFD3",
|
|
74
74
|
dark: "#fa0",
|
|
75
75
|
orange: "#F68B1E",
|
|
76
|
-
text: "#
|
|
76
|
+
text: "#fff",
|
|
77
77
|
},
|
|
78
78
|
secondary: {
|
|
79
79
|
main: "#f11",
|
|
@@ -98,18 +98,21 @@ export default function colors(theme: ThemeTypes) {
|
|
|
98
98
|
light: "#777",
|
|
99
99
|
dark: "#111",
|
|
100
100
|
text: "#fff",
|
|
101
|
+
mid: "#f2f3f4",
|
|
101
102
|
},
|
|
102
103
|
textSecondary: {
|
|
103
104
|
main: "#aaa",
|
|
104
|
-
|
|
105
|
-
dark: "#
|
|
106
|
-
|
|
105
|
+
mid: "#9ab",
|
|
106
|
+
dark: "#678",
|
|
107
|
+
darkBlue: "#123",
|
|
107
108
|
},
|
|
108
109
|
blue: {
|
|
109
110
|
main: "#09F",
|
|
110
111
|
light: "#39f",
|
|
111
112
|
dark: "#028",
|
|
112
113
|
text: "#fff",
|
|
114
|
+
navy: "#071440",
|
|
115
|
+
soft: "#EBF2FF",
|
|
113
116
|
},
|
|
114
117
|
info: {
|
|
115
118
|
main: "#09f",
|
|
@@ -122,6 +125,9 @@ export default function colors(theme: ThemeTypes) {
|
|
|
122
125
|
text: "#fff",
|
|
123
126
|
light: "#5c3",
|
|
124
127
|
dark: "#062",
|
|
128
|
+
|
|
129
|
+
green: "#49D3BA",
|
|
130
|
+
lighter: "#00A86B",
|
|
125
131
|
},
|
|
126
132
|
|
|
127
133
|
warning: {
|
|
@@ -135,6 +141,13 @@ export default function colors(theme: ThemeTypes) {
|
|
|
135
141
|
text: "#fff",
|
|
136
142
|
light: "#f43",
|
|
137
143
|
dark: "#a20",
|
|
144
|
+
red: "#D92D20",
|
|
145
|
+
soft: "#fee",
|
|
146
|
+
bold: "#d22",
|
|
147
|
+
},
|
|
148
|
+
grey: {
|
|
149
|
+
dark: "#101828",
|
|
150
|
+
main: "#344054",
|
|
138
151
|
},
|
|
139
152
|
...dynamicColors,
|
|
140
153
|
};
|
package/src/types.ts
CHANGED
|
@@ -200,7 +200,12 @@ export interface TextFieldProps extends TextInputProps {
|
|
|
200
200
|
inputStyles?: any;
|
|
201
201
|
gutterBottom?: number;
|
|
202
202
|
end?: ReactNode;
|
|
203
|
-
options?: {
|
|
203
|
+
options?: {
|
|
204
|
+
start?: ReactNode;
|
|
205
|
+
secondary?: string;
|
|
206
|
+
value: string | number;
|
|
207
|
+
label: string;
|
|
208
|
+
}[];
|
|
204
209
|
onFocus?: () => void;
|
|
205
210
|
onBlur?: () => void;
|
|
206
211
|
}
|
|
@@ -233,9 +238,9 @@ export interface SafeAreaViewProps {
|
|
|
233
238
|
export interface SelectMenuProps {
|
|
234
239
|
open: boolean;
|
|
235
240
|
onClose: () => void;
|
|
236
|
-
value:
|
|
237
|
-
options: { secondary?: string; value:
|
|
238
|
-
onChange: (value: string
|
|
241
|
+
value: any;
|
|
242
|
+
options: { secondary?: string; value: any; label: string }[];
|
|
243
|
+
onChange: (value: string) => void;
|
|
239
244
|
disableAutoClose?: boolean;
|
|
240
245
|
label?: string;
|
|
241
246
|
secondary?: string;
|