UNPKG

native-variants

Version:

A library for handling variants in React Native components with theme support.

267 lines (266 loc) 7.3 kB
import React from "react"; import type { ColorSchemeConfig } from "../types.js"; /** * Color scheme options for the theme. */ export type ColorScheme = "light" | "dark"; /** * Theme mode options. * - "light": Always use light theme * - "dark": Always use dark theme * - "system": Follow system preference */ export type ThemeMode = ColorScheme | "system"; /** * Theme context value interface. * * @template T - The colors type */ export interface ThemeContextValue<T extends Record<string, string>> { /** Current color scheme (resolved from mode) */ colorScheme: ColorScheme; /** Current theme mode setting */ mode: ThemeMode; /** Whether dark mode is active */ isDark: boolean; /** Current theme colors based on color scheme */ colors: T; /** Set theme mode */ setMode: (mode: ThemeMode) => void; /** Toggle between light and dark (ignores system) */ toggle: () => void; } /** * Props for ThemeProvider component. * * @template T - The colors type */ export interface ThemeProviderProps<T extends Record<string, string>> { /** Child components */ children: React.ReactNode; /** * Color scheme configuration with default (light) and dark colors. * Get this from createNVA's colorScheme output. * * @example * ```tsx * const { colorScheme } = createNVA({ * theme: { * colors: { * default: { primary: "#000" }, * dark: { primary: "#fff" }, * }, * }, * }); * * <ThemeProvider colors={colorScheme}> * <App /> * </ThemeProvider> * ``` */ colors: ColorSchemeConfig<T>; /** Initial theme mode (default: "system") */ defaultMode?: ThemeMode; /** Custom storage get function for persisting theme preference */ onGetStorage?: () => Promise<ThemeMode | null>; /** Custom storage set function for persisting theme preference */ onSetStorage?: (mode: ThemeMode) => Promise<void>; } /** * ThemeProvider component. * Provides theme context with dark/light mode support. * * **Important:** This provider requires colors to be passed explicitly. * Get colors from createNVA's colorScheme output. * * @template T - The colors type * * @example * ```tsx * // 1. Create your theme with createNVA * const { theme, colorScheme, styled } = createNVA({ * theme: { * colors: { * default: { * background: "#ffffff", * foreground: "#000000", * primary: "#3b82f6", * }, * dark: { * background: "#0a0a0a", * foreground: "#ffffff", * primary: "#60a5fa", * }, * }, * }, * }); * * // 2. Wrap your app with ThemeProvider * function App() { * return ( * <ThemeProvider colors={colorScheme}> * <MyApp /> * </ThemeProvider> * ); * } * * // 3. Use colors in components * function MyComponent() { * const { colors, isDark, toggle } = useTheme(); * * return ( * <View style={{ backgroundColor: colors.background }}> * <Text style={{ color: colors.foreground }}> * {isDark ? "Dark Mode" : "Light Mode"} * </Text> * <Button onPress={toggle} title="Toggle" /> * </View> * ); * } * * // With AsyncStorage persistence * import AsyncStorage from "@react-native-async-storage/async-storage"; * * <ThemeProvider * colors={colorScheme} * defaultMode="system" * onGetStorage={async () => { * const mode = await AsyncStorage.getItem("theme-mode"); * return mode as ThemeMode | null; * }} * onSetStorage={async (mode) => { * await AsyncStorage.setItem("theme-mode", mode); * }} * > * <App /> * </ThemeProvider> * ``` */ export declare function ThemeProvider<T extends Record<string, string>>({ children, colors, defaultMode, onGetStorage, onSetStorage, }: ThemeProviderProps<T>): React.JSX.Element | null; /** * Hook to access theme context. * Must be used within a ThemeProvider. * * @template T - The colors type * @returns Theme context value with colors and controls * @throws Error if used outside ThemeProvider * * @example * ```tsx * function MyComponent() { * const { colors, isDark, toggle, setMode } = useTheme<MyColors>(); * * return ( * <View style={{ backgroundColor: colors.background }}> * <Text style={{ color: colors.foreground }}> * Current mode: {isDark ? "Dark" : "Light"} * </Text> * <Button onPress={toggle} title="Toggle Theme" /> * <Button onPress={() => setMode("system")} title="Use System" /> * </View> * ); * } * ``` */ export declare function useTheme<T extends Record<string, string>>(): ThemeContextValue<T>; /** * Hook to access only theme colors. * Convenience wrapper around useTheme that returns just the colors. * * @template T - The colors type * @returns Current theme colors * * @example * ```tsx * function MyComponent() { * const colors = useThemeColors<MyColors>(); * * return ( * <View style={{ backgroundColor: colors.background }}> * <Text style={{ color: colors.primary }}>Hello</Text> * </View> * ); * } * ``` */ export declare function useThemeColors<T extends Record<string, string>>(): T; /** * Hook to check if dark mode is active. * Convenience wrapper for quick dark mode checks. * * @returns Boolean indicating if dark mode is active * * @example * ```tsx * function MyComponent() { * const isDark = useIsDark(); * * return ( * <Image source={isDark ? darkLogo : lightLogo} /> * ); * } * ``` */ export declare function useIsDark(): boolean; /** * Hook to get the current color scheme. * Returns "light" or "dark" based on current theme. * * @returns Current color scheme * * @example * ```tsx * function MyComponent() { * const colorScheme = useColorScheme(); * * return ( * <StatusBar barStyle={colorScheme === "dark" ? "light-content" : "dark-content"} /> * ); * } * ``` */ export declare function useColorScheme(): ColorScheme; /** * Creates a themed style helper that automatically uses current theme colors. * Useful for creating styled components with theme access. * * @template T - The colors type * @template S - The styles record type * @param styleFactory - Function that receives colors and returns styles * @returns Hook that returns computed styles * * @example * ```tsx * type MyColors = { card: string; border: string; cardForeground: string }; * * const useCardStyles = createThemedStyles<MyColors, { * container: ViewStyle; * title: TextStyle; * }>((colors) => ({ * container: { * backgroundColor: colors.card, * borderColor: colors.border, * borderWidth: 1, * borderRadius: 8, * padding: 16, * }, * title: { * color: colors.cardForeground, * fontSize: 18, * fontWeight: "600", * }, * })); * * function Card({ title, children }) { * const styles = useCardStyles(); * * return ( * <View style={styles.container}> * <Text style={styles.title}>{title}</Text> * {children} * </View> * ); * } * ``` */ export declare function createThemedStyles<T extends Record<string, string>, S extends Record<string, object>>(styleFactory: (colors: T) => S): () => S;