Skip to main content

Overview

Open Mushaf Native provides a comprehensive set of custom React hooks that handle everything from Quran metadata loading to gesture handling and theme management.

Data Management Hooks

useQuranMetadata

Loads Quran metadata including surah data, hizb data, aya coordinates, and Quran text based on the selected riwaya (Hafs or Warsh).
function useQuranMetadata(): QuranMetadata
return
QuranMetadata
thumnData
Thumn[]
Array of thumn (eighth of a hizb) metadata
hizbData
Hizb[]
Array of hizb (half juz) metadata
surahData
Surah[]
Array of surah metadata including names and starting pages
ayaData
Page[]
Array of aya coordinates for each page
specsData
Specs
Mushaf specifications (dimensions, margins, etc.)
chapterData
Chapter[]
Chapter metadata
quranData
QuranText[]
Complete Quran text data
isLoading
boolean
Whether metadata is currently loading
error
string | null
Error message if loading failed
Usage Example:
import useQuranMetadata from '@/hooks/useQuranMetadata';

function QuranViewer() {
  const { surahData, ayaData, isLoading, error } = useQuranMetadata();
  
  if (isLoading) return <LoadingSpinner />;
  if (error) return <ErrorMessage>{error}</ErrorMessage>;
  
  return <MushafView surahs={surahData} ayas={ayaData} />;
}

useQuranSearch

Performs advanced Quran search with support for exact text, lemma, root, and fuzzy matching using the quran-search-engine package.
function useQuranSearch({
  quranData,
  morphologyData,
  wordMap,
  query,
  advancedOptions,
  fuseInstance,
  page,
  limit
}): SearchResults
quranData
QuranText[] | null
required
Quran text data array
morphologyData
MorphologyAya[]
required
Morphology data for advanced search
wordMap
WordMap
required
Word mapping for root and lemma search
query
string
required
Search query in Arabic
advancedOptions
AdvancedOptions
required
Search options:
  • lemma: Enable lemma-based search
  • root: Enable root-based search
  • fuzzy: Enable fuzzy matching
page
number
required
Current page number for pagination
limit
number
required
Number of results per page
return
SearchResults
pageResults
QuranText[]
Search results for the current page
counts
Counts
Result counts by search type:
  • simple: Exact text matches
  • lemma: Lemma matches
  • root: Root matches
  • fuzzy: Fuzzy matches
  • total: Total results
getPositiveTokens
function
Function to get highlighted tokens for a verse
Usage Example:
import useQuranSearch from '@/hooks/useQuranSearch';

function SearchPage() {
  const { pageResults, counts } = useQuranSearch({
    quranData,
    morphologyData,
    wordMap,
    query: 'الله',
    advancedOptions: { lemma: true, root: false, fuzzy: false },
    fuseInstance: null,
    page: 1,
    limit: 10
  });
  
  return (
    <div>
      <p>Found {counts.total} results</p>
      {pageResults.map(result => (
        <SearchResult key={result.gid} verse={result} />
      ))}
    </div>
  );
}

useTafseerContent

Retrieves and formats Tafseer (exegesis) text for a specific aya and surah.
function useTafseerContent({
  tafseerData,
  surah,
  aya
}): string
tafseerData
TafseerAya[] | null
required
Array of Tafseer data or null if not loaded
surah
number
required
Surah number (1-114)
aya
number
required
Aya number within the surah
Returns: HTML string containing the Tafseer text, or a default message if not found. Usage Example:
import { useTafseerContent } from '@/hooks/useTafseerContent';

function TafseerView({ surah, aya, tafseerData }) {
  const tafseerHTML = useTafseerContent({ tafseerData, surah, aya });
  
  return <WebView html={tafseerHTML} />;
}

hasNoTafseerContent

Checks if Tafseer text is available for a specific aya.
function hasNoTafseerContent({
  tafseerData,
  surah,
  aya
}): boolean
tafseerData
TafseerAya[] | null
required
Array of Tafseer data or null if not loaded
surah
number
required
Surah number (1-114)
aya
number
required
Aya number within the surah
Returns: true if no Tafseer content is found or if the text is empty, false otherwise. Usage Example:
import { hasNoTafseerContent } from '@/hooks/useTafseerContent';

function TafseerButton({ surah, aya, tafseerData }) {
  const noTafseer = hasNoTafseerContent({ tafseerData, surah, aya });
  
  return (
    <Button disabled={noTafseer}>
      {noTafseer ? 'No Tafseer Available' : 'View Tafseer'}
    </Button>
  );
}

Page & Navigation Hooks

useCurrentPage

