native-variants
Version:
A library for handling variants in React Native components with theme support.
267 lines (266 loc) • 7.3 kB
TypeScript
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;