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
Loads Quran metadata including surah data, hizb data, aya coordinates, and Quran text based on the selected riwaya (Hafs or Warsh).
function useQuranMetadata(): QuranMetadata
Array of thumn (eighth of a hizb) metadata
Array of hizb (half juz) metadata
Array of surah metadata including names and starting pages
Array of aya coordinates for each page
Mushaf specifications (dimensions, margins, etc.)
Whether metadata is currently loading
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
Morphology data for advanced search
Word mapping for root and lemma search
Search options:
lemma: Enable lemma-based search
root: Enable root-based search
fuzzy: Enable fuzzy matching
Current page number for pagination
Number of results per page
Search results for the current page
Result counts by search type:
simple: Exact text matches
lemma: Lemma matches
root: Root matches
fuzzy: Fuzzy matches
total: Total results
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
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
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
The active page number (may be temporary or saved)
The permanently saved page number
Function to update the current page
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
Page dimensions:
customPageWidth: Width of the page in pixels
customPageHeight: Height of the page in pixels
Array of overlay elements with:
x: X coordinate
y: Y coordinate
width: Width of the overlay
aya: Aya number
surah: Surah 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
Expo Asset object for the current page image
Whether the asset is currently loading
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
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
onPageChange
(page: number) => void
required
Callback function when page changes
Reanimated shared value for X translation
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
Background color for the current theme
Tint color for UI elements
Light variant of primary color
Light variant of danger color
Ivory color for special backgrounds
Highlight color for exact search matches
Highlight color for related matches (lemma/root)
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
Optional color overrides:
light: Override for light mode
dark: Override for dark mode
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
Neutral notification style (gray)
Success notification style (green)
Error notification style (red)
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>
);
}
useOrientation
Detects the current device orientation.
function useOrientation(): OrientationResult
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} />;
}
Updates the Android home screen widget with current reading progress.
function useUpdateAndroidWidget(): WidgetUpdater
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
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);
}}
/>
);
}