Manages the current Quran page state, syncing between URL parameters and persisted storage.
function useCurrentPage(): CurrentPageState
return
CurrentPageState
currentPage
number
The active page number (may be temporary or saved)
currentSavedPage
number
The permanently saved page number
setCurrentPage
(page: number) => void
Function to update the current page
isTemporaryNavigation
boolean
Whether viewing a temporary page different from saved position
Usage Example:
import useCurrentPage from '@/hooks/useCurrentPage';

function PageNavigator() {
  const { currentPage, setCurrentPage, isTemporaryNavigation } = useCurrentPage();
  
  return (
    <div>
      <p>Page {currentPage} {isTemporaryNavigation && '(preview)'}</p>
      <button onClick={() => setCurrentPage(currentPage + 1)}>Next</button>
    </div>
  );
}

usePageOverlay

Generates interactive overlay elements for aya selection on a Mushaf page.
function usePageOverlay({
  index,
  dimensions
}): PageOverlayResult
index
number
required
Page index (0-based)
dimensions
object
required
Page dimensions:
  • customPageWidth: Width of the page in pixels
  • customPageHeight: Height of the page in pixels
return
PageOverlayResult
overlay
OverlayElement[]
Array of overlay elements with:
  • x: X coordinate
  • y: Y coordinate
  • width: Width of the overlay
  • aya: Aya number
  • surah: Surah number
lineHeight
number
Calculated line height for the page
Usage Example:
import usePageOverlay from '@/hooks/usePageOverLay';

function InteractivePage({ pageIndex, width, height }) {
  const { overlay } = usePageOverlay({
    index: pageIndex,
    dimensions: { customPageWidth: width, customPageHeight: height }
  });
  
  return overlay.map((element, i) => (
    <TouchableOverlay
      key={i}
      x={element.x}
      y={element.y}
      width={element.width}
      onPress={() => handleAyaPress(element.surah, element.aya)}
    />
  ));
}

Image & Asset Hooks

useImagesArray

Loads the Mushaf page image asset for the current page and riwaya.
function useImagesArray(): ImageAssetResult
return
ImageAssetResult
asset
Asset | null
Expo Asset object for the current page image
isLoading
boolean
Whether the asset is currently loading
error
string | null
Error message if loading failed
Usage Example:
import useImagesArray from '@/hooks/useImagesArray';

function MushafPage() {
  const { asset, isLoading, error } = useImagesArray();
  
  if (isLoading) return <LoadingSpinner />;
  if (error) return <ErrorMessage>{error}</ErrorMessage>;
  
  return <Image source={{ uri: asset.uri }} />;
}

useImagePreloader

Preloads adjacent Mushaf pages for smoother navigation.
function useImagePreloader(currentPage: number): null
currentPage
number
required
The current page number
Behavior:
  • Preloads current page, previous 1 page, and next 2 pages
  • Automatically manages cache to prevent memory issues
  • Returns null (side-effects only)
Usage Example:
import useImagePreloader from '@/hooks/useImagePreloader';

function MushafViewer() {
  const { currentPage } = useCurrentPage();
  useImagePreloader(currentPage); // Preloads adjacent pages
  
  return <PageView page={currentPage} />;
}

Gesture & Interaction Hooks

usePanGestureHandler

Handles pan gestures for page navigation with smooth animations.
function usePanGestureHandler(
  currentPage: number,
  onPageChange: (page: number) => void,
  maxPages: number
): GestureHandlerResult
currentPage
number
required
Current page number
onPageChange
(page: number) => void
required
Callback function when page changes
maxPages
number
required
Maximum number of pages
return
GestureHandlerResult
translateX
SharedValue<number>
Reanimated shared value for X translation
panGestureHandler
Gesture
React Native Gesture Handler pan gesture
Usage Example:
import { usePanGestureHandler } from '@/hooks/usePanGestureHandler';
import { GestureDetector } from 'react-native-gesture-handler';
import Animated, { useAnimatedStyle } from 'react-native-reanimated';

function SwipeablePage() {
  const { translateX, panGestureHandler } = usePanGestureHandler(
    currentPage,
    (page) => setCurrentPage(page),
    604
  );
  
  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ translateX: translateX.value }]
  }));
  
  return (
    <GestureDetector gesture={panGestureHandler}>
      <Animated.View style={animatedStyle}>
        <PageContent />
      </Animated.View>
    </GestureDetector>
  );
}

UI & Theme Hooks

useColors

