npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@crystin001/theme-settings-lib

v1.4.0

Published

Reusable theme and settings library for mobile apps

Readme

Theme & Settings Library

A reusable library for theme management, settings, and internationalization that can be shared across multiple React Native applications.

Features

  • 🎨 Multiple Theme Families - 9 theme families with light and dark variants, plus 3 user-customizable slots
  • 🌍 Built-in Localization - Settings UI ships translated in 6 languages (en-US, es-ES, ja-JP, pt-BR, zh-CN, zh-TW); apps choose which ones to expose
  • 💾 Persistent Settings - Theme, language, custom themes, recent swatches and background pattern preferences saved automatically
  • 🟦 Background Patterns - SVG grid/stripes/zigzag overlay with thickness, spacing, opacity, rotation and swap-colors toggle
  • 🧩 Drop-in Settings UI - LanguageSection, ThemeSection and AboutSection components you can compose into your settings screen
  • 🎨 Custom Theme Builder - In-app HSV color picker that generates accessible custom themes from a few seed colors
  • Accessibility - WCAG-compliant contrast utilities and theme generator
  • 🔧 Type-Safe - Full TypeScript support with declaration files

Installation

Option A: Git Repository (Recommended)

Add to your package.json:

{
  "dependencies": {
    "@crystin001/theme-settings-lib": "git+https://github.com/trial-and-code/theme-settings-lib.git"
  }
}

Then run npm install. The library will automatically build during installation.

Note: The library requires TypeScript to build. It will be installed automatically as a dev dependency and the build will run during npm install.

To install a specific version or branch:

{
  "dependencies": {
    "@crystin001/theme-settings-lib": "git+https://github.com/trial-and-code/theme-settings-lib.git#v1.0.0"
  }
}

Option B: Local Package (Development)

For local development, you can use a file path to link the library directly:

{
  "dependencies": {
    "@crystin001/theme-settings-lib": "file:../theme-settings-lib"
  }
}

Note: Make sure to run npm run build in the library directory after making changes.

Option C: npm Package (Future)

npm install @crystin001/theme-settings-lib

Usage

1. Wrap Your App with SettingsProvider

Wrap your root component with SettingsProvider to enable theme and settings management. Pass your app's available language list:

// app/_layout.tsx or App.tsx
import {
  SettingsProvider,
  BackgroundPatternProvider,
  type LanguageOption,
} from '@crystin001/theme-settings-lib';
import { Stack } from 'expo-router';

const MY_LANGUAGES: LanguageOption[] = [
  { code: 'en-US', name: 'English (US)', available: true },
  { code: 'es-ES', name: 'Español (ES)', available: true },
  { code: 'ja-JP', name: '日本語 (JP)', available: false, comingSoonLabel: '近日公開' },
];

export default function RootLayout() {
  return (
    <SettingsProvider availableLanguages={MY_LANGUAGES}>
      <BackgroundPatternProvider>
        <Stack>
          {/* Your app screens */}
        </Stack>
      </BackgroundPatternProvider>
    </SettingsProvider>
  );
}

The lib ships its own translations for all settings.*, common.* and errors.* keys it consumes (currently in en-US, es-ES, ja-JP, pt-BR, zh-CN and zh-TW). Apps just need to (a) decide which language codes appear in the menu via availableLanguages, and (b) i18n.addResourceBundle(...) their own app-specific keys. See Localization below.

2. Use Theme Hooks in Your Components

Access theme colors and settings in your components:

import { View, Text, Button } from 'react-native';
import { useTheme, useSettings } from '@crystin001/theme-settings-lib';

function MyComponent() {
  const colors = useTheme();
  const { setThemeFamily } = useSettings();

  return (
    <View style={{ backgroundColor: colors.background }}>
      <Text style={{ color: colors.text }}>Hello World</Text>
      <Button 
        onPress={() => setThemeFamily('neon-surf')} 
        title="Change to Neon Surf" 
      />
    </View>
  );
}

3. Use Translations

