Skip to content

Latest commit

ย 

History

History
600 lines (494 loc) ยท 14.4 KB

File metadata and controls

600 lines (494 loc) ยท 14.4 KB

Theme Hooks Documentation

This document provides detailed documentation for the theme hooks used in the Fynd Commerce App. These hooks provide a clean, type-safe interface for accessing and using theme data.

๐ŸŽฏ Overview

The theme system provides two main hooks:

  1. useCustomTheme - Access theme data directly in components
  2. useThemedStyles - Create themed styles with memoization

๐ŸŽจ useCustomTheme Hook

Import

import {useCustomTheme} from '../shared/hooks/use-custom-theme';

Purpose

The useCustomTheme hook provides direct access to the current theme configuration, including colors, typography, spacing, and layout properties.

API Reference

Returns

  • CustomTheme: The current theme configuration object

Throws

  • Error: If used outside of ThemeProvider context
  • Error: If theme is missing required properties

Usage Examples

Basic Usage

import {useCustomTheme} from '../shared/hooks/use-custom-theme';

const MyComponent = () => {
  const theme = useCustomTheme();

  return (
    <View style={{backgroundColor: theme.color.primaryColor}}>
      <Text style={{color: theme.color.textBody}}>Hello World</Text>
    </View>
  );
};

Typography Usage

const TypographyExample = () => {
  const theme = useCustomTheme();

  return (
    <View>
      <Text
        style={{
          fontSize: theme.typography.fontSize.heading,
          fontWeight: theme.typography.fontWeight.bold,
          color: theme.color.textHeading,
          lineHeight: theme.typography.lineHeight.heading,
        }}>
        Heading Text
      </Text>
      <Text
        style={{
          fontSize: theme.typography.fontSize.base,
          fontWeight: theme.typography.fontWeight.regular,
          color: theme.color.textBody,
          lineHeight: theme.typography.lineHeight.base,
        }}>
        Body Text
      </Text>
    </View>
  );
};

Spacing Usage

const SpacingExample = () => {
  const theme = useCustomTheme();

  return (
    <View
      style={{
        padding: theme.spacing.md,
        margin: theme.spacing.base,
        gap: theme.spacing.sm,
      }}>
      <Text>Content with themed spacing</Text>
    </View>
  );
};

Color Variants Usage

const ColorVariantsExample = () => {
  const theme = useCustomTheme();

  return (
    <View>
      {/* Primary button */}
      <View style={{backgroundColor: theme.color.buttonPrimary}}>
        <Text style={{color: theme.color.white}}>Primary Button</Text>
      </View>

      {/* Secondary button */}
      <View style={{backgroundColor: theme.color.buttonSecondary}}>
        <Text style={{color: theme.color.textBody}}>Secondary Button</Text>
      </View>

      {/* Theme accent variants */}
      <View style={{backgroundColor: theme.color.themeAccent}}>
        <Text>Theme Accent</Text>
      </View>
      <View style={{backgroundColor: theme.color.themeAccentD1}}>
        <Text>Darker Variant</Text>
      </View>
      <View style={{backgroundColor: theme.color.themeAccentL1}}>
        <Text>Lighter Variant</Text>
      </View>
    </View>
  );
};

Error Handling

Context Error

const MyComponent = () => {
  try {
    const theme = useCustomTheme();
    // Use theme
  } catch (error) {
    if (
      error.message === 'useCustomTheme must be used within a ThemeProvider'
    ) {
      // Handle missing provider
      return <Text>Theme not available</Text>;
    }
    throw error;
  }
};

Validation Error

const MyComponent = () => {
  try {
    const theme = useCustomTheme();

    // Validate specific properties
    if (!theme.color?.primaryColor) {
      return <Text>Primary color not available</Text>;
    }

    return <View style={{backgroundColor: theme.color.primaryColor}} />;
  } catch (error) {
    // Handle validation errors
    return <Text>Theme validation failed</Text>;
  }
};

๐ŸŽจ useThemedStyles Hook

Import

import {useThemedStyles} from '../shared/hooks/use-themed-styles';

Purpose

The useThemedStyles hook creates themed styles with automatic memoization, ensuring optimal performance by preventing unnecessary re-renders.

API Reference

Parameters

  • createStyles: (theme: CustomTheme) => T - Function that creates styles using theme data

Returns

  • T: Memoized styles object

Usage Examples

Basic Themed Styles

import {useThemedStyles} from '../shared/hooks/use-themed-styles';

const MyComponent = () => {
  const styles = useThemedStyles(theme => ({
    container: {
      backgroundColor: theme.color.bgColor,
      padding: theme.spacing.md,
      borderRadius: theme.radius.button,
    },
    text: {
      color: theme.color.textBody,
      fontSize: theme.typography.fontSize.base,
      fontWeight: theme.typography.fontWeight.regular,
      lineHeight: theme.typography.lineHeight.base,
    },
  }));

  return (
    <View style={styles.container}>
      <Text style={styles.text}>Themed Content</Text>
    </View>
  );
};

