UNPKG

@hoddy-ui/core

Version:

Core rich react native components written in typescript

1,241 lines (946 loc) 39.3 kB
# @hoddy-ui/core **The complete UI component library for React Native and Expo applications** 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. ## ✨ Features - 🎨 **20+ Production-Ready Components** - From basic buttons to complex forms - 🌗 **Dark Mode Support** - Automatic theme switching with system preference detection - 🔧 **TypeScript First** - Full type safety and IntelliSense support -**Performance Optimized** - Minimal bundle size with tree shaking - 🎯 **Accessibility Ready** - WCAG compliant components - 🔌 **Highly Customizable** - Extensive theming and configuration options - 📱 **Cross Platform** - Works seamlessly on iOS and Android ## 📦 Installation ```bash npm install @hoddy-ui/core # or yarn add @hoddy-ui/core ``` ### Peer Dependencies Install the required peer dependencies: ```bash 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 react-native-reanimated ``` Or with yarn: ```bash 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 react-native-reanimated ``` **Important**: Make sure to follow the [react-native-reanimated installation guide](https://docs.swmansion.com/react-native-reanimated/docs/3.x/fundamentals/getting-started) for platform-specific setup as it requires additional configuration for iOS and Android. ## 🚀 Quick Start ### Basic Setup 1. **Initialize the library** (optional but recommended): ```tsx import { initialize } from "@hoddy-ui/core"; initialize({ // Google Maps API key for Locator component googleMapApiKey: "your-google-maps-api-key", // Edge-to-edge display (affects Android navigation bar styling) edgeToEdge: false, // Custom colors colors: { primary: { main: "#6366f1", light: "#818cf8", dark: "#4f46e5", }, }, // Typography settings typography: { fontFamily: "Inter-Regular", fontWeights: { 400: "Inter-Regular", 500: "Inter-Medium", 600: "Inter-SemiBold", 700: "Inter-Bold", }, }, }); ``` 2. **Wrap your app with the theme provider**: ```tsx import React from "react"; import { UIThemeProvider } from "@hoddy-ui/core"; import App from "./App"; export default function Root() { return ( <UIThemeProvider> <App /> </UIThemeProvider> ); } ``` 3. **Start using components**: ```tsx import React from "react"; import { View } from "react-native"; import { Typography, Button, TextField, Animator, useColors, useFadeAnimation, } from "@hoddy-ui/core"; export default function HomeScreen() { const colors = useColors(); return ( <View style={{ padding: 20, backgroundColor: colors.white[1] }}> <Animator type="fade" duration={1000}> <Typography variant="h4" color="primary" gutterBottom={20}> Welcome to Hoddy UI! </Typography> </Animator> <Animator type="slide" direction="up" delay={200}> <TextField label="Email Address" variant="outlined" keyboardType="email-address" gutterBottom={16} /> </Animator> <Animator type="grow" delay={400}> <Button title="Get Started" variant="contained" color="primary" onPress={() => console.log("Button pressed!")} /> </Animator> </View> ); } ``` ## ⚙️ Configuration ### Global Configuration Use the `initialize` function to configure the library globally: ```tsx import { initialize } from "@hoddy-ui/core"; initialize({ // Google Maps API key for map components googleMapApiKey?: string; // Custom color palette overrides colors?: { primary?: { main: string; light?: string; dark?: string }; secondary?: { main: string; light?: string; dark?: string }; // ... and more color options }; // Enable edge-to-edge display mode edgeToEdge?: boolean; // Typography settings typography?: { // Primary font family fontFamily?: string; // Font family mappings for each weight (Android support) fontWeights?: { 100?: string; 200?: string; 300?: string; 400?: string; 500?: string; 600?: string; 700?: string; 800?: string; 900?: string; }; }; }); ``` ### Configuration Example ```tsx initialize({ googleMapApiKey: "AIzaSyBxxxxxxxxxxxxxxxxxxxxxx", edgeToEdge: true, colors: { primary: "#007AFF", secondary: "#34C759", }, typography: { fontFamily: "Inter", fontWeights: { 400: "Inter-Regular", 500: "Inter-Medium", 600: "Inter-SemiBold", 700: "Inter-Bold", }, }, }); ``` **Note:** The `fontWeights` property is particularly useful for Android devices where different font weights require separate font family files. This allows you to map each weight (100-900) to its corresponding font family name. ### Theme Configuration The theme system automatically detects system preferences and can be controlled programmatically: ```tsx import { useTheme } from "@hoddy-ui/core"; function ThemeToggle() { const { themeState, themeDispatch } = useTheme(); const toggleTheme = () => { themeDispatch({ type: themeState.mode === "dark" ? "light" : "dark", }); }; return ( <Button title={`Switch to ${themeState.mode === "dark" ? "Light" : "Dark"} Mode`} onPress={toggleTheme} /> ); } ``` ## 🎨 Theming System ### Using Hooks Access theme colors and state throughout your app: ```tsx import { useColors, useTheme } from "@hoddy-ui/core"; function MyComponent() { const colors = useColors(); const theme = useTheme(); return ( <View style={{ backgroundColor: colors.white[1], borderColor: colors.primary.main, }} > <Typography color={theme === "dark" ? "white" : "dark"}> Current theme: {theme} </Typography> </View> ); } ``` ### Color Palette The library includes a comprehensive color system: ```tsx const colors = { // Primary colors primary: { main: "#007AFF", light: "#5AC8FA", dark: "#0051D5" }, secondary: { main: "#FF3B30", light: "#FF6B6B", dark: "#D70015" }, // Neutral colors white: ["#FFFFFF", "#F8F9FA", "#E9ECEF"], black: ["#000000", "#212529", "#495057"], // Semantic colors success: { main: "#28A745", light: "#34CE57", dark: "#1E7E34" }, error: { main: "#DC3545", light: "#E74C3C", dark: "#C82333" }, warning: { main: "#FFC107", light: "#FFD54F", dark: "#FF8F00" }, // Utility colors textPrimary: { main: "#212529" }, textSecondary: { main: "#6C757D" }, divider: { main: "#DEE2E6" }, }; ``` ## 🧩 Components ### Layout & Structure - **`SafeAreaView`** - Safe area wrapper for different devices - **`Grid`** & **`GridItem`** - Flexible grid layout system - **`FormWrapper`** - Form container with validation support ### Navigation & Status - **`AdaptiveStatusBar`** - Theme-aware status bar - Navigation utilities via hooks ### Typography - **`Typography`** - Comprehensive text component with variants (h1-h6, body1-body2, caption) ### Form Components - **`TextField`** - Material Design text input with variants - **`TextField2`** - Alternative text field design - **`OTPInput`** - One-Time Password input with auto-advance and paste support - **`Locator`** - Location picker with Google Maps integration ### Interactive Elements - **`Button`** - Primary action buttons with variants - **`IconButton`** - Icon-only buttons - **`LinkButton`** - Text-based link buttons ### Feedback & Communication - **`FlashMessage`** - Toast notifications and alerts - **`AlertX`** - Customizable alert dialogs - **`Spinner`** - Loading indicators ### Data Display - **`Avatar`** - User profile images and placeholders - **`List`**, **`ListItem`**, **`ListItemText`** - List components ### Overlays & Modals - **`Popup`** - Modal dialogs and bottom sheets ### Animation - **`Animator`** - Layout animations and transitions ## 📖 Component API Reference ### Typography A versatile text component supporting multiple variants and styling options. **Props:** | Prop | Type | Default | Description | | -------------- | --------------------------------------------------------------------------------- | --------- | ----------------------------- | | `variant` | `"h1" \| "h2" \| "h3" \| "h4" \| "h5" \| "h6" \| "body1" \| "body2" \| "caption"` | `"body1"` | Text style variant | | `color` | `string` | `"dark"` | Text color from theme palette | | `align` | `"left" \| "center" \| "right"` | `"left"` | Text alignment | | `gutterBottom` | `number` | `0` | Bottom margin in pixels | | `fontWeight` | `number` | `400` | Font weight | | `textCase` | `"uppercase" \| "lowercase" \| "capitalize"` | `null` | Text transformation | **Example:** ```tsx <Typography variant="h4" color="primary" gutterBottom={20}> Welcome to Hoddy UI </Typography> ``` ### Button A comprehensive button component with multiple variants and states. **Props:** | Prop | Type | Default | Description | | ---------- | ------------------------------------- | ------------- | -------------------------- | | `title` | `string` | - | Button text | | `variant` | `"contained" \| "outlined" \| "text"` | `"contained"` | Button variant | | `color` | `string` | `"primary"` | Button color from theme | | `size` | `"small" \| "medium" \| "large"` | `"medium"` | Button size | | `disabled` | `boolean` | `false` | Disabled state | | `loading` | `boolean` | `false` | Loading state with spinner | | `onPress` | `() => void` | - | Press handler | | `start` | `ReactNode` | - | Leading icon/element | | `end` | `ReactNode` | - | Trailing icon/element | **Example:** ```tsx <Button title="Submit" variant="contained" color="primary" loading={isLoading} onPress={handleSubmit} /> ``` ### IconButton A button component that displays only an icon. **Props:** | Prop | Type | Default | Description | | ----------------- | --------------------- | ------------ | ------------------------- | | `icon` | `string` | - | Icon name | | `iconType` | `"material" \| "ion"` | `"material"` | Icon library to use | | `size` | `number` | `24` | Icon size in pixels | | `color` | `string` | `"dark"` | Icon color from theme | | `bg` | `boolean` | `false` | Show background circle | | `elevation` | `number` | `0` | Shadow elevation | | `disabled` | `boolean` | `false` | Disabled state | | `onPress` | `() => void` | - | Press handler | | `style` | `ViewStyle` | `{}` | Icon style overrides | | `containerStyles` | `ViewStyle` | `{}` | Container style overrides | **Example:** ```tsx <IconButton icon="star" iconType="ion" size={28} color="primary" bg={true} elevation={2} onPress={() => console.log("Starred!")} /> ``` ### LinkButton A text-based button component for navigation or secondary actions. **Props:** | Prop | Type | Default | Description | | ------------ | ------------ | -------- | --------------------- | | `title` | `string` | - | Button text | | `color` | `string` | `"blue"` | Text color from theme | | `fontSize` | `number` | `12` | Font size | | `fontWeight` | `string` | `"400"` | Font weight | | `disabled` | `boolean` | `false` | Disabled state | | `onPress` | `() => void` | - | Press handler | | `style` | `TextStyle` | `{}` | Text style overrides | **Example:** ```tsx <LinkButton title="Forgot Password?" color="primary" fontSize={14} onPress={() => navigation.navigate("ForgotPassword")} /> ``` ### TextField A Material Design text input component with comprehensive features. **Props:** | Prop | Type | Default | Description | | -------------- | -------------------------------------- | ------------ | --------------------- | | `label` | `string` | - | Input label | | `variant` | `"outlined" \| "filled" \| "standard"` | `"outlined"` | Input variant | | `value` | `string` | - | Input value | | `onChangeText` | `(text: string) => void` | - | Change handler | | `placeholder` | `string` | - | Placeholder text | | `error` | `boolean` | `false` | Error state | | `helperText` | `string` | - | Helper/error text | | `disabled` | `boolean` | `false` | Disabled state | | `multiline` | `boolean` | `false` | Multiline input | | `start` | `ReactNode` | - | Leading icon/element | | `end` | `ReactNode` | - | Trailing icon/element | **Example:** ```tsx <TextField label="Email Address" variant="outlined" value={email} onChangeText={setEmail} keyboardType="email-address" error={!!emailError} helperText={emailError} /> ``` ### OTPInput A specialized input component for One-Time Password entry with auto-advance, paste support, and backspace handling. **Props:** | Prop | Type | Default | Description | | ---------- | ------------------------------------- | ------------ | -------------------------------- | | `length` | `number` | `6` | Number of OTP digits | | `onChange` | `(value: string) => void` | - | Change handler for OTP value | | `value` | `string` | `""` | Current OTP value | | `variant` | `"outlined" \| "text" \| "contained"` | `"outlined"` | Input variant style | | `spacing` | `number` | `1` | Spacing between input boxes | | `size` | `number` | `45` | Size of each input box in pixels | **Features:** - **Auto-advance**: Automatically moves to next input after digit entry - **Paste support**: Handles pasting of complete OTP codes - **Backspace handling**: Moves to previous input on backspace - **Number-only input**: Automatically filters non-numeric characters - **Customizable styling**: Supports different variants and sizes **Example:** ```tsx const [otp, setOtp] = useState(''); <OTPInput length={6} value={otp} onChange={setOtp} variant="outlined" size={50} spacing={2} /> // Usage with form validation <OTPInput length={4} value={otp} onChange={(value) => { setOtp(value); if (value.length === 4) { verifyOTP(value); } }} variant="contained" /> ``` ### Locator A location picker component with Google Maps integration. **Props:** | Prop | Type | Default | Description | | -------------------- | ---------------------------------- | ------------- | -------------------------- | | `onLocationSelected` | `(location: LocationType) => void` | - | Location selection handler | | `label` | `string` | - | Input label | | `variant` | `"contained" \| "outlined"` | `"contained"` | Input variant | | `location` | `LocationType` | - | Current location | | `country` | `string` | `"ng"` | Country code for search | | `error` | `boolean` | `false` | Error state | **Example:** ```tsx <Locator label="Select Location" onLocationSelected={(location) => setSelectedLocation(location)} country="us" /> ``` ### SafeAreaView A safe area wrapper component that handles device-specific safe areas. **Props:** | Prop | Type | Default | Description | | ---------- | ----------- | ------- | ------------------------- | | `children` | `ReactNode` | - | Child components | | `style` | `ViewStyle` | `{}` | Container style overrides | **Example:** ```tsx <SafeAreaView style={{ backgroundColor: "white" }}> <YourContent /> </SafeAreaView> ``` ### AdaptiveStatusBar A status bar component that automatically adapts to the current theme. **Props:** | Prop | Type | Default | Description | | ------------- | --------- | ------- | ------------------------------------- | | `translucent` | `boolean` | `false` | Whether the status bar is translucent | **Example:** ```tsx <AdaptiveStatusBar translucent={true} /> ``` ### AlertX A customizable alert component for displaying important messages. **Props:** | Prop | Type | Default | Description | | -------------- | --------------------------------------------- | ------------- | ------------------------- | | `type` | `"info" \| "warning" \| "success" \| "error"` | `"info"` | Alert type | | `variant` | `"contained" \| "outlined"` | `"contained"` | Alert variant | | `title` | `string` | - | Alert title | | `body` | `string` | - | Alert message | | `gutterBottom` | `number` | `0` | Bottom margin in pixels | | `style` | `ViewStyle` | `{}` | Container style overrides | **Example:** ```tsx <AlertX type="success" title="Success!" body="Your profile has been updated successfully." gutterBottom={20} /> ``` ### Avatar A component for displaying user avatars with support for images, labels, or default icons. **Props:** | Prop | Type | Default | Description | | --------- | --------------------------- | ------------- | --------------------------- | | `source` | `ImageSourcePropType` | - | Image source | | `label` | `string` | - | Text label (first letter) | | `size` | `number` | `48` | Avatar size in pixels | | `color` | `string` | `"dark"` | Background color from theme | | `variant` | `"contained" \| "outlined"` | `"contained"` | Avatar variant | | `style` | `ViewStyle` | `{}` | Container style overrides | **Example:** ```tsx <Avatar source={{ uri: 'https://example.com/avatar.jpg' }} size={64} /> <Avatar label="John Doe" color="primary" size={48} /> ``` ### Grid & GridItem Flexible grid layout components for organizing content. **Grid Props:** | Prop | Type | Default | Description | | ---------- | ----------- | ------- | ------------------------- | | `children` | `ReactNode` | - | GridItem components | | `spacing` | `number` | `1` | Spacing between items | | `style` | `ViewStyle` | `{}` | Container style overrides | **GridItem Props:** | Prop | Type | Default | Description | | ------------ | ---------------------------------------- | ------- | ------------------------- | | `children` | `ReactNode` | - | Item content | | `col` | `number` | `2` | Number of columns to span | | `alignItems` | `"center" \| "flex-start" \| "flex-end"` | - | Item alignment | | `spacing` | `number` | `1` | Item spacing | | `style` | `ViewStyle` | `{}` | Item style overrides | **Example:** ```tsx <Grid spacing={2}> <GridItem col={2}> <Typography>Full width item</Typography> </GridItem> <GridItem col={4} alignItems="center"> <Typography>Quarter width item</Typography> </GridItem> <GridItem col={4}> <Typography>Another quarter width</Typography> </GridItem> </Grid> ``` ### FormWrapper A wrapper component that provides keyboard handling and scrolling for forms. **Props:** | Prop | Type | Default | Description | | ------------------------ | ------------------------------- | ------------------ | --------------------------- | | `children` | `ReactNode` | - | Form content | | `mode` | `"scroll" \| "static"` | `"scroll"` | Wrapper mode | | `behavior` | `KeyboardAvoidingView` behavior | Platform-dependent | Keyboard avoidance behavior | | `keyboardVerticalOffset` | `number` | `10` | Keyboard offset | | `contentContainerStyle` | `ViewStyle` | `{}` | ScrollView content style | | `style` | `ViewStyle` | `{}` | Container style | | `onScroll` | `(event) => void` | - | Scroll event handler | **Example:** ```tsx <FormWrapper mode="scroll" keyboardVerticalOffset={20}> <TextField label="Name" /> <TextField label="Email" /> <Button title="Submit" /> </FormWrapper> ``` ### List, ListItem & ListItemText Components for displaying structured lists of data. **List Props:** | Prop | Type | Default | Description | | ---------- | ----------- | ------- | ------------------------- | | `children` | `ReactNode` | - | ListItem components | | `style` | `ViewStyle` | `{}` | Container style overrides | **ListItem Props:** | Prop | Type | Default | Description | | ---------- | ------------ | ------- | ------------------------- | | `children` | `ReactNode` | - | Item content | | `link` | `boolean` | `false` | Show arrow indicator | | `divider` | `boolean` | `false` | Show bottom border | | `onPress` | `() => void` | - | Press handler | | `index` | `number` | `1` | Item index for animations | | `style` | `ViewStyle` | `{}` | Item style overrides | **ListItemText Props:** | Prop | Type | Default | Description | | ---------------- | ----------------- | ------- | ------------------------- | | `primary` | `string` | - | Primary text | | `secondary` | `string` | - | Secondary text | | `divider` | `boolean` | `false` | Show bottom border | | `primaryProps` | `TypographyProps` | `{}` | Primary text props | | `secondaryProps` | `TypographyProps` | `{}` | Secondary text props | | `style` | `ViewStyle` | `{}` | Container style overrides | **Example:** ```tsx <List> <ListItem link onPress={() => navigate("Profile")}> <ListItemText primary="Profile Settings" secondary="Manage your account" /> </ListItem> <ListItem divider> <ListItemText primary="Notifications" /> </ListItem> </List> ``` ### Popup A modal component for overlays, dialogs, and bottom sheets. **Props:** | Prop | Type | Default | Description | | ------------------------ | ------------------- | ------- | ------------------------- | | `open` | `boolean` | - | Whether popup is visible | | `onClose` | `() => void` | - | Close handler | | `title` | `string` | - | Popup title | | `children` | `ReactNode` | - | Popup content | | `sheet` | `boolean \| number` | `false` | Bottom sheet mode/height | | `bare` | `boolean` | `false` | Hide header and padding | | `keyboardVerticalOffset` | `number` | - | Keyboard avoidance offset | | `onModalShow` | `() => void` | - | Callback when modal shows | | `onModalHide` | `() => void` | - | Callback when modal hides | | `style` | `ViewStyle` | `{}` | Container style overrides | **Example:** ```tsx <Popup open={isOpen} onClose={() => setIsOpen(false)} title="Confirm Action" sheet={400} onModalShow={() => console.log("Modal is now visible")} onModalHide={() => console.log("Modal is now hidden")} > <Typography>Are you sure you want to delete this item?</Typography> <Button title="Delete" color="error" /> <Button title="Cancel" variant="outlined" /> </Popup> ``` ### Spinner A loading indicator component with customizable appearance. **Props:** | Prop | Type | Default | Description | | ------------ | -------------------- | ----------- | ------------------------- | | `size` | `"small" \| "large"` | `"large"` | Spinner size | | `color` | `string` | `"primary"` | Spinner color from theme | | `label` | `string` | - | Loading text | | `fullscreen` | `boolean` | `false` | Cover entire screen | | `style` | `ViewStyle` | `{}` | Container style overrides | **Example:** ```tsx <Spinner size="large" color="primary" label="Loading..." fullscreen={true} /> ``` ### Animator A unified component that provides a single interface for all animation types with generic props. Built with **react-native-reanimated** for optimal performance and smooth animations. **Features:** - **Single Component**: One component handles all animation types - **Generic Props**: Consistent prop naming across all animations (e.g., `closeAfter` instead of animation-specific names) - **Modular Hooks**: Animation logic is separated into individual custom hooks - **Type Safety**: Full TypeScript support with proper typing - **Performance**: Built with react-native-reanimated for native performance - **Smooth Animations**: Runs on the UI thread for 60fps animations **Requirements:** Requires `react-native-reanimated` as peer dependencies. Make sure to follow the [react-native-reanimated installation guide](https://docs.swmansion.com/react-native-reanimated/docs/3.x/fundamentals/getting-started) for platform-specific setup. **Generic Props:** All animation types support these generic props: | Prop | Type | Default | Description | | ------------ | --------------------------------------------------------------------------- | ------- | ------------------------------------------------------------- | | `type` | `"fade" \| "grow" \| "slide" \| "blink" \| "float" \| "roll" \| "thrownup"` | - | Animation type | | `duration` | `number` | `500` | Animation duration in milliseconds | | `delay` | `number` | `0` | Delay before animation starts | | `closeAfter` | `number \| null` | `null` | Time after which the exit animation starts (null for no exit) | | `style` | `ViewStyle` | `{}` | Additional styles for the animated view | **Animation-Specific Props:** **Slide Animation:** - `direction`: `"up" \| "down" \| "left" \| "right"` - `initialValue`: Custom initial position value **Grow Animation:** - `initialScale`: Starting scale (default: 0) **Blink Animation:** - `blinkDuration`: Duration of one blink cycle - `minOpacity`: Minimum opacity value - `maxOpacity`: Maximum opacity value **Float Animation:** - `closeDuration`: Duration of exit animation - `floatDistance`: Distance to float up/down - `floatDuration`: Duration of one float cycle **Roll Animation:** - `initialTranslateY`: Initial vertical position - `initialRotate`: Initial rotation value **Examples:** ```tsx // Fade animation <Animator type="fade" duration={1000} closeAfter={3000}> <Text>This will fade in and out</Text> </Animator> // Slide animation <Animator type="slide" direction="up" duration={800} closeAfter={2000}> <View>This will slide up from bottom</View> </Animator> // Grow animation <Animator type="grow" initialScale={0.5} duration={600}> <Button>This will grow from 50% scale</Button> </Animator> // Blink animation (continuous) <Animator type="blink" blinkDuration={1000} minOpacity={0.3}> <Icon>This will blink continuously</Icon> </Animator> // Float animation <Animator type="float" floatDistance={20} floatDuration={2000} closeAfter={5000}> <View>This will float up and down</View> </Animator> // Roll animation <Animator type="roll" initialRotate="45deg" duration={800}> <Image>This will roll and rotate</Image> </Animator> // Thrown up animation <Animator type="thrownup" delay={500} closeAfter={4000}> <Notification>This will spring up from bottom</Notification> </Animator> ``` **Available Animation Types:** 1. **fade**: Simple fade in/out using opacity (native performance) 2. **grow**: Scale-based growth animation with easing 3. **slide**: Directional slide animations from screen edges 4. **blink**: Continuous opacity blinking with repeat 5. **float**: Floating up/down motion with fade effects 6. **roll**: Combined rotation and translation effects 7. **thrownup**: Spring-based upward animation with physics All animations run on the UI thread for optimal performance and smooth 60fps animations. **Using Animation Hooks Directly:** You can also use the animation hooks directly for custom implementations with react-native-reanimated: ```tsx import { useFadeAnimation, useSlideAnimation } from "@hoddy-ui/core"; import Animated from "react-native-reanimated"; const MyComponent = () => { const { animatedStyle } = useFadeAnimation({ duration: 800, closeAfter: 2000, }); return ( <Animated.View style={animatedStyle}> <Text>Custom animated content</Text> </Animated.View> ); }; ``` **Performance Benefits:** With react-native-reanimated, all animations: - **Run on the UI thread** for better performance - **Maintain 60fps** even during JavaScript thread blocking - **Use native drivers** automatically - **Support worklets** for complex animation logic - **Provide smooth gestures** and interactions **Migration from Legacy API:** Replace old individual animation components: ```tsx // Old way <AnimatedFade fadeOutAfter={2000}> <Text>Content</Text> </AnimatedFade> // New way <Animator type="fade" closeAfter={2000}> <Text>Content</Text> </Animator> ``` ### FlashMessage Display toast notifications and alerts. **Props:** | Prop | Type | Default | Description | | ---------- | --------------------------------------------- | -------- | ---------------------- | | `message` | `string` | - | Message text | | `type` | `"success" \| "error" \| "warning" \| "info"` | `"info"` | Message type | | `duration` | `number` | `3000` | Display duration in ms | | `position` | `"top" \| "bottom"` | `"top"` | Message position | **Usage:** ```tsx import { showMessage } from "@hoddy-ui/core"; // Show a success message showMessage({ message: "Profile updated successfully!", type: "success", }); ``` ## 🔧 Hooks ### useColors Access the current theme's color palette: ```tsx import { useColors } from "@hoddy-ui/core"; function MyComponent() { const colors = useColors(); return ( <View style={{ backgroundColor: colors.primary.main }}> {/* Component content */} </View> ); } ``` ### useTheme Access and control the current theme: ```tsx import { useTheme } from "@hoddy-ui/core"; function ThemeAwareComponent() { const { themeState, themeDispatch } = useTheme(); const toggleTheme = () => { themeDispatch({ type: themeState.mode === "dark" ? "light" : "dark", }); }; return <Button title="Toggle Theme" onPress={toggleTheme} />; } ``` ### useNavScreenOptions Get theme-aware navigation screen options: ```tsx import { useNavScreenOptions } from "@hoddy-ui/core"; function MyScreen() { const screenOptions = useNavScreenOptions("stack"); // Use with React Navigation return ( <Stack.Screen name="Home" component={HomeScreen} options={screenOptions} /> ); } ``` ### Animation Hooks Access animation logic directly for custom implementations using react-native-reanimated: #### useFadeAnimation ```tsx import { useFadeAnimation } from "@hoddy-ui/core"; import Animated from "react-native-reanimated"; function FadeComponent() { const { animatedStyle } = useFadeAnimation({ duration: 800, closeAfter: 2000, }); return ( <Animated.View style={animatedStyle}> <Text>This will fade in and out</Text> </Animated.View> ); } ``` #### useSlideAnimation ```tsx import { useSlideAnimation } from "@hoddy-ui/core"; import Animated from "react-native-reanimated"; function SlideComponent() { const { animatedStyle } = useSlideAnimation({ direction: "up", duration: 600, initialValue: 100, }); return ( <Animated.View style={animatedStyle}> <Text>This will slide up</Text> </Animated.View> ); } ``` #### useGrowAnimation ```tsx import { useGrowAnimation } from "@hoddy-ui/core"; import Animated from "react-native-reanimated"; function GrowComponent() { const { animatedStyle } = useGrowAnimation({ duration: 500, initialScale: 0.5, }); return ( <Animated.View style={animatedStyle}> <Text>This will grow from 50% scale</Text> </Animated.View> ); } ``` #### Other Animation Hooks - `useBlinkAnimation` - For continuous blinking effects - `useFloatAnimation` - For floating up/down motion - `useRollAnimation` - For rotation and translation effects - `useThrownUpAnimation` - For spring-based upward animations All animation hooks accept similar configuration objects with properties like `duration`, `delay`, and animation-specific options. They return `animatedStyle` objects that work with `Animated.View` from react-native-reanimated for optimal performance. ## 🎯 Advanced Usage ### Custom Theme Provider Create your own theme provider with custom configurations: ```tsx import { UIThemeProvider, initialize } from "@hoddy-ui/core"; // Initialize with custom configuration initialize({ fontFamily: "CustomFont-Regular", colors: { primary: { main: "#FF6B6B" }, secondary: { main: "#4ECDC4" }, }, }); function App() { return ( <UIThemeProvider> <YourAppContent /> </UIThemeProvider> ); } ``` ### Form Validation Example ```tsx import React, { useState } from "react"; import { View } from "react-native"; import { TextField, Button, FormWrapper } from "@hoddy-ui/core"; function LoginForm() { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [errors, setErrors] = useState({}); const validate = () => { const newErrors = {}; if (!email) newErrors.email = "Email is required"; if (!password) newErrors.password = "Password is required"; setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const handleSubmit = () => { if (validate()) { // Handle form submission } }; return ( <FormWrapper> <TextField label="Email" value={email} onChangeText={setEmail} error={!!errors.email} helperText={errors.email} keyboardType="email-address" /> <TextField label="Password" value={password} onChangeText={setPassword} error={!!errors.password} helperText={errors.password} secureTextEntry /> <Button title="Login" onPress={handleSubmit} variant="contained" color="primary" /> </FormWrapper> ); } ``` ## 📱 Platform Compatibility - **React Native**: ≥ 0.71.8 - **Expo**: SDK 48+ - **iOS**: 11.0+ - **Android**: API 21+ (Android 5.0) - **TypeScript**: ≥ 5.0.4 ## 🤝 Contributing We welcome contributions! Please see our [Contributing Guide](../../CONTRIBUTING.md) for details. ## 📄 License MIT © [Hoddy Inc](https://github.com/kinghoddy) ## 🔗 Links - [GitHub Repository](https://github.com/kinghoddy/hoddy-ui) - [npm Package](https://www.npmjs.com/package/@hoddy-ui/core) - [Issues & Support](https://github.com/kinghoddy/hoddy-ui/issues) --- **Need help?** [Open an issue](https://github.com/kinghoddy/hoddy-ui/issues) or check out our [examples](../../test/my-app).