Access translations using the useTranslation hook:

import { Text } from 'react-native';
import { useTranslation } from '@crystin001/theme-settings-lib';

function MyComponent() {
  const { t } = useTranslation();

  return (
    <Text>{t('common.welcome')}</Text>
  );
}

4. Get Specific Theme Colors

Use useThemeColor to get specific colors from the current theme:

import { View, Text } from 'react-native';
import { useThemeColor } from '@crystin001/theme-settings-lib';

function MyComponent() {
  const backgroundColor = useThemeColor({}, 'background');
  const textColor = useThemeColor({}, 'text');
  const primaryColor = useThemeColor({}, 'primary');

  return (
    <View style={{ backgroundColor }}>
      <Text style={{ color: textColor }}>Primary: {primaryColor}</Text>
    </View>
  );
}

5. Drop-in Settings UI Sections

The library ships three composable section components for settings screens. Each is optional and accepts a render-prop Icon so your app's icon set (peak-you's IconSymbol, Ionicons, etc.) is used:

import { useState } from 'react';
import { ScrollView } from 'react-native';
import {
  LanguageSection,
  ThemeSection,
  AboutSection,
} from '@crystin001/theme-settings-lib';
import { IconSymbol } from '@/components/ui/icon-symbol';
import { ThemedText } from '@/components/themed-text';
import appIcon from '@/assets/icon.png';

export function SettingsScreen() {
  const [open, setOpen] = useState({ theme: false, language: false, about: false });
  const toggle = (k: keyof typeof open) => setOpen(p => ({ ...p, [k]: !p[k] }));

  return (
    <ScrollView>
      <ThemeSection
        expanded={open.theme}
        onToggle={() => toggle('theme')}
        Icon={IconSymbol}
        Text={ThemedText}
      />
      <LanguageSection
        expanded={open.language}
        onToggle={() => toggle('language')}
        Icon={IconSymbol}
        Text={ThemedText}
      />
      <AboutSection
        expanded={open.about}
        onToggle={() => toggle('about')}
        Icon={IconSymbol}
        Text={ThemedText}
        appName="My App"
        appVersion="1.0.0 (1)"
        appIcon={appIcon}
        description="Short marketing description."
        dataPrivacyText="Your data stays on your device."
        supportEmail="[email protected]"
        privacyPolicyUrl="https://example.com/privacy"
      />
    </ScrollView>
  );
}

Notes:

  • Icon is optional. When omitted, sections fall back to plain text glyphs.
  • Text is optional. When omitted, plain RN Text styled with the theme color is used.
  • iconNames lets you remap default SF-Symbol-style names to your icon set.
  • ThemeSection automatically renders the background pattern controls when wrapped in a BackgroundPatternProvider. Pass showBackgroundPattern={false} to hide them.

6. Built-in Localization

The library ships translations for the strings rendered by its UI sections (background pattern controls, custom theme labels, about / language headers, etc.) in:

| Code | Language | | ------- | ----------------- | | en-US | English (US) | | es-ES | Español (España) | | ja-JP | 日本語 | | pt-BR | Português (BR) | | zh-CN | 简体中文 | | zh-TW | 繁體中文 |

These are loaded automatically when you import anything from @crystin001/theme-settings-lib. You don't have to ship them yourself.

import { LIB_LOCALES, libResources } from '@crystin001/theme-settings-lib';

// LIB_LOCALES is the list of BCP-47 codes the lib has translations for.
// Use it to drive your `availableLanguages` if you want to expose every
// language the lib supports out of the box:
const ALL_LIB_LANGUAGES = LIB_LOCALES.map((code) => ({ code, name: code }));

If your app already manages its own i18next instance, you can merge the lib's bundles by re-using libResources directly.

Add app-specific keys

Apps still own translations for their own UI. Add them with addResourceBundle using deep = true, overwrite = true so they merge with — rather than replace — the lib's defaults:

import { i18n } from '@crystin001/theme-settings-lib';

