@hoddy-ui/core 1.0.100 → 1.1.1
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/README.md +773 -190
- package/next/components/AdaptiveStatusBarNext.tsx +12 -18
- package/next/dist/index.d.mts +90 -8
- package/next/dist/index.d.ts +90 -8
- package/next/dist/index.js +347 -316
- package/next/dist/index.js.map +1 -1
- package/next/dist/index.mjs +366 -337
- package/next/dist/index.mjs.map +1 -1
- package/next/index.ts +1 -0
- package/next/package.json +1 -1
- package/package.json +1 -1
- package/src/Components/AdaptiveStatusBar.tsx +13 -19
- package/src/Components/Locator.tsx +50 -22
- package/src/Components/Popup.tsx +16 -13
- package/src/Components/TextField.tsx +230 -220
- package/src/Components/Typography.tsx +1 -3
- package/src/config/KeyManager.ts +2 -0
- package/src/config/index.ts +2 -0
- package/src/theme/index.tsx +3 -1
- package/src/types.ts +2 -1
package/README.md
CHANGED
|
@@ -1,331 +1,914 @@
|
|
|
1
1
|
# @hoddy-ui/core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**The complete UI component library for React Native and Expo applications**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A comprehensive, production-ready UI component library that follows Material Design principles with a modern twist. Built with TypeScript and optimized for React Native and Expo applications.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## ✨ Features
|
|
8
8
|
|
|
9
|
-
**
|
|
9
|
+
- 🎨 **20+ Production-Ready Components** - From basic buttons to complex forms
|
|
10
|
+
- 🌗 **Dark Mode Support** - Automatic theme switching with system preference detection
|
|
11
|
+
- 🔧 **TypeScript First** - Full type safety and IntelliSense support
|
|
12
|
+
- ⚡ **Performance Optimized** - Minimal bundle size with tree shaking
|
|
13
|
+
- 🎯 **Accessibility Ready** - WCAG compliant components
|
|
14
|
+
- 🔌 **Highly Customizable** - Extensive theming and configuration options
|
|
15
|
+
- 📱 **Cross Platform** - Works seamlessly on iOS and Android
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
## 📦 Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
12
20
|
npm install @hoddy-ui/core
|
|
21
|
+
# or
|
|
22
|
+
yarn add @hoddy-ui/core
|
|
13
23
|
```
|
|
14
24
|
|
|
15
|
-
|
|
25
|
+
### Peer Dependencies
|
|
16
26
|
|
|
17
|
-
|
|
18
|
-
|
|
27
|
+
Install the required peer dependencies:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install @expo/vector-icons @react-native-async-storage/async-storage @react-navigation/native expo-navigation-bar expo-system-ui react-native-safe-area-context react-native-size-matters
|
|
19
31
|
```
|
|
20
32
|
|
|
21
|
-
|
|
33
|
+
Or with yarn:
|
|
22
34
|
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
"@react-native-async-storage/async-storage": "^1.18.1",
|
|
26
|
-
"@react-navigation/native": "^6.1.6",
|
|
27
|
-
"expo-navigation-bar": "^2.1.1",
|
|
28
|
-
"expo-system-ui": "^2.2.1",
|
|
29
|
-
"react": "^18.2.0",
|
|
30
|
-
"react-native": "^0.71.8",
|
|
31
|
-
"react-native-safe-area-context": "^4.5.3",
|
|
32
|
-
"react-native-size-matters": "^0.4.0"
|
|
35
|
+
```bash
|
|
36
|
+
yarn add @expo/vector-icons @react-native-async-storage/async-storage @react-navigation/native expo-navigation-bar expo-system-ui react-native-safe-area-context react-native-size-matters
|
|
33
37
|
```
|
|
34
38
|
|
|
35
|
-
##
|
|
39
|
+
## 🚀 Quick Start
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
### Basic Setup
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
import { UIThemeProvider } from "hoddy-ui/core";
|
|
43
|
+
1. **Initialize the library** (optional but recommended):
|
|
41
44
|
|
|
42
|
-
|
|
45
|
+
```tsx
|
|
46
|
+
import { initialize } from "@hoddy-ui/core";
|
|
47
|
+
|
|
48
|
+
initialize({
|
|
49
|
+
// Custom font family
|
|
50
|
+
fontFamily: "Inter-Regular",
|
|
51
|
+
|
|
52
|
+
// Google Maps API key for Locator component
|
|
53
|
+
googleMapApiKey: "your-google-maps-api-key",
|
|
54
|
+
|
|
55
|
+
// Edge-to-edge display (affects Android navigation bar styling)
|
|
56
|
+
edgeToEdge: false,
|
|
57
|
+
|
|
58
|
+
// Custom colors
|
|
59
|
+
colors: {
|
|
60
|
+
primary: {
|
|
61
|
+
main: "#6366f1",
|
|
62
|
+
light: "#818cf8",
|
|
63
|
+
dark: "#4f46e5",
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
2. **Wrap your app with the theme provider**:
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import React from "react";
|
|
73
|
+
import { UIThemeProvider } from "@hoddy-ui/core";
|
|
74
|
+
import App from "./App";
|
|
75
|
+
|
|
76
|
+
export default function Root() {
|
|
43
77
|
return (
|
|
44
78
|
<UIThemeProvider>
|
|
45
|
-
<
|
|
79
|
+
<App />
|
|
46
80
|
</UIThemeProvider>
|
|
47
81
|
);
|
|
48
82
|
}
|
|
49
83
|
```
|
|
50
84
|
|
|
51
|
-
|
|
85
|
+
3. **Start using components**:
|
|
52
86
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
```javascript
|
|
87
|
+
```tsx
|
|
56
88
|
import React from "react";
|
|
57
89
|
import { View } from "react-native";
|
|
58
|
-
import { Button,
|
|
90
|
+
import { Typography, Button, TextField, useColors } from "@hoddy-ui/core";
|
|
91
|
+
|
|
92
|
+
export default function HomeScreen() {
|
|
93
|
+
const colors = useColors();
|
|
59
94
|
|
|
60
|
-
const HomeScreen = () => {
|
|
61
95
|
return (
|
|
62
|
-
<View>
|
|
63
|
-
<Typography
|
|
64
|
-
|
|
96
|
+
<View style={{ padding: 20, backgroundColor: colors.white[1] }}>
|
|
97
|
+
<Typography variant="h4" color="primary" gutterBottom={20}>
|
|
98
|
+
Welcome to Hoddy UI!
|
|
99
|
+
</Typography>
|
|
100
|
+
|
|
101
|
+
<TextField
|
|
102
|
+
label="Email Address"
|
|
103
|
+
variant="outlined"
|
|
104
|
+
keyboardType="email-address"
|
|
105
|
+
gutterBottom={16}
|
|
106
|
+
/>
|
|
107
|
+
|
|
108
|
+
<Button
|
|
109
|
+
title="Get Started"
|
|
110
|
+
variant="contained"
|
|
111
|
+
color="primary"
|
|
112
|
+
onPress={() => console.log("Button pressed!")}
|
|
113
|
+
/>
|
|
65
114
|
</View>
|
|
66
115
|
);
|
|
67
|
-
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## ⚙️ Configuration
|
|
120
|
+
|
|
121
|
+
### Global Configuration
|
|
68
122
|
|
|
69
|
-
|
|
123
|
+
Use the `initialize` function to configure the library globally:
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
import { initialize } from "@hoddy-ui/core";
|
|
127
|
+
|
|
128
|
+
initialize({
|
|
129
|
+
// Font family for all typography components
|
|
130
|
+
fontFamily?: string;
|
|
131
|
+
|
|
132
|
+
// Google Maps API key for Locator component
|
|
133
|
+
googleMapApiKey?: string;
|
|
134
|
+
|
|
135
|
+
// Edge-to-edge display (skips Android navigation bar styling)
|
|
136
|
+
edgeToEdge?: boolean;
|
|
137
|
+
|
|
138
|
+
// Custom color overrides
|
|
139
|
+
colors?: {
|
|
140
|
+
primary?: { main: string; light?: string; dark?: string };
|
|
141
|
+
secondary?: { main: string; light?: string; dark?: string };
|
|
142
|
+
// ... and more
|
|
143
|
+
};
|
|
144
|
+
});
|
|
70
145
|
```
|
|
71
146
|
|
|
72
|
-
|
|
147
|
+
### Theme Configuration
|
|
73
148
|
|
|
74
|
-
|
|
149
|
+
The theme system automatically detects system preferences and can be controlled programmatically:
|
|
75
150
|
|
|
76
|
-
|
|
77
|
-
-
|
|
78
|
-
- [AlertX](#alertx)
|
|
79
|
-
- [Button](#button)
|
|
80
|
-
- [FlashMessage](#flashmessage)
|
|
81
|
-
- [FormWrapper](#formwrapper)
|
|
82
|
-
- [Grid](#grid)
|
|
83
|
-
- [GridItem](#griditem)
|
|
84
|
-
- [IconButton](#iconbutton)
|
|
85
|
-
- [LinkButton](#linkbutton)
|
|
86
|
-
- [List](#list)
|
|
87
|
-
- [ListItem](#listitem)
|
|
88
|
-
- [ListItemText](#listitemtext)
|
|
89
|
-
- [Locator](#locator)
|
|
90
|
-
- [Popup](#popup)
|
|
91
|
-
- [SafeAreaView](#safeareaview)
|
|
92
|
-
- [Spinner](#spinner)
|
|
93
|
-
- [TextField](#textfield)
|
|
94
|
-
- [TextField2](#textfield2)
|
|
95
|
-
- [Typography](#typography)
|
|
151
|
+
```tsx
|
|
152
|
+
import { useTheme } from "@hoddy-ui/core";
|
|
96
153
|
|
|
97
|
-
|
|
154
|
+
function ThemeToggle() {
|
|
155
|
+
const { themeState, themeDispatch } = useTheme();
|
|
98
156
|
|
|
99
|
-
|
|
157
|
+
const toggleTheme = () => {
|
|
158
|
+
themeDispatch({
|
|
159
|
+
type: themeState.mode === "dark" ? "light" : "dark",
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<Button
|
|
165
|
+
title={`Switch to ${themeState.mode === "dark" ? "Light" : "Dark"} Mode`}
|
|
166
|
+
onPress={toggleTheme}
|
|
167
|
+
/>
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
```
|
|
100
171
|
|
|
101
|
-
|
|
172
|
+
## 🎨 Theming System
|
|
102
173
|
|
|
103
|
-
|
|
174
|
+
### Using Hooks
|
|
104
175
|
|
|
105
|
-
|
|
106
|
-
| --------------- | ------ | --------------- | ----------------------------------------------------------------------------------------- |
|
|
107
|
-
| barStyle | string | "light-content" | The style of the status bar. Possible values: "default", "light-content", "dark-content". |
|
|
108
|
-
| backgroundColor | string | Theme-dependent | The background color of the status bar. |
|
|
176
|
+
Access theme colors and state throughout your app:
|
|
109
177
|
|
|
110
|
-
|
|
178
|
+
```tsx
|
|
179
|
+
import { useColors, useTheme } from "@hoddy-ui/core";
|
|
111
180
|
|
|
112
|
-
|
|
113
|
-
|
|
181
|
+
function MyComponent() {
|
|
182
|
+
const colors = useColors();
|
|
183
|
+
const theme = useTheme();
|
|
114
184
|
|
|
115
|
-
const App = () => {
|
|
116
185
|
return (
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
186
|
+
<View
|
|
187
|
+
style={{
|
|
188
|
+
backgroundColor: colors.white[1],
|
|
189
|
+
borderColor: colors.primary.main,
|
|
190
|
+
}}
|
|
191
|
+
>
|
|
192
|
+
<Typography color={theme === "dark" ? "white" : "dark"}>
|
|
193
|
+
Current theme: {theme}
|
|
194
|
+
</Typography>
|
|
195
|
+
</View>
|
|
121
196
|
);
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Color Palette
|
|
201
|
+
|
|
202
|
+
The library includes a comprehensive color system:
|
|
203
|
+
|
|
204
|
+
```tsx
|
|
205
|
+
const colors = {
|
|
206
|
+
// Primary colors
|
|
207
|
+
primary: { main: "#007AFF", light: "#5AC8FA", dark: "#0051D5" },
|
|
208
|
+
secondary: { main: "#FF3B30", light: "#FF6B6B", dark: "#D70015" },
|
|
209
|
+
|
|
210
|
+
// Neutral colors
|
|
211
|
+
white: ["#FFFFFF", "#F8F9FA", "#E9ECEF"],
|
|
212
|
+
black: ["#000000", "#212529", "#495057"],
|
|
213
|
+
|
|
214
|
+
// Semantic colors
|
|
215
|
+
success: { main: "#28A745", light: "#34CE57", dark: "#1E7E34" },
|
|
216
|
+
error: { main: "#DC3545", light: "#E74C3C", dark: "#C82333" },
|
|
217
|
+
warning: { main: "#FFC107", light: "#FFD54F", dark: "#FF8F00" },
|
|
218
|
+
|
|
219
|
+
// Utility colors
|
|
220
|
+
textPrimary: { main: "#212529" },
|
|
221
|
+
textSecondary: { main: "#6C757D" },
|
|
222
|
+
divider: { main: "#DEE2E6" },
|
|
122
223
|
};
|
|
123
224
|
```
|
|
124
225
|
|
|
125
|
-
|
|
226
|
+
## 🧩 Components
|
|
126
227
|
|
|
127
|
-
|
|
228
|
+
### Layout & Structure
|
|
128
229
|
|
|
129
|
-
|
|
230
|
+
- **`SafeAreaView`** - Safe area wrapper for different devices
|
|
231
|
+
- **`Grid`** & **`GridItem`** - Flexible grid layout system
|
|
232
|
+
- **`FormWrapper`** - Form container with validation support
|
|
130
233
|
|
|
131
|
-
|
|
132
|
-
| ------- | ------- | ------- | ------------------------------------- |
|
|
133
|
-
| image | number | - | The source of the avatar image. |
|
|
134
|
-
| size | number | 40 | The size of the avatar in pixels. |
|
|
135
|
-
| rounded | boolean | false | Whether the avatar should be rounded. |
|
|
234
|
+
### Navigation & Status
|
|
136
235
|
|
|
137
|
-
|
|
236
|
+
- **`AdaptiveStatusBar`** - Theme-aware status bar
|
|
237
|
+
- Navigation utilities via hooks
|
|
138
238
|
|
|
139
|
-
|
|
239
|
+
### Typography
|
|
140
240
|
|
|
141
|
-
|
|
241
|
+
- **`Typography`** - Comprehensive text component with variants (h1-h6, body1-body2, caption)
|
|
142
242
|
|
|
143
|
-
|
|
144
|
-
| ------- | ------ | --------- | --------------------------------------------------------------------------------- |
|
|
145
|
-
| title | string | - | The title of the alert. |
|
|
146
|
-
| message | string | - | The message/content of the alert. |
|
|
147
|
-
| type | string | "default" | The type of the alert. Possible values: "default", "success", "error", "warning". |
|
|
243
|
+
### Form Components
|
|
148
244
|
|
|
149
|
-
|
|
245
|
+
- **`TextField`** - Material Design text input with variants
|
|
246
|
+
- **`TextField2`** - Alternative text field design
|
|
247
|
+
- **`Locator`** - Location picker with Google Maps integration
|
|
150
248
|
|
|
151
|
-
|
|
249
|
+
### Interactive Elements
|
|
152
250
|
|
|
153
|
-
|
|
251
|
+
- **`Button`** - Primary action buttons with variants
|
|
252
|
+
- **`IconButton`** - Icon-only buttons
|
|
253
|
+
- **`LinkButton`** - Text-based link buttons
|
|
154
254
|
|
|
155
|
-
|
|
156
|
-
| ------- | -------- | ------- | ------------------------------------------ |
|
|
157
|
-
| title | string | - | The text to display on the button. |
|
|
158
|
-
| onPress | function | - | The function to be called on button press. |
|
|
255
|
+
### Feedback & Communication
|
|
159
256
|
|
|
160
|
-
|
|
257
|
+
- **`FlashMessage`** - Toast notifications and alerts
|
|
258
|
+
- **`AlertX`** - Customizable alert dialogs
|
|
259
|
+
- **`Spinner`** - Loading indicators
|
|
161
260
|
|
|
162
|
-
|
|
261
|
+
### Data Display
|
|
163
262
|
|
|
164
|
-
|
|
263
|
+
- **`Avatar`** - User profile images and placeholders
|
|
264
|
+
- **`List`**, **`ListItem`**, **`ListItemText`** - List components
|
|
165
265
|
|
|
166
|
-
|
|
167
|
-
| -------- | ------- | --------- | ----------------------------------------------------------------------------------------- |
|
|
168
|
-
| message | string | - | The message/content of the flash message. |
|
|
169
|
-
| type | string | "default" | The type of the flash message. Possible values: "default", "success", "error", "warning". |
|
|
170
|
-
| duration | number | 3000 | The duration in milliseconds that the flash message should be displayed. |
|
|
171
|
-
| autoHide | boolean | true | Whether the flash message should auto-hide after the specified duration. |
|
|
266
|
+
### Overlays & Modals
|
|
172
267
|
|
|
173
|
-
|
|
268
|
+
- **`Popup`** - Modal dialogs and bottom sheets
|
|
174
269
|
|
|
175
|
-
|
|
270
|
+
### Animation
|
|
176
271
|
|
|
177
|
-
|
|
272
|
+
- **`Animator`** - Layout animations and transitions
|
|
178
273
|
|
|
179
|
-
|
|
180
|
-
| -------- | ---- | ------- | ----------------------------------------- |
|
|
181
|
-
| children | node | - | The form fields/components to be wrapped. |
|
|
274
|
+
## 📖 Component API Reference
|
|
182
275
|
|
|
183
|
-
###
|
|
276
|
+
### Typography
|
|
184
277
|
|
|
185
|
-
A
|
|
278
|
+
A versatile text component supporting multiple variants and styling options.
|
|
186
279
|
|
|
187
280
|
**Props:**
|
|
188
281
|
|
|
189
|
-
| Prop
|
|
190
|
-
|
|
|
191
|
-
|
|
|
192
|
-
|
|
|
193
|
-
|
|
|
282
|
+
| Prop | Type | Default | Description |
|
|
283
|
+
| -------------- | --------------------------------------------------------------------------------- | --------- | ----------------------------- |
|
|
284
|
+
| `variant` | `"h1" \| "h2" \| "h3" \| "h4" \| "h5" \| "h6" \| "body1" \| "body2" \| "caption"` | `"body1"` | Text style variant |
|
|
285
|
+
| `color` | `string` | `"dark"` | Text color from theme palette |
|
|
286
|
+
| `align` | `"left" \| "center" \| "right"` | `"left"` | Text alignment |
|
|
287
|
+
| `gutterBottom` | `number` | `0` | Bottom margin in pixels |
|
|
288
|
+
| `fontWeight` | `number` | `400` | Font weight |
|
|
289
|
+
| `textCase` | `"uppercase" \| "lowercase" \| "capitalize"` | `null` | Text transformation |
|
|
290
|
+
|
|
291
|
+
**Example:**
|
|
292
|
+
|
|
293
|
+
```tsx
|
|
294
|
+
<Typography variant="h4" color="primary" gutterBottom={20}>
|
|
295
|
+
Welcome to Hoddy UI
|
|
296
|
+
</Typography>
|
|
297
|
+
```
|
|
194
298
|
|
|
195
|
-
###
|
|
299
|
+
### Button
|
|
196
300
|
|
|
197
|
-
A
|
|
301
|
+
A comprehensive button component with multiple variants and states.
|
|
198
302
|
|
|
199
303
|
**Props:**
|
|
200
304
|
|
|
201
|
-
| Prop
|
|
202
|
-
|
|
|
203
|
-
|
|
|
305
|
+
| Prop | Type | Default | Description |
|
|
306
|
+
| ---------- | ------------------------------------- | ------------- | -------------------------- |
|
|
307
|
+
| `title` | `string` | - | Button text |
|
|
308
|
+
| `variant` | `"contained" \| "outlined" \| "text"` | `"contained"` | Button variant |
|
|
309
|
+
| `color` | `string` | `"primary"` | Button color from theme |
|
|
310
|
+
| `size` | `"small" \| "medium" \| "large"` | `"medium"` | Button size |
|
|
311
|
+
| `disabled` | `boolean` | `false` | Disabled state |
|
|
312
|
+
| `loading` | `boolean` | `false` | Loading state with spinner |
|
|
313
|
+
| `onPress` | `() => void` | - | Press handler |
|
|
314
|
+
| `start` | `ReactNode` | - | Leading icon/element |
|
|
315
|
+
| `end` | `ReactNode` | - | Trailing icon/element |
|
|
316
|
+
|
|
317
|
+
**Example:**
|
|
318
|
+
|
|
319
|
+
```tsx
|
|
320
|
+
<Button
|
|
321
|
+
title="Submit"
|
|
322
|
+
variant="contained"
|
|
323
|
+
color="primary"
|
|
324
|
+
loading={isLoading}
|
|
325
|
+
onPress={handleSubmit}
|
|
326
|
+
/>
|
|
327
|
+
```
|
|
204
328
|
|
|
205
329
|
### IconButton
|
|
206
330
|
|
|
207
|
-
A button component
|
|
331
|
+
A button component that displays only an icon.
|
|
208
332
|
|
|
209
333
|
**Props:**
|
|
210
334
|
|
|
211
|
-
| Prop
|
|
212
|
-
|
|
|
213
|
-
| icon
|
|
214
|
-
|
|
|
335
|
+
| Prop | Type | Default | Description |
|
|
336
|
+
| ----------------- | --------------------- | ------------ | ------------------------- |
|
|
337
|
+
| `icon` | `string` | - | Icon name |
|
|
338
|
+
| `iconType` | `"material" \| "ion"` | `"material"` | Icon library to use |
|
|
339
|
+
| `size` | `number` | `24` | Icon size in pixels |
|
|
340
|
+
| `color` | `string` | `"dark"` | Icon color from theme |
|
|
341
|
+
| `bg` | `boolean` | `false` | Show background circle |
|
|
342
|
+
| `elevation` | `number` | `0` | Shadow elevation |
|
|
343
|
+
| `disabled` | `boolean` | `false` | Disabled state |
|
|
344
|
+
| `onPress` | `() => void` | - | Press handler |
|
|
345
|
+
| `style` | `ViewStyle` | `{}` | Icon style overrides |
|
|
346
|
+
| `containerStyles` | `ViewStyle` | `{}` | Container style overrides |
|
|
347
|
+
|
|
348
|
+
**Example:**
|
|
349
|
+
|
|
350
|
+
```tsx
|
|
351
|
+
<IconButton
|
|
352
|
+
icon="star"
|
|
353
|
+
iconType="ion"
|
|
354
|
+
size={28}
|
|
355
|
+
color="primary"
|
|
356
|
+
bg={true}
|
|
357
|
+
elevation={2}
|
|
358
|
+
onPress={() => console.log("Starred!")}
|
|
359
|
+
/>
|
|
360
|
+
```
|
|
215
361
|
|
|
216
362
|
### LinkButton
|
|
217
363
|
|
|
218
|
-
A button component
|
|
364
|
+
A text-based button component for navigation or secondary actions.
|
|
219
365
|
|
|
220
366
|
**Props:**
|
|
221
367
|
|
|
222
|
-
| Prop
|
|
223
|
-
|
|
|
224
|
-
| title
|
|
225
|
-
|
|
|
368
|
+
| Prop | Type | Default | Description |
|
|
369
|
+
| ------------ | ------------ | -------- | --------------------- |
|
|
370
|
+
| `title` | `string` | - | Button text |
|
|
371
|
+
| `color` | `string` | `"blue"` | Text color from theme |
|
|
372
|
+
| `fontSize` | `number` | `12` | Font size |
|
|
373
|
+
| `fontWeight` | `string` | `"400"` | Font weight |
|
|
374
|
+
| `disabled` | `boolean` | `false` | Disabled state |
|
|
375
|
+
| `onPress` | `() => void` | - | Press handler |
|
|
376
|
+
| `style` | `TextStyle` | `{}` | Text style overrides |
|
|
377
|
+
|
|
378
|
+
**Example:**
|
|
379
|
+
|
|
380
|
+
```tsx
|
|
381
|
+
<LinkButton
|
|
382
|
+
title="Forgot Password?"
|
|
383
|
+
color="primary"
|
|
384
|
+
fontSize={14}
|
|
385
|
+
onPress={() => navigation.navigate("ForgotPassword")}
|
|
386
|
+
/>
|
|
387
|
+
```
|
|
226
388
|
|
|
227
|
-
###
|
|
389
|
+
### TextField
|
|
228
390
|
|
|
229
|
-
A component
|
|
391
|
+
A Material Design text input component with comprehensive features.
|
|
230
392
|
|
|
231
393
|
**Props:**
|
|
232
394
|
|
|
233
|
-
| Prop
|
|
234
|
-
|
|
|
235
|
-
|
|
|
395
|
+
| Prop | Type | Default | Description |
|
|
396
|
+
| -------------- | -------------------------------------- | ------------ | --------------------- |
|
|
397
|
+
| `label` | `string` | - | Input label |
|
|
398
|
+
| `variant` | `"outlined" \| "filled" \| "standard"` | `"outlined"` | Input variant |
|
|
399
|
+
| `value` | `string` | - | Input value |
|
|
400
|
+
| `onChangeText` | `(text: string) => void` | - | Change handler |
|
|
401
|
+
| `placeholder` | `string` | - | Placeholder text |
|
|
402
|
+
| `error` | `boolean` | `false` | Error state |
|
|
403
|
+
| `helperText` | `string` | - | Helper/error text |
|
|
404
|
+
| `disabled` | `boolean` | `false` | Disabled state |
|
|
405
|
+
| `multiline` | `boolean` | `false` | Multiline input |
|
|
406
|
+
| `start` | `ReactNode` | - | Leading icon/element |
|
|
407
|
+
| `end` | `ReactNode` | - | Trailing icon/element |
|
|
408
|
+
|
|
409
|
+
**Example:**
|
|
410
|
+
|
|
411
|
+
```tsx
|
|
412
|
+
<TextField
|
|
413
|
+
label="Email Address"
|
|
414
|
+
variant="outlined"
|
|
415
|
+
value={email}
|
|
416
|
+
onChangeText={setEmail}
|
|
417
|
+
keyboardType="email-address"
|
|
418
|
+
error={!!emailError}
|
|
419
|
+
helperText={emailError}
|
|
420
|
+
/>
|
|
421
|
+
```
|
|
236
422
|
|
|
237
|
-
###
|
|
423
|
+
### Locator
|
|
238
424
|
|
|
239
|
-
A
|
|
425
|
+
A location picker component with Google Maps integration.
|
|
240
426
|
|
|
241
427
|
**Props:**
|
|
242
428
|
|
|
243
|
-
| Prop
|
|
244
|
-
|
|
|
245
|
-
|
|
|
429
|
+
| Prop | Type | Default | Description |
|
|
430
|
+
| -------------------- | ---------------------------------- | ------------- | -------------------------- |
|
|
431
|
+
| `onLocationSelected` | `(location: LocationType) => void` | - | Location selection handler |
|
|
432
|
+
| `label` | `string` | - | Input label |
|
|
433
|
+
| `variant` | `"contained" \| "outlined"` | `"contained"` | Input variant |
|
|
434
|
+
| `location` | `LocationType` | - | Current location |
|
|
435
|
+
| `country` | `string` | `"ng"` | Country code for search |
|
|
436
|
+
| `error` | `boolean` | `false` | Error state |
|
|
437
|
+
|
|
438
|
+
**Example:**
|
|
439
|
+
|
|
440
|
+
```tsx
|
|
441
|
+
<Locator
|
|
442
|
+
label="Select Location"
|
|
443
|
+
onLocationSelected={(location) => setSelectedLocation(location)}
|
|
444
|
+
country="us"
|
|
445
|
+
/>
|
|
446
|
+
```
|
|
246
447
|
|
|
247
|
-
###
|
|
448
|
+
### SafeAreaView
|
|
248
449
|
|
|
249
|
-
A
|
|
450
|
+
A safe area wrapper component that handles device-specific safe areas.
|
|
250
451
|
|
|
251
452
|
**Props:**
|
|
252
453
|
|
|
253
|
-
| Prop
|
|
254
|
-
|
|
|
255
|
-
| children |
|
|
454
|
+
| Prop | Type | Default | Description |
|
|
455
|
+
| ---------- | ----------- | ------- | ------------------------- |
|
|
456
|
+
| `children` | `ReactNode` | - | Child components |
|
|
457
|
+
| `style` | `ViewStyle` | `{}` | Container style overrides |
|
|
256
458
|
|
|
257
|
-
|
|
459
|
+
**Example:**
|
|
460
|
+
|
|
461
|
+
```tsx
|
|
462
|
+
<SafeAreaView style={{ backgroundColor: "white" }}>
|
|
463
|
+
<YourContent />
|
|
464
|
+
</SafeAreaView>
|
|
465
|
+
```
|
|
258
466
|
|
|
259
|
-
|
|
467
|
+
### AdaptiveStatusBar
|
|
468
|
+
|
|
469
|
+
A status bar component that automatically adapts to the current theme.
|
|
260
470
|
|
|
261
471
|
**Props:**
|
|
262
472
|
|
|
263
|
-
| Prop
|
|
264
|
-
|
|
|
265
|
-
|
|
|
266
|
-
| longitude | number | - | The longitude of the location. |
|
|
473
|
+
| Prop | Type | Default | Description |
|
|
474
|
+
| ------------- | --------- | ------- | ------------------------------------- |
|
|
475
|
+
| `translucent` | `boolean` | `false` | Whether the status bar is translucent |
|
|
267
476
|
|
|
268
|
-
|
|
477
|
+
**Example:**
|
|
478
|
+
|
|
479
|
+
```tsx
|
|
480
|
+
<AdaptiveStatusBar translucent={true} />
|
|
481
|
+
```
|
|
269
482
|
|
|
270
|
-
|
|
483
|
+
### AlertX
|
|
484
|
+
|
|
485
|
+
A customizable alert component for displaying important messages.
|
|
271
486
|
|
|
272
487
|
**Props:**
|
|
273
488
|
|
|
274
|
-
| Prop
|
|
275
|
-
|
|
|
276
|
-
|
|
|
277
|
-
|
|
|
489
|
+
| Prop | Type | Default | Description |
|
|
490
|
+
| -------------- | --------------------------------------------- | ------------- | ------------------------- |
|
|
491
|
+
| `type` | `"info" \| "warning" \| "success" \| "error"` | `"info"` | Alert type |
|
|
492
|
+
| `variant` | `"contained" \| "outlined"` | `"contained"` | Alert variant |
|
|
493
|
+
| `title` | `string` | - | Alert title |
|
|
494
|
+
| `body` | `string` | - | Alert message |
|
|
495
|
+
| `gutterBottom` | `number` | `0` | Bottom margin in pixels |
|
|
496
|
+
| `style` | `ViewStyle` | `{}` | Container style overrides |
|
|
497
|
+
|
|
498
|
+
**Example:**
|
|
499
|
+
|
|
500
|
+
```tsx
|
|
501
|
+
<AlertX
|
|
502
|
+
type="success"
|
|
503
|
+
title="Success!"
|
|
504
|
+
body="Your profile has been updated successfully."
|
|
505
|
+
gutterBottom={20}
|
|
506
|
+
/>
|
|
507
|
+
```
|
|
278
508
|
|
|
279
|
-
###
|
|
509
|
+
### Avatar
|
|
280
510
|
|
|
281
|
-
A component
|
|
511
|
+
A component for displaying user avatars with support for images, labels, or default icons.
|
|
282
512
|
|
|
283
513
|
**Props:**
|
|
284
514
|
|
|
285
|
-
| Prop
|
|
286
|
-
|
|
|
287
|
-
|
|
|
515
|
+
| Prop | Type | Default | Description |
|
|
516
|
+
| --------- | --------------------------- | ------------- | --------------------------- |
|
|
517
|
+
| `source` | `ImageSourcePropType` | - | Image source |
|
|
518
|
+
| `label` | `string` | - | Text label (first letter) |
|
|
519
|
+
| `size` | `number` | `48` | Avatar size in pixels |
|
|
520
|
+
| `color` | `string` | `"dark"` | Background color from theme |
|
|
521
|
+
| `variant` | `"contained" \| "outlined"` | `"contained"` | Avatar variant |
|
|
522
|
+
| `style` | `ViewStyle` | `{}` | Container style overrides |
|
|
523
|
+
|
|
524
|
+
**Example:**
|
|
525
|
+
|
|
526
|
+
```tsx
|
|
527
|
+
<Avatar
|
|
528
|
+
source={{ uri: 'https://example.com/avatar.jpg' }}
|
|
529
|
+
size={64}
|
|
530
|
+
/>
|
|
531
|
+
|
|
532
|
+
<Avatar
|
|
533
|
+
label="John Doe"
|
|
534
|
+
color="primary"
|
|
535
|
+
size={48}
|
|
536
|
+
/>
|
|
537
|
+
```
|
|
288
538
|
|
|
289
|
-
###
|
|
539
|
+
### Grid & GridItem
|
|
540
|
+
|
|
541
|
+
Flexible grid layout components for organizing content.
|
|
542
|
+
|
|
543
|
+
**Grid Props:**
|
|
544
|
+
|
|
545
|
+
| Prop | Type | Default | Description |
|
|
546
|
+
| ---------- | ----------- | ------- | ------------------------- |
|
|
547
|
+
| `children` | `ReactNode` | - | GridItem components |
|
|
548
|
+
| `spacing` | `number` | `1` | Spacing between items |
|
|
549
|
+
| `style` | `ViewStyle` | `{}` | Container style overrides |
|
|
550
|
+
|
|
551
|
+
**GridItem Props:**
|
|
552
|
+
|
|
553
|
+
| Prop | Type | Default | Description |
|
|
554
|
+
| ------------ | ---------------------------------------- | ------- | ------------------------- |
|
|
555
|
+
| `children` | `ReactNode` | - | Item content |
|
|
556
|
+
| `col` | `number` | `2` | Number of columns to span |
|
|
557
|
+
| `alignItems` | `"center" \| "flex-start" \| "flex-end"` | - | Item alignment |
|
|
558
|
+
| `spacing` | `number` | `1` | Item spacing |
|
|
559
|
+
| `style` | `ViewStyle` | `{}` | Item style overrides |
|
|
560
|
+
|
|
561
|
+
**Example:**
|
|
562
|
+
|
|
563
|
+
```tsx
|
|
564
|
+
<Grid spacing={2}>
|
|
565
|
+
<GridItem col={2}>
|
|
566
|
+
<Typography>Full width item</Typography>
|
|
567
|
+
</GridItem>
|
|
568
|
+
<GridItem col={4} alignItems="center">
|
|
569
|
+
<Typography>Quarter width item</Typography>
|
|
570
|
+
</GridItem>
|
|
571
|
+
<GridItem col={4}>
|
|
572
|
+
<Typography>Another quarter width</Typography>
|
|
573
|
+
</GridItem>
|
|
574
|
+
</Grid>
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
### FormWrapper
|
|
290
578
|
|
|
291
|
-
A component
|
|
579
|
+
A wrapper component that provides keyboard handling and scrolling for forms.
|
|
292
580
|
|
|
293
581
|
**Props:**
|
|
294
582
|
|
|
295
|
-
| Prop
|
|
296
|
-
|
|
|
297
|
-
|
|
|
298
|
-
|
|
|
583
|
+
| Prop | Type | Default | Description |
|
|
584
|
+
| ------------------------ | ------------------------------- | ------------------ | --------------------------- |
|
|
585
|
+
| `children` | `ReactNode` | - | Form content |
|
|
586
|
+
| `mode` | `"scroll" \| "static"` | `"scroll"` | Wrapper mode |
|
|
587
|
+
| `behavior` | `KeyboardAvoidingView` behavior | Platform-dependent | Keyboard avoidance behavior |
|
|
588
|
+
| `keyboardVerticalOffset` | `number` | `10` | Keyboard offset |
|
|
589
|
+
| `contentContainerStyle` | `ViewStyle` | `{}` | ScrollView content style |
|
|
590
|
+
| `style` | `ViewStyle` | `{}` | Container style |
|
|
591
|
+
| `onScroll` | `(event) => void` | - | Scroll event handler |
|
|
592
|
+
|
|
593
|
+
**Example:**
|
|
594
|
+
|
|
595
|
+
```tsx
|
|
596
|
+
<FormWrapper mode="scroll" keyboardVerticalOffset={20}>
|
|
597
|
+
<TextField label="Name" />
|
|
598
|
+
<TextField label="Email" />
|
|
599
|
+
<Button title="Submit" />
|
|
600
|
+
</FormWrapper>
|
|
601
|
+
```
|
|
299
602
|
|
|
300
|
-
###
|
|
603
|
+
### List, ListItem & ListItemText
|
|
604
|
+
|
|
605
|
+
Components for displaying structured lists of data.
|
|
606
|
+
|
|
607
|
+
**List Props:**
|
|
608
|
+
|
|
609
|
+
| Prop | Type | Default | Description |
|
|
610
|
+
| ---------- | ----------- | ------- | ------------------------- |
|
|
611
|
+
| `children` | `ReactNode` | - | ListItem components |
|
|
612
|
+
| `style` | `ViewStyle` | `{}` | Container style overrides |
|
|
613
|
+
|
|
614
|
+
**ListItem Props:**
|
|
615
|
+
|
|
616
|
+
| Prop | Type | Default | Description |
|
|
617
|
+
| ---------- | ------------ | ------- | ------------------------- |
|
|
618
|
+
| `children` | `ReactNode` | - | Item content |
|
|
619
|
+
| `link` | `boolean` | `false` | Show arrow indicator |
|
|
620
|
+
| `divider` | `boolean` | `false` | Show bottom border |
|
|
621
|
+
| `onPress` | `() => void` | - | Press handler |
|
|
622
|
+
| `index` | `number` | `1` | Item index for animations |
|
|
623
|
+
| `style` | `ViewStyle` | `{}` | Item style overrides |
|
|
624
|
+
|
|
625
|
+
**ListItemText Props:**
|
|
626
|
+
|
|
627
|
+
| Prop | Type | Default | Description |
|
|
628
|
+
| ---------------- | ----------------- | ------- | ------------------------- |
|
|
629
|
+
| `primary` | `string` | - | Primary text |
|
|
630
|
+
| `secondary` | `string` | - | Secondary text |
|
|
631
|
+
| `divider` | `boolean` | `false` | Show bottom border |
|
|
632
|
+
| `primaryProps` | `TypographyProps` | `{}` | Primary text props |
|
|
633
|
+
| `secondaryProps` | `TypographyProps` | `{}` | Secondary text props |
|
|
634
|
+
| `style` | `ViewStyle` | `{}` | Container style overrides |
|
|
635
|
+
|
|
636
|
+
**Example:**
|
|
637
|
+
|
|
638
|
+
```tsx
|
|
639
|
+
<List>
|
|
640
|
+
<ListItem link onPress={() => navigate("Profile")}>
|
|
641
|
+
<ListItemText primary="Profile Settings" secondary="Manage your account" />
|
|
642
|
+
</ListItem>
|
|
643
|
+
<ListItem divider>
|
|
644
|
+
<ListItemText primary="Notifications" />
|
|
645
|
+
</ListItem>
|
|
646
|
+
</List>
|
|
647
|
+
```
|
|
301
648
|
|
|
302
|
-
|
|
649
|
+
### Popup
|
|
650
|
+
|
|
651
|
+
A modal component for overlays, dialogs, and bottom sheets.
|
|
303
652
|
|
|
304
653
|
**Props:**
|
|
305
654
|
|
|
306
|
-
| Prop
|
|
307
|
-
|
|
|
308
|
-
|
|
|
309
|
-
|
|
|
655
|
+
| Prop | Type | Default | Description |
|
|
656
|
+
| ------------------------ | ------------------- | ------- | ------------------------- |
|
|
657
|
+
| `open` | `boolean` | - | Whether popup is visible |
|
|
658
|
+
| `onClose` | `() => void` | - | Close handler |
|
|
659
|
+
| `title` | `string` | - | Popup title |
|
|
660
|
+
| `children` | `ReactNode` | - | Popup content |
|
|
661
|
+
| `sheet` | `boolean \| number` | `false` | Bottom sheet mode/height |
|
|
662
|
+
| `bare` | `boolean` | `false` | Hide header and padding |
|
|
663
|
+
| `keyboardVerticalOffset` | `number` | - | Keyboard avoidance offset |
|
|
664
|
+
| `style` | `ViewStyle` | `{}` | Container style overrides |
|
|
665
|
+
|
|
666
|
+
**Example:**
|
|
667
|
+
|
|
668
|
+
```tsx
|
|
669
|
+
<Popup
|
|
670
|
+
open={isOpen}
|
|
671
|
+
onClose={() => setIsOpen(false)}
|
|
672
|
+
title="Confirm Action"
|
|
673
|
+
sheet={400}
|
|
674
|
+
>
|
|
675
|
+
<Typography>Are you sure you want to delete this item?</Typography>
|
|
676
|
+
<Button title="Delete" color="error" />
|
|
677
|
+
<Button title="Cancel" variant="outlined" />
|
|
678
|
+
</Popup>
|
|
679
|
+
```
|
|
310
680
|
|
|
311
|
-
###
|
|
681
|
+
### Spinner
|
|
312
682
|
|
|
313
|
-
|
|
683
|
+
A loading indicator component with customizable appearance.
|
|
314
684
|
|
|
315
685
|
**Props:**
|
|
316
686
|
|
|
317
|
-
| Prop
|
|
318
|
-
|
|
|
319
|
-
|
|
|
320
|
-
|
|
|
687
|
+
| Prop | Type | Default | Description |
|
|
688
|
+
| ------------ | -------------------- | ----------- | ------------------------- |
|
|
689
|
+
| `size` | `"small" \| "large"` | `"large"` | Spinner size |
|
|
690
|
+
| `color` | `string` | `"primary"` | Spinner color from theme |
|
|
691
|
+
| `label` | `string` | - | Loading text |
|
|
692
|
+
| `fullscreen` | `boolean` | `false` | Cover entire screen |
|
|
693
|
+
| `style` | `ViewStyle` | `{}` | Container style overrides |
|
|
321
694
|
|
|
322
|
-
|
|
695
|
+
**Example:**
|
|
696
|
+
|
|
697
|
+
```tsx
|
|
698
|
+
<Spinner size="large" color="primary" label="Loading..." fullscreen={true} />
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
### Animator
|
|
323
702
|
|
|
324
|
-
A component for
|
|
703
|
+
A component for adding layout animations and transitions.
|
|
325
704
|
|
|
326
705
|
**Props:**
|
|
327
706
|
|
|
328
|
-
| Prop
|
|
329
|
-
|
|
|
330
|
-
|
|
|
331
|
-
|
|
|
707
|
+
| Prop | Type | Default | Description |
|
|
708
|
+
| --------------- | --------------------------------------------------------------------------- | ----------------- | ------------------------- |
|
|
709
|
+
| `children` | `ReactNode` | - | Content to animate |
|
|
710
|
+
| `type` | `"fade" \| "slideInLeft" \| "slideInRight" \| "slideInUp" \| "slideInDown"` | `"fade"` | Animation type |
|
|
711
|
+
| `duration` | `number` | `500` | Animation duration (ms) |
|
|
712
|
+
| `delay` | `number` | `100` | Animation delay (ms) |
|
|
713
|
+
| `animationType` | `"easeInEaseOut" \| "linear" \| "spring"` | `"easeInEaseOut"` | Animation timing function |
|
|
714
|
+
| `style` | `ViewStyle` | `{}` | Container style overrides |
|
|
715
|
+
|
|
716
|
+
**Example:**
|
|
717
|
+
|
|
718
|
+
```tsx
|
|
719
|
+
<Animator type="slideInUp" duration={600} delay={200} animationType="spring">
|
|
720
|
+
<Typography>This content will slide up</Typography>
|
|
721
|
+
</Animator>
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
### FlashMessage
|
|
725
|
+
|
|
726
|
+
Display toast notifications and alerts.
|
|
727
|
+
|
|
728
|
+
**Props:**
|
|
729
|
+
|
|
730
|
+
| Prop | Type | Default | Description |
|
|
731
|
+
| ---------- | --------------------------------------------- | -------- | ---------------------- |
|
|
732
|
+
| `message` | `string` | - | Message text |
|
|
733
|
+
| `type` | `"success" \| "error" \| "warning" \| "info"` | `"info"` | Message type |
|
|
734
|
+
| `duration` | `number` | `3000` | Display duration in ms |
|
|
735
|
+
| `position` | `"top" \| "bottom"` | `"top"` | Message position |
|
|
736
|
+
|
|
737
|
+
**Usage:**
|
|
738
|
+
|
|
739
|
+
```tsx
|
|
740
|
+
import { showMessage } from "@hoddy-ui/core";
|
|
741
|
+
|
|
742
|
+
// Show a success message
|
|
743
|
+
showMessage({
|
|
744
|
+
message: "Profile updated successfully!",
|
|
745
|
+
type: "success",
|
|
746
|
+
});
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
## 🔧 Hooks
|
|
750
|
+
|
|
751
|
+
### useColors
|
|
752
|
+
|
|
753
|
+
Access the current theme's color palette:
|
|
754
|
+
|
|
755
|
+
```tsx
|
|
756
|
+
import { useColors } from "@hoddy-ui/core";
|
|
757
|
+
|
|
758
|
+
function MyComponent() {
|
|
759
|
+
const colors = useColors();
|
|
760
|
+
|
|
761
|
+
return (
|
|
762
|
+
<View style={{ backgroundColor: colors.primary.main }}>
|
|
763
|
+
{/* Component content */}
|
|
764
|
+
</View>
|
|
765
|
+
);
|
|
766
|
+
}
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
### useTheme
|
|
770
|
+
|
|
771
|
+
Access and control the current theme:
|
|
772
|
+
|
|
773
|
+
```tsx
|
|
774
|
+
import { useTheme } from "@hoddy-ui/core";
|
|
775
|
+
|
|
776
|
+
function ThemeAwareComponent() {
|
|
777
|
+
const { themeState, themeDispatch } = useTheme();
|
|
778
|
+
|
|
779
|
+
const toggleTheme = () => {
|
|
780
|
+
themeDispatch({
|
|
781
|
+
type: themeState.mode === "dark" ? "light" : "dark",
|
|
782
|
+
});
|
|
783
|
+
};
|
|
784
|
+
|
|
785
|
+
return <Button title="Toggle Theme" onPress={toggleTheme} />;
|
|
786
|
+
}
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
### useNavScreenOptions
|
|
790
|
+
|
|
791
|
+
Get theme-aware navigation screen options:
|
|
792
|
+
|
|
793
|
+
```tsx
|
|
794
|
+
import { useNavScreenOptions } from "@hoddy-ui/core";
|
|
795
|
+
|
|
796
|
+
function MyScreen() {
|
|
797
|
+
const screenOptions = useNavScreenOptions("stack");
|
|
798
|
+
|
|
799
|
+
// Use with React Navigation
|
|
800
|
+
return (
|
|
801
|
+
<Stack.Screen name="Home" component={HomeScreen} options={screenOptions} />
|
|
802
|
+
);
|
|
803
|
+
}
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
## 🎯 Advanced Usage
|
|
807
|
+
|
|
808
|
+
### Custom Theme Provider
|
|
809
|
+
|
|
810
|
+
Create your own theme provider with custom configurations:
|
|
811
|
+
|
|
812
|
+
```tsx
|
|
813
|
+
import { UIThemeProvider, initialize } from "@hoddy-ui/core";
|
|
814
|
+
|
|
815
|
+
// Initialize with custom configuration
|
|
816
|
+
initialize({
|
|
817
|
+
fontFamily: "CustomFont-Regular",
|
|
818
|
+
colors: {
|
|
819
|
+
primary: { main: "#FF6B6B" },
|
|
820
|
+
secondary: { main: "#4ECDC4" },
|
|
821
|
+
},
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
function App() {
|
|
825
|
+
return (
|
|
826
|
+
<UIThemeProvider>
|
|
827
|
+
<YourAppContent />
|
|
828
|
+
</UIThemeProvider>
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
### Form Validation Example
|
|
834
|
+
|
|
835
|
+
```tsx
|
|
836
|
+
import React, { useState } from "react";
|
|
837
|
+
import { View } from "react-native";
|
|
838
|
+
import { TextField, Button, FormWrapper } from "@hoddy-ui/core";
|
|
839
|
+
|
|
840
|
+
function LoginForm() {
|
|
841
|
+
const [email, setEmail] = useState("");
|
|
842
|
+
const [password, setPassword] = useState("");
|
|
843
|
+
const [errors, setErrors] = useState({});
|
|
844
|
+
|
|
845
|
+
const validate = () => {
|
|
846
|
+
const newErrors = {};
|
|
847
|
+
if (!email) newErrors.email = "Email is required";
|
|
848
|
+
if (!password) newErrors.password = "Password is required";
|
|
849
|
+
setErrors(newErrors);
|
|
850
|
+
return Object.keys(newErrors).length === 0;
|
|
851
|
+
};
|
|
852
|
+
|
|
853
|
+
const handleSubmit = () => {
|
|
854
|
+
if (validate()) {
|
|
855
|
+
// Handle form submission
|
|
856
|
+
}
|
|
857
|
+
};
|
|
858
|
+
|
|
859
|
+
return (
|
|
860
|
+
<FormWrapper>
|
|
861
|
+
<TextField
|
|
862
|
+
label="Email"
|
|
863
|
+
value={email}
|
|
864
|
+
onChangeText={setEmail}
|
|
865
|
+
error={!!errors.email}
|
|
866
|
+
helperText={errors.email}
|
|
867
|
+
keyboardType="email-address"
|
|
868
|
+
/>
|
|
869
|
+
|
|
870
|
+
<TextField
|
|
871
|
+
label="Password"
|
|
872
|
+
value={password}
|
|
873
|
+
onChangeText={setPassword}
|
|
874
|
+
error={!!errors.password}
|
|
875
|
+
helperText={errors.password}
|
|
876
|
+
secureTextEntry
|
|
877
|
+
/>
|
|
878
|
+
|
|
879
|
+
<Button
|
|
880
|
+
title="Login"
|
|
881
|
+
onPress={handleSubmit}
|
|
882
|
+
variant="contained"
|
|
883
|
+
color="primary"
|
|
884
|
+
/>
|
|
885
|
+
</FormWrapper>
|
|
886
|
+
);
|
|
887
|
+
}
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
## 📱 Platform Compatibility
|
|
891
|
+
|
|
892
|
+
- **React Native**: ≥ 0.71.8
|
|
893
|
+
- **Expo**: SDK 48+
|
|
894
|
+
- **iOS**: 11.0+
|
|
895
|
+
- **Android**: API 21+ (Android 5.0)
|
|
896
|
+
- **TypeScript**: ≥ 5.0.4
|
|
897
|
+
|
|
898
|
+
## 🤝 Contributing
|
|
899
|
+
|
|
900
|
+
We welcome contributions! Please see our [Contributing Guide](../../CONTRIBUTING.md) for details.
|
|
901
|
+
|
|
902
|
+
## 📄 License
|
|
903
|
+
|
|
904
|
+
MIT © [Hoddy Inc](https://github.com/kinghoddy)
|
|
905
|
+
|
|
906
|
+
## 🔗 Links
|
|
907
|
+
|
|
908
|
+
- [GitHub Repository](https://github.com/kinghoddy/hoddy-ui)
|
|
909
|
+
- [npm Package](https://www.npmjs.com/package/@hoddy-ui/core)
|
|
910
|
+
- [Issues & Support](https://github.com/kinghoddy/hoddy-ui/issues)
|
|
911
|
+
|
|
912
|
+
---
|
|
913
|
+
|
|
914
|
+
**Need help?** [Open an issue](https://github.com/kinghoddy/hoddy-ui/issues) or check out our [examples](../../test/hoddyui).
|