Complex Component Styles

const ComplexComponent = () => {
  const styles = useThemedStyles(theme => ({
    container: {
      backgroundColor: theme.color.pageBackground,
      padding: theme.spacing.base,
      margin: theme.spacing.md,
    },
    header: {
      backgroundColor: theme.color.headerBackground,
      padding: theme.spacing.md,
      borderBottomWidth: 1,
      borderBottomColor: theme.color.dividerStokes,
    },
    headerText: {
      color: theme.color.textHeading,
      fontSize: theme.typography.fontSize.lg,
      fontWeight: theme.typography.fontWeight.bold,
      lineHeight: theme.typography.lineHeight.lg,
    },
    content: {
      padding: theme.spacing.md,
    },
    bodyText: {
      color: theme.color.textBody,
      fontSize: theme.typography.fontSize.base,
      fontWeight: theme.typography.fontWeight.regular,
      lineHeight: theme.typography.lineHeight.base,
    },
    button: {
      backgroundColor: theme.color.buttonPrimary,
      padding: theme.spacing.sm,
      borderRadius: theme.radius.button,
      alignItems: 'center',
    },
    buttonText: {
      color: theme.color.white,
      fontSize: theme.typography.fontSize.md,
      fontWeight: theme.typography.fontWeight.medium,
    },
  }));

  return (
    <View style={styles.container}>
      <View style={styles.header}>
        <Text style={styles.headerText}>Header</Text>
      </View>
      <View style={styles.content}>
        <Text style={styles.bodyText}>Content goes here</Text>
        <TouchableOpacity style={styles.button}>
          <Text style={styles.buttonText}>Action</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
};

Conditional Styles

const ConditionalComponent = ({isActive, isError}) => {
  const styles = useThemedStyles(theme => ({
    container: {
      backgroundColor: isError
        ? theme.color.errorBackground
        : isActive
        ? theme.color.successBackground
        : theme.color.bgColor,
      padding: theme.spacing.md,
      borderRadius: theme.radius.button,
    },
    text: {
      color: isError
        ? theme.color.errorText
        : isActive
        ? theme.color.successText
        : theme.color.textBody,
      fontSize: theme.typography.fontSize.base,
      fontWeight: theme.typography.fontWeight.medium,
    },
  }));

  return (
    <View style={styles.container}>
      <Text style={styles.text}>
        {isError ? 'Error State' : isActive ? 'Active State' : 'Default State'}
      </Text>
    </View>
  );
};

Responsive Styles

import {Dimensions} from 'react-native';

const ResponsiveComponent = () => {
  const {width} = Dimensions.get('window');

  const styles = useThemedStyles(theme => ({
    container: {
      backgroundColor: theme.color.bgColor,
      padding: width > 768 ? theme.spacing.lg : theme.spacing.md,
      flexDirection: width > 768 ? 'row' : 'column',
    },
    text: {
      color: theme.color.textBody,
      fontSize:
        width > 768
          ? theme.typography.fontSize.lg
          : theme.typography.fontSize.base,
      lineHeight:
        width > 768
          ? theme.typography.lineHeight.lg
          : theme.typography.lineHeight.base,
    },
  }));

  return (
    <View style={styles.container}>
      <Text style={styles.text}>Responsive Content</Text>
    </View>
  );
};

๐Ÿ”ง Integration Examples

Complete Component with Both Hooks

import React from 'react';
import {View, Text, TouchableOpacity} from 'react-native';
import {useCustomTheme} from '../shared/hooks/use-custom-theme';
import {useThemedStyles} from '../shared/hooks/use-themed-styles';

const ThemedComponent = ({title, onPress, variant = 'primary'}) => {
  const theme = useCustomTheme();

  const styles = useThemedStyles(theme => ({
    container: {
      backgroundColor: theme.color.bgColor,
      padding: theme.spacing.md,
      borderRadius: theme.radius.button,
      borderWidth: 1,
      borderColor: theme.color.dividerStokes,
    },
    title: {
      color: theme.color.textHeading,
      fontSize: theme.typography.fontSize.lg,
      fontWeight: theme.typography.fontWeight.bold,
      lineHeight: theme.typography.lineHeight.lg,
      marginBottom: theme.spacing.sm,
    },
    button: {
      backgroundColor:
        variant === 'primary'
          ? theme.color.buttonPrimary
          : theme.color.buttonSecondary,
      padding: theme.spacing.sm,
      borderRadius: theme.radius.button,
      alignItems: 'center',
    },
    buttonText: {
      color: variant === 'primary' ? theme.color.white : theme.color.textBody,
      fontSize: theme.typography.fontSize.md,
      fontWeight: theme.typography.fontWeight.medium,
    },
  }));

  return (
    <View style={styles.container}>
      <Text style={styles.title}>{title}</Text>
      <TouchableOpacity style={styles.button} onPress={onPress}>
        <Text style={styles.buttonText}>Action</Text>
      </TouchableOpacity>
    </View>
  );
};

Form Component with Theme

const ThemedForm = () => {
  const theme = useCustomTheme();

  const styles = useThemedStyles(theme => ({
    form: {
      backgroundColor: theme.color.pageBackground,
      padding: theme.spacing.base,
    },
    input: {
      backgroundColor: theme.color.white,
      borderWidth: 1,
      borderColor: theme.color.dividerStokes,
      borderRadius: theme.radius.button,
      padding: theme.spacing.sm,
      marginBottom: theme.spacing.md,
      fontSize: theme.typography.fontSize.base,
      color: theme.color.textBody,
    },
    label: {
      color: theme.color.textLabel,
      fontSize: theme.typography.fontSize.sm,
      fontWeight: theme.typography.fontWeight.medium,
      marginBottom: theme.spacing.xs,
    },
    submitButton: {
      backgroundColor: theme.color.buttonPrimary,
      padding: theme.spacing.md,
      borderRadius: theme.radius.button,
      alignItems: 'center',
    },
    submitButtonText: {
      color: theme.color.white,
      fontSize: theme.typography.fontSize.md,
      fontWeight: theme.typography.fontWeight.bold,
    },
  }));

  return (
    <View style={styles.form}>
      <Text style={styles.label}>Email</Text>
      <TextInput style={styles.input} placeholder="Enter email" />

      <Text style={styles.label}>Password</Text>
      <TextInput
        style={styles.input}
        placeholder="Enter password"
        secureTextEntry
      />

      <TouchableOpacity style={styles.submitButton}>
        <Text style={styles.submitButtonText}>Submit</Text>
      </TouchableOpacity>
    </View>
  );
};

๐Ÿ› Troubleshooting

Common Issues

1. Hook Used Outside Provider

// โŒ This will throw an error
const MyComponent = () => {
  const theme = useCustomTheme(); // Error: must be used within ThemeProvider
  return <View />;
};

// โœ… Wrap with ThemeProvider
const App = () => (
  <ThemeProvider>
    <MyComponent />
  </ThemeProvider>
);

2. Missing Theme Properties

// โŒ This might fail if theme is incomplete
const MyComponent = () => {
  const theme = useCustomTheme();
  return <View style={{backgroundColor: theme.color.primaryColor}} />;
};

// โœ… Add validation
const MyComponent = () => {
  const theme = useCustomTheme();

  if (!theme.color?.primaryColor) {
    return <View style={{backgroundColor: '#000'}} />;
  }

  return <View style={{backgroundColor: theme.color.primaryColor}} />;
};

3. Performance Issues with useThemedStyles

// โŒ This will cause unnecessary re-renders
const MyComponent = () => {
  const styles = useThemedStyles(theme => ({
    container: {
      backgroundColor: theme.color.bgColor,
      // This function is recreated on every render
    },
  }));
  return <View style={styles.container} />;
};

// โœ… Move function outside component or use useCallback
const createStyles = theme => ({
  container: {
    backgroundColor: theme.color.bgColor,
  },
});

const MyComponent = () => {
  const styles = useThemedStyles(createStyles);
  return <View style={styles.container} />;
};

Debug Tools

// Enable theme debugging
const debugTheme = () => {
  const theme = useCustomTheme();

  console.log('๐ŸŽจ Theme Debug:', {
    colorKeys: Object.keys(theme.color),
    typographyKeys: Object.keys(theme.typography),
    spacingKeys: Object.keys(theme.spacing),
    hasRadius: !!theme.radius,
    hasLayout: !!theme.layout,
  });
};

// Use in development
if (__DEV__) {
  debugTheme();
}

๐Ÿš€ Best Practices

1. Performance Optimization

  • Use useThemedStyles for complex style objects
  • Memoize style creation functions
  • Avoid inline styles when possible

2. Type Safety

  • Always validate theme properties before use
  • Use TypeScript for better IntelliSense
  • Handle missing theme properties gracefully

3. Code Organization

  • Keep style functions simple and focused
  • Use descriptive style names
  • Group related styles together

4. Error Handling

  • Provide fallback values for missing theme properties
  • Handle theme loading states
  • Log errors for debugging

๐Ÿ”ฎ Future Enhancements

  1. Custom Theme Hooks: Specialized hooks for specific use cases
  2. Theme Validation: Runtime theme validation
  3. Performance Monitoring: Theme usage analytics
  4. Advanced Memoization: More sophisticated caching strategies

This documentation covers the main theme hooks. For more specific use cases or advanced patterns, refer to the other theme documentation sections.