i18n.addResourceBundle(
  'en-US',
  'translation',
  {
    myFeature: { title: 'My Feature', description: 'This is my feature' },
    // overrides for any lib key are also fine here
    settings: { about: 'About this app' },
  },
  true, // deep merge
  true  // overwrite individual keys when they collide
);

Adding more languages

Future minor releases will add more entries to LIB_LOCALES. Apps don't need any code changes to pick those up — they just become available the next time you upgrade the package.

7. Complete Example: Integration with React Navigation

Here's a complete example showing integration with React Navigation:

// app/_layout.tsx
import { Stack } from 'expo-router';
import { StatusBar } from 'expo-status-bar';
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
import { SettingsProvider, useSettings } from '@crystin001/theme-settings-lib';

function RootLayoutNav() {
  const { currentTheme } = useSettings();
  const isDarkTheme = currentTheme.endsWith('-dark');

  return (
    <ThemeProvider value={isDarkTheme ? DarkTheme : DefaultTheme}>
      <Stack>
        <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
      </Stack>
      <StatusBar style={isDarkTheme ? 'light' : 'dark'} />
    </ThemeProvider>
  );
}

export default function RootLayout() {
  return (
    <SettingsProvider>
      <RootLayoutNav />
    </SettingsProvider>
  );
}

Available Theme Families

  • System - Follows device theme preference (default)
  • Neon Surf - Vibrant neon colors (hot pink, cyan, yellow, orange)
  • Pink & Purple - Soft purple and pink tones
  • Pastel - Gentle pastel colors
  • GitHub - GitHub-inspired theme
  • High Contrast - Maximum contrast for accessibility
  • Solarized - Solarized color scheme
  • Dark Plus - Dark theme with blue accents

Each theme family has both light and dark variants that automatically switch based on device settings.

API Reference

Hooks

useTheme()

Returns all colors from the current theme.

const colors = useTheme();
// Returns: { text, background, tint, icon, ... }

useThemeColor(props?, colorName?)

Get a specific color from the current theme.

const backgroundColor = useThemeColor({}, 'background');
const textColor = useThemeColor({ light: '#000', dark: '#fff' }, 'text');

useSettings()

Access theme and language settings.

const {
  selectedThemeFamily,
  currentTheme,
  setThemeFamily,
  language,
  setLanguage,
  availableThemeFamilies,
  availableLanguages
} = useSettings();

useTranslation()

Get the translation function.

const { t } = useTranslation();
const welcomeText = t('common.welcome');

Settings Context

The useSettings() hook returns:

  • selectedThemeFamily - Currently selected theme family (e.g., 'neon-surf')
  • currentTheme - Effective theme being used (includes variant, e.g., 'neon-surf-light')
  • setThemeFamily(family) - Change theme family
  • language - Current language code (e.g., 'en-US')
  • setLanguage(lang) - Change language
  • availableThemeFamilies - Array of all available theme families with metadata
  • availableLanguages - Array of all available languages

Background Pattern

BackgroundPatternProvider

Wraps your app to persist user-chosen background pattern + slider settings.

<BackgroundPatternProvider defaultPattern="grid">
  <App />
</BackgroundPatternProvider>

useBackgroundPattern()

const {
  selectedPattern,        // 'none' | 'grid' | 'stripes' | 'zigzag'
  setPattern,
  settings,               // { lineThickness, spacing, opacity, rotation }
  setLineThickness, setSpacing, setOpacity, setRotation,
  patternOptions,         // [{ id, label }]
  isLoaded,
} = useBackgroundPattern();

<BackgroundPatternOverlay />

Renders the pattern as an absolutely-positioned SVG overlay. Typically used inside a themed background view:

<View style={{ backgroundColor }}>
  {isLoaded && (
    <BackgroundPatternOverlay
      pattern={selectedPattern}
      settings={settings}
      color={colors.accent2}
    />
  )}
  {children}
</View>

Settings UI Sections

  • <LanguageSection /> — collapsible language picker driven by availableLanguages.

  • <ThemeSection /> — theme family picker plus background pattern controls (when a BackgroundPatternProvider is mounted).

  • <AboutSection /> — collapsible "About" panel with app icon, version, support email, privacy policy and (optional) "Rate the app" links.

    Pass appStoreId (iOS App Store numeric ID) and/or playStoreId (Android package name) to add a "Rate the app" row that opens the right store deep-link per platform. Pass onRateApp for fully custom logic (e.g. native StoreKit review prompt).

All three accept expanded, onToggle, optional Icon (e.g. IconSymbol), optional Text (e.g. your ThemedText) and iconNames overrides. See the Usage section above for an example.

Color Utilities

getContrastRatio(color1, color2)

Calculate the contrast ratio between two colors (returns 1-21).

import { getContrastRatio } from '@crystin001/theme-settings-lib';

const ratio = getContrastRatio('#000000', '#FFFFFF'); // Returns ~21

getContrastTextColor(backgroundColor, lightColor?, darkColor?, minContrast?)

Get a readable text color for a given background.

import { getContrastTextColor } from '@crystin001/theme-settings-lib';

const textColor = getContrastTextColor('#000000'); // Returns '#FFFFFF'

meetsContrastRequirement(foreground, background, level?)

Check if a color combination meets WCAG contrast requirements.

import { meetsContrastRequirement } from '@crystin001/theme-settings-lib';

const isAccessible = meetsContrastRequirement('#000000', '#FFFFFF', 'AA'); // Returns true

ensureContrast(foreground, background, level?)

Ensure a color combination has readable contrast, adjusting if needed.

import { ensureContrast } from '@crystin001/theme-settings-lib';

const readableColor = ensureContrast('#888888', '#FFFFFF', 'AA');

Contributing / Development

For information about developing the library, including:

  • Building the library
  • Running the example app for visual theme development
  • Project structure
  • Development workflow

See SETUP.md in the repository.

Versioning

The library follows Semantic Versioning:

  • Major (x.0.0) - Breaking API changes
  • Minor (0.x.0) - New themes, features, or languages
  • Patch (0.0.x) - Bug fixes and theme adjustments

Troubleshooting

"Unable to resolve path to module" Error

If you get an error like Unable to resolve path to module '@crystin001/theme-settings-lib', try these steps:

  1. The library should build automatically during installation. If you're using a local file path and made changes, rebuild:

    cd theme-settings-lib
    npm run build

    Note: When installing from git, the library builds automatically via the prepare script. You only need to manually build if using a local file: path and making changes.

  2. Clear Metro cache and restart:

    # In your app directory
    npx react-native start --reset-cache
    # Or for Expo:
    npx expo start --clear
  3. Reinstall dependencies:

    # In your app directory
    rm -rf node_modules
    npm install
    # Or if using yarn:
    rm -rf node_modules
    yarn install
  4. If using local file path, verify the path is correct:

    {
      "dependencies": {
        "@crystin001/theme-settings-lib": "file:../theme-settings-lib"
      }
    }

    Make sure the relative path from your app's package.json to the library is correct.

  5. For Expo projects, you may need to restart the development server completely:

    # Stop the server, then:
    npx expo start --clear
  6. Check that dist/ folder exists and contains compiled files: The library must be built before it can be used. Run npm run build in the library directory.

Peer Dependencies

This library requires the following peer dependencies (installed by your app):

  • react - React library
  • react-native - React Native framework
  • i18next - Internationalization framework
  • react-i18next - React bindings for i18next
  • expo-localization - Expo localization utilities
  • @react-native-async-storage/async-storage - Async storage for persistence
  • color (optional) - Color manipulation library
  • react-native-svg (optional) - Required if you render BackgroundPatternOverlay or use ThemeSection's background pattern controls
  • @react-native-community/slider (optional) - Required for the sliders in ThemeSection's background pattern controls

License

MIT

Repository

https://github.com/trial-and-code/theme-settings-lib


For developers: See SETUP.md for development setup, building the library, and running the example app.