@hoddy-ui/core 1.0.0
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/index.ts +15 -0
- package/package.json +34 -0
- package/src/Components/AdaptiveStatusBar.tsx +38 -0
- package/src/Components/AlertX.tsx +60 -0
- package/src/Components/Avatar.tsx +57 -0
- package/src/Components/Button.tsx +174 -0
- package/src/Components/SafeAreaView.tsx +19 -0
- package/src/Components/SelectMenu.tsx +139 -0
- package/src/Components/Spinner.tsx +54 -0
- package/src/Components/TextField.tsx +442 -0
- package/src/Components/Typography.tsx +47 -0
- package/src/hooks.ts +73 -0
- package/src/theme/colors.ts +141 -0
- package/src/theme/index.tsx +83 -0
- package/src/types.ts +243 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
2
|
+
import * as NavigationBar from "expo-navigation-bar";
|
|
3
|
+
import * as SystemUI from "expo-system-ui";
|
|
4
|
+
import React, { createContext, useReducer } from "react";
|
|
5
|
+
import { Platform, useColorScheme } from "react-native";
|
|
6
|
+
import {
|
|
7
|
+
ThemeActionTypes,
|
|
8
|
+
ThemeContext,
|
|
9
|
+
ThemeProviderProps,
|
|
10
|
+
ThemeState,
|
|
11
|
+
ThemeTypes,
|
|
12
|
+
} from "../types";
|
|
13
|
+
|
|
14
|
+
export const UIThemeContext = createContext<ThemeContext>({
|
|
15
|
+
themeState: { mode: "default", value: "light" },
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
function themeReducer(
|
|
19
|
+
state: ThemeState,
|
|
20
|
+
{ type, payload }: ThemeActionTypes
|
|
21
|
+
): ThemeState {
|
|
22
|
+
console.log(type, payload);
|
|
23
|
+
// Platform
|
|
24
|
+
if (payload === "dark" || type === "dark") {
|
|
25
|
+
SystemUI.setBackgroundColorAsync("#111111");
|
|
26
|
+
if (Platform.OS === "android") {
|
|
27
|
+
NavigationBar.setButtonStyleAsync("light");
|
|
28
|
+
NavigationBar.setBackgroundColorAsync("#111111");
|
|
29
|
+
}
|
|
30
|
+
} else {
|
|
31
|
+
SystemUI.setBackgroundColorAsync("#ffffff");
|
|
32
|
+
if (Platform.OS === "android") {
|
|
33
|
+
NavigationBar.setButtonStyleAsync("dark");
|
|
34
|
+
NavigationBar.setBackgroundColorAsync("#fff");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
switch (type) {
|
|
39
|
+
case "dark":
|
|
40
|
+
return { mode: "dark", value: "dark" };
|
|
41
|
+
case "default":
|
|
42
|
+
return { mode: "default", value: payload! };
|
|
43
|
+
case "light":
|
|
44
|
+
return { mode: "light", value: "light" };
|
|
45
|
+
default:
|
|
46
|
+
return state;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const UIThemeProvider = ({ children }: ThemeProviderProps) => {
|
|
51
|
+
const [themeState, themeDispatch] = useReducer(themeReducer, {
|
|
52
|
+
mode: "default",
|
|
53
|
+
value: "light",
|
|
54
|
+
});
|
|
55
|
+
const colorScheme: ThemeTypes = useColorScheme()!;
|
|
56
|
+
|
|
57
|
+
React.useEffect(() => {
|
|
58
|
+
AsyncStorage.getItem("theme").then((val: any) => {
|
|
59
|
+
if (val) {
|
|
60
|
+
if (val === "default") {
|
|
61
|
+
themeDispatch({
|
|
62
|
+
type: "default",
|
|
63
|
+
payload: colorScheme,
|
|
64
|
+
});
|
|
65
|
+
} else
|
|
66
|
+
themeDispatch({
|
|
67
|
+
type: val,
|
|
68
|
+
});
|
|
69
|
+
} else {
|
|
70
|
+
themeDispatch({
|
|
71
|
+
type: "default",
|
|
72
|
+
payload: colorScheme,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}, [colorScheme]);
|
|
77
|
+
return (
|
|
78
|
+
<UIThemeContext.Provider value={{ themeState, themeDispatch }}>
|
|
79
|
+
{children}
|
|
80
|
+
</UIThemeContext.Provider>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import {
|
|
3
|
+
NativeScrollEvent,
|
|
4
|
+
NativeSyntheticEvent,
|
|
5
|
+
TextInputProps,
|
|
6
|
+
TextStyle,
|
|
7
|
+
ViewStyle,
|
|
8
|
+
} from "react-native";
|
|
9
|
+
|
|
10
|
+
export type ThemeTypes = "dark" | "light";
|
|
11
|
+
export type ThemeModes = "dark" | "light" | "default";
|
|
12
|
+
export type colorTypes =
|
|
13
|
+
| "primary"
|
|
14
|
+
| "secondary"
|
|
15
|
+
| "light"
|
|
16
|
+
| "dark"
|
|
17
|
+
| "info"
|
|
18
|
+
| "warning"
|
|
19
|
+
| "error"
|
|
20
|
+
| "purple"
|
|
21
|
+
| "blue"
|
|
22
|
+
| "textSecondary";
|
|
23
|
+
|
|
24
|
+
export interface ThemeActionTypes {
|
|
25
|
+
type: ThemeModes;
|
|
26
|
+
payload?: ThemeTypes;
|
|
27
|
+
}
|
|
28
|
+
export interface ThemeState {
|
|
29
|
+
value: ThemeTypes;
|
|
30
|
+
mode: ThemeModes;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ThemeContext {
|
|
34
|
+
themeState: ThemeState;
|
|
35
|
+
themeDispatch?: any;
|
|
36
|
+
}
|
|
37
|
+
export interface ThemeProviderProps {
|
|
38
|
+
children: ReactNode;
|
|
39
|
+
}
|
|
40
|
+
export interface AlertXProps {
|
|
41
|
+
type: "info" | "warning" | "success" | "error";
|
|
42
|
+
variant?: "contained" | "outlined";
|
|
43
|
+
title?: string;
|
|
44
|
+
gutterBottom?: number;
|
|
45
|
+
body: string;
|
|
46
|
+
style?: ViewStyle;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Component Types
|
|
50
|
+
|
|
51
|
+
export interface AvatarProps {
|
|
52
|
+
color?: colorTypes;
|
|
53
|
+
label?: string;
|
|
54
|
+
variant?: "outlined" | "contained";
|
|
55
|
+
source?: any;
|
|
56
|
+
size?: number;
|
|
57
|
+
style?: ViewStyle;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface ButtonProps {
|
|
61
|
+
color?: colorTypes;
|
|
62
|
+
variant?: "text" | "outlined" | "contained";
|
|
63
|
+
gutterBottom?: number;
|
|
64
|
+
elevation?: number;
|
|
65
|
+
onPress?: () => void;
|
|
66
|
+
disabled?: boolean;
|
|
67
|
+
title?: string;
|
|
68
|
+
loading?: boolean;
|
|
69
|
+
size?: "large" | "small";
|
|
70
|
+
rounded?: boolean;
|
|
71
|
+
style?: ViewStyle;
|
|
72
|
+
fullWidth?: boolean;
|
|
73
|
+
translucent?: "dark" | undefined;
|
|
74
|
+
start?: ReactNode;
|
|
75
|
+
end?: ReactNode;
|
|
76
|
+
}
|
|
77
|
+
export interface FlashMessageProps {
|
|
78
|
+
message?: string;
|
|
79
|
+
title?: string;
|
|
80
|
+
type: "success" | "warning" | "error";
|
|
81
|
+
}
|
|
82
|
+
export interface LinkButtonProps {
|
|
83
|
+
title: string;
|
|
84
|
+
style?: ViewStyle;
|
|
85
|
+
color?: colorTypes;
|
|
86
|
+
fontSize?: number;
|
|
87
|
+
fontWeight: string;
|
|
88
|
+
disabled?: boolean;
|
|
89
|
+
onPress?: () => void;
|
|
90
|
+
}
|
|
91
|
+
export interface IconButtonProps {
|
|
92
|
+
style?: TextStyle;
|
|
93
|
+
color?: colorTypes;
|
|
94
|
+
fontSize?: number;
|
|
95
|
+
disabled?: boolean;
|
|
96
|
+
onPress?: () => void;
|
|
97
|
+
icon: any;
|
|
98
|
+
elevation?: number;
|
|
99
|
+
bg?: boolean;
|
|
100
|
+
size?: number;
|
|
101
|
+
containerStyles?: ViewStyle;
|
|
102
|
+
iconType?: "material" | "ion";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export type locatorLocation = {
|
|
106
|
+
description: string;
|
|
107
|
+
longitude: number;
|
|
108
|
+
latitude: number;
|
|
109
|
+
};
|
|
110
|
+
export type LocatorInputProps = {
|
|
111
|
+
onBlur?: () => void;
|
|
112
|
+
onFocus?: () => void;
|
|
113
|
+
clear?: () => void;
|
|
114
|
+
locateMe?: () => void;
|
|
115
|
+
value?: string;
|
|
116
|
+
onChangeText: (text: string) => void;
|
|
117
|
+
};
|
|
118
|
+
export interface LocatorProps {
|
|
119
|
+
variant?: "contained" | "outlined";
|
|
120
|
+
onLocationSelected: (location: locatorLocation | null) => void;
|
|
121
|
+
label?: string;
|
|
122
|
+
error?: string;
|
|
123
|
+
float?: boolean;
|
|
124
|
+
location?: locatorLocation | null;
|
|
125
|
+
gutterBottom?: number;
|
|
126
|
+
helperText?: string;
|
|
127
|
+
renderInput?: (props: LocatorInputProps) => ReactNode;
|
|
128
|
+
country?: string;
|
|
129
|
+
}
|
|
130
|
+
export interface ListProps {
|
|
131
|
+
style?: ViewStyle;
|
|
132
|
+
children: ReactNode;
|
|
133
|
+
}
|
|
134
|
+
export interface ListItemTextProps {
|
|
135
|
+
primary: string;
|
|
136
|
+
divider?: boolean;
|
|
137
|
+
primaryProps?: TypographyProps;
|
|
138
|
+
secondaryProps?: TypographyProps;
|
|
139
|
+
secondary?: string;
|
|
140
|
+
style?: ViewStyle;
|
|
141
|
+
}
|
|
142
|
+
export interface ListItemProps {
|
|
143
|
+
link?: boolean;
|
|
144
|
+
divider?: boolean;
|
|
145
|
+
onPress?: () => void;
|
|
146
|
+
index?: number;
|
|
147
|
+
style?: ViewStyle;
|
|
148
|
+
children: ReactNode;
|
|
149
|
+
}
|
|
150
|
+
export interface FormWrapperProps {
|
|
151
|
+
children: ReactNode;
|
|
152
|
+
behavior?: "position" | "height" | "padding";
|
|
153
|
+
contentContainerStyle?: ViewStyle;
|
|
154
|
+
mode?: "scroll" | "static";
|
|
155
|
+
keyboardVerticalOffset?: number;
|
|
156
|
+
style?: ViewStyle;
|
|
157
|
+
onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
158
|
+
}
|
|
159
|
+
export interface GridItemProps {
|
|
160
|
+
children: ReactNode;
|
|
161
|
+
col?: number;
|
|
162
|
+
alignItems?: "center" | "flex-start" | "flex-end";
|
|
163
|
+
spacing?: number;
|
|
164
|
+
style?: ViewStyle;
|
|
165
|
+
}
|
|
166
|
+
export interface GridProps {
|
|
167
|
+
children: ReactNode;
|
|
168
|
+
spacing?: number;
|
|
169
|
+
style?: ViewStyle;
|
|
170
|
+
}
|
|
171
|
+
export interface PopupProps {
|
|
172
|
+
title?: string;
|
|
173
|
+
sheet?: number | boolean;
|
|
174
|
+
bare?: boolean;
|
|
175
|
+
children: ReactNode;
|
|
176
|
+
open: boolean;
|
|
177
|
+
onClose?: () => void;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export interface SpinnerProps {
|
|
181
|
+
label?: string;
|
|
182
|
+
size?: "large" | "small";
|
|
183
|
+
color?: colorTypes;
|
|
184
|
+
fullscreen?: boolean;
|
|
185
|
+
style?: ViewStyle;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export interface TextFieldProps extends TextInputProps {
|
|
189
|
+
label?: string;
|
|
190
|
+
variant?: "outlined" | "text" | "contained";
|
|
191
|
+
color?: colorTypes;
|
|
192
|
+
type?: "email" | "tel" | "password" | "text" | "number" | "search";
|
|
193
|
+
helperText?: string;
|
|
194
|
+
value: any;
|
|
195
|
+
start?: ReactNode;
|
|
196
|
+
rounded?: boolean;
|
|
197
|
+
error?: string | string[];
|
|
198
|
+
disabled?: boolean;
|
|
199
|
+
style?: ViewStyle;
|
|
200
|
+
inputStyles?: any;
|
|
201
|
+
gutterBottom?: number;
|
|
202
|
+
end?: ReactNode;
|
|
203
|
+
options?: { secondary?: string; value: string | number; label: string }[];
|
|
204
|
+
onFocus?: () => void;
|
|
205
|
+
onBlur?: () => void;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export interface TypographyProps {
|
|
209
|
+
children: ReactNode;
|
|
210
|
+
color?: colorTypes;
|
|
211
|
+
style?: TextStyle | ViewStyle;
|
|
212
|
+
textCase?: "capitalize" | "uppercase" | "lowercase" | null;
|
|
213
|
+
variant?:
|
|
214
|
+
| "caption"
|
|
215
|
+
| "body1"
|
|
216
|
+
| "body2"
|
|
217
|
+
| "h6"
|
|
218
|
+
| "h5"
|
|
219
|
+
| "h4"
|
|
220
|
+
| "h3"
|
|
221
|
+
| "h2"
|
|
222
|
+
| "h1";
|
|
223
|
+
align?: "center" | "left" | "right";
|
|
224
|
+
gutterBottom?: number;
|
|
225
|
+
fontWeight?: 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export interface SafeAreaViewProps {
|
|
229
|
+
children: ReactNode;
|
|
230
|
+
style?: ViewStyle;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export interface SelectMenuProps {
|
|
234
|
+
open: boolean;
|
|
235
|
+
onClose: () => void;
|
|
236
|
+
value: string | number;
|
|
237
|
+
options: { secondary?: string; value: string | number; label: string }[];
|
|
238
|
+
onChange: (value: string | number) => void;
|
|
239
|
+
disableAutoClose?: boolean;
|
|
240
|
+
label?: string;
|
|
241
|
+
secondary?: string;
|
|
242
|
+
helperText?: string;
|
|
243
|
+
}
|