Provides theme-aware color values based on the current color scheme.
function useColors(): ColorScheme
return
ColorScheme
backgroundColor
string
Background color for the current theme
tintColor
string
Tint color for UI elements
textColor
string
Primary text color
iconColor
string
Icon color
primaryColor
string
Primary brand color
primaryLightColor
string
Light variant of primary color
secondaryColor
string
Secondary color
cardColor
string
Card background color
dangerColor
string
Danger/error color
dangerLightColor
string
Light variant of danger color
ivoryColor
string
Ivory color for special backgrounds
directColor
string
Highlight color for exact search matches
Highlight color for related matches (lemma/root)
fuzzyColor
string
Highlight color for fuzzy matches
Usage Example:
import { useColors } from '@/hooks/useColors';

function ThemedButton() {
  const { primaryColor, textColor } = useColors();
  
  return (
    <View style={{ backgroundColor: primaryColor }}>
      <Text style={{ color: textColor }}>Submit</Text>
    </View>
  );
}

useThemeColor

Retrieves a specific theme color with optional overrides.
function useThemeColor(
  props: { light?: string; dark?: string },
  colorName: keyof typeof Colors.light & keyof typeof Colors.dark
): string
props
object
required
Optional color overrides:
  • light: Override for light mode
  • dark: Override for dark mode
colorName
ColorName
required
Name of the color from the Colors constants
Returns: The color value as a string. Usage Example:
import { useThemeColor } from '@/hooks/useThemeColor';

function CustomComponent({ lightColor, darkColor }) {
  const backgroundColor = useThemeColor(
    { light: lightColor, dark: darkColor },
    'background'
  );
  
  return <View style={{ backgroundColor }} />;
}

useNotificationStyles

Provides predefined styles for different notification types.
function useNotificationStyles(): NotificationStyles
return
NotificationStyles
neutral
StyleObject
Neutral notification style (gray)
success
StyleObject
Success notification style (green)
error
StyleObject
Error notification style (red)
info
StyleObject
Info notification style (blue)
Each style object contains:
  • borderColor: Border color
  • backgroundColor: Background color
  • color: Text color
Usage Example:
import useNotificationStyles from '@/hooks/useNotificationStyles';

function Notification({ type, message }) {
  const styles = useNotificationStyles();
  const style = styles[type];
  
  return (
    <View style={{
      borderColor: style.borderColor,
      backgroundColor: style.backgroundColor
    }}>
      <Text style={{ color: style.color }}>{message}</Text>
    </View>
  );
}

Platform & Device Hooks

useOrientation

Detects the current device orientation.
function useOrientation(): OrientationResult
return
OrientationResult
isLandscape
boolean
True if device is in landscape mode
Usage Example:
import useOrientation from '@/hooks/useOrientation';

function ResponsiveLayout() {
  const { isLandscape } = useOrientation();
  
  return (
    <View style={{ flexDirection: isLandscape ? 'row' : 'column' }}>
      <Content />
    </View>
  );
}

useColorScheme

Re-export of React Native’s useColorScheme hook.
function useColorScheme(): 'light' | 'dark' | null
Returns: Current color scheme preference: 'light', 'dark', or null if not available. Usage Example:
import { useColorScheme } from '@/hooks/useColorScheme';

function ThemedIcon() {
  const colorScheme = useColorScheme();
  const iconColor = colorScheme === 'dark' ? '#fff' : '#000';
  
  return <Icon color={iconColor} />;
}

useUpdateAndroidWidget

Updates the Android home screen widget with current reading progress.
function useUpdateAndroidWidget(): WidgetUpdater
return
WidgetUpdater
updateAndroidWidget
() => Promise<void>
Async function to update the widget
Behavior:
  • Updates widget with current page, surah, hizb, and daily progress
  • Validates daily tracker data
  • Handles both Hafs and Warsh riwaya metadata
  • Android-only (no-op on other platforms)
Usage Example:
import { useUpdateAndroidWidget } from '@/hooks/useUpdateAndroidWidget';

function PageNavigator() {
  const { updateAndroidWidget } = useUpdateAndroidWidget();
  
  const handlePageChange = async (page: number) => {
    setCurrentPage(page);
    await updateAndroidWidget();
  };
  
  return <Navigation onPageChange={handlePageChange} />;
}

Utility Hooks

useDebounce

Debounces a function call to prevent excessive executions.
function useDebounce<T extends (...args: any[]) => void>(
  fn: T,
  delay: number
): T
fn
function
required
The function to debounce
delay
number
required
Delay in milliseconds
Returns: Debounced version of the function. Usage Example:
import useDebounce from '@/hooks/useDebounce';

function SearchInput() {
  const [query, setQuery] = useState('');
  
  const performSearch = (searchQuery: string) => {
    // Execute search
  };
  
  const debouncedSearch = useDebounce(performSearch, 500);
  
  return (
    <input
      onChange={(e) => {
        setQuery(e.target.value);
        debouncedSearch(e.target.value);
      }}
    />
  );
}

Build docs developers (and LLMs) love