React Native for Web is a comprehensive compatibility library that enables React Native components and APIs to run seamlessly on web browsers using React DOM.
—
React Native's system integration APIs adapted for web, providing access to device capabilities, clipboard operations, URL handling, sharing functionality, and internationalization support.
The JavaScript entry point for running React Native applications on the web. AppRegistry provides the core application lifecycle management for registering and running React Native Web apps.
const AppRegistry: {
registerComponent: (appKey: string, componentProvider: () => React.ComponentType) => string;
runApplication: (appKey: string, appParameters: AppParameters) => void;
getAppKeys: () => string[];
getApplication: (appKey: string, appParameters?: AppParameters) => {element: React.ReactNode, getStyleElement: (any) => React.ReactNode};
registerConfig: (config: AppConfig[]) => void;
registerRunnable: (appKey: string, run: Function) => string;
unmountApplicationComponentAtRootTag: (rootTag: Element) => void;
setComponentProviderInstrumentationHook: (hook: ComponentProviderInstrumentationHook) => void;
setWrapperComponentProvider: (provider: WrapperComponentProvider) => void;
};Web Implementation: AppRegistry on web manages the mounting and lifecycle of React applications, providing compatibility with React Native's application registration pattern while integrating with web DOM elements.
Registers a React component as a runnable application that can be started with runApplication.
AppRegistry.registerComponent(appKey: string, componentProvider: () => React.ComponentType): stringRuns a registered application by mounting it to a DOM element. This is the primary method for starting React Native Web applications.
AppRegistry.runApplication(appKey: string, appParameters: AppParameters): voidUsage:
import React from "react";
import { AppRegistry, View, Text, StyleSheet } from "react-native-web";
// Define your app component
const App = () => (
<View style={styles.container}>
<Text style={styles.title}>Hello React Native Web!</Text>
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#f5f5f5",
},
title: {
fontSize: 24,
fontWeight: "bold",
color: "#333",
},
});
// Register the component
AppRegistry.registerComponent("MyApp", () => App);
// Run the application (typically done once at app startup)
AppRegistry.runApplication("MyApp", {
rootTag: document.getElementById("root"),
});Returns an array of all registered application keys.
AppRegistry.getAppKeys(): string[]Gets the application configuration for server-side rendering or advanced use cases.
AppRegistry.getApplication(appKey: string, appParameters?: AppParameters): {element: React.ReactNode, getStyleElement: (any) => React.ReactNode}System appearance and color scheme detection API that responds to user theme preferences and provides real-time updates when the color scheme changes.
const Appearance: {
getColorScheme: () => 'light' | 'dark';
addChangeListener: (listener: (preferences: AppearancePreferences) => void) => {remove: () => void};
};Web Implementation:
Uses the CSS media query (prefers-color-scheme: dark) to detect system theme preferences and provides listeners for theme changes.
Returns the current color scheme preference based on system settings.
Appearance.getColorScheme(): 'light' | 'dark'Adds a listener for color scheme changes. Returns an object with a remove method to unsubscribe.
Appearance.addChangeListener(listener: (preferences: AppearancePreferences) => void): {remove: () => void}Usage:
import React, { useState, useEffect } from "react";
import { Appearance, View, Text, StyleSheet } from "react-native-web";
function ThemedApp() {
const [colorScheme, setColorScheme] = useState(Appearance.getColorScheme());
useEffect(() => {
const subscription = Appearance.addChangeListener(({ colorScheme }) => {
setColorScheme(colorScheme);
});
return () => subscription.remove();
}, []);
const styles = colorScheme === 'dark' ? darkStyles : lightStyles;
return (
<View style={styles.container}>
<Text style={styles.title}>
Current theme: {colorScheme}
</Text>
</View>
);
}
const lightStyles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ffffff',
justifyContent: 'center',
alignItems: 'center',
},
title: {
color: '#000000',
fontSize: 18,
},
});
const darkStyles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#000000',
justifyContent: 'center',
alignItems: 'center',
},
title: {
color: '#ffffff',
fontSize: 18,
},
});Browser-compatible alert system for displaying modal dialogs and user notifications with customizable actions and styling.
const Alert: {
alert: (title?: string, message?: string, buttons?: AlertButton[], options?: AlertOptions) => void;
};Web Implementation: The web implementation provides a minimal interface that can be extended with custom modal implementations. The default implementation uses browser APIs where available.
Alert.alert(): voidUsage:
import { Alert } from "react-native-web";
// Basic usage (web implementation is minimal)
function ShowAlert() {
const handlePress = () => {
Alert.alert();
};
return (
<TouchableOpacity onPress={handlePress}>
<Text>Show Alert</Text>
</TouchableOpacity>
);
}
// Custom alert implementation for web
function CustomAlert({ visible, title, message, buttons, onDismiss }) {
if (!visible) return null;
return (
<View style={styles.overlay}>
<View style={styles.alertContainer}>
{title && <Text style={styles.title}>{title}</Text>}
{message && <Text style={styles.message}>{message}</Text>}
<View style={styles.buttonContainer}>
{buttons?.map((button, index) => (
<TouchableOpacity
key={index}
style={[styles.button, button.style === 'destructive' && styles.destructiveButton]}
onPress={() => {
button.onPress?.();
onDismiss();
}}
>
<Text style={[styles.buttonText, button.style === 'destructive' && styles.destructiveText]}>
{button.text}
</Text>
</TouchableOpacity>
))}
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
overlay: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0,0,0,0.5)',
justifyContent: 'center',
alignItems: 'center',
zIndex: 1000
},
alertContainer: {
backgroundColor: 'white',
borderRadius: 12,
padding: 20,
minWidth: 300,
maxWidth: 400,
margin: 20
},
title: {
fontSize: 18,
fontWeight: 'bold',
marginBottom: 8,
textAlign: 'center'
},
message: {
fontSize: 14,
marginBottom: 20,
textAlign: 'center',
color: '#666'
},
buttonContainer: {
flexDirection: 'row',
justifyContent: 'space-between'
},
button: {
flex: 1,
padding: 12,
marginHorizontal: 4,
backgroundColor: '#007AFF',
borderRadius: 8,
alignItems: 'center'
},
destructiveButton: {
backgroundColor: '#FF3B30'
},
buttonText: {
color: 'white',
fontWeight: '600'
},
destructiveText: {
color: 'white'
}
});Web-compatible clipboard operations for reading and writing text content with fallback implementations for older browsers.
const Clipboard: {
isAvailable: () => boolean;
getString: () => Promise<string>;
setString: (text: string) => boolean;
};Check if clipboard operations are supported in the current browser.
Clipboard.isAvailable(): booleanGet text content from the clipboard (web implementation returns empty string).
Clipboard.getString(): Promise<string>Set text content to the clipboard using browser APIs.
Clipboard.setString(text: string): booleanUsage:
import { Clipboard } from "react-native-web";
function ClipboardDemo() {
const [clipboardText, setClipboardText] = React.useState('');
const [status, setStatus] = React.useState('');
const copyToClipboard = (text) => {
if (Clipboard.isAvailable()) {
const success = Clipboard.setString(text);
setStatus(success ? 'Copied to clipboard!' : 'Failed to copy');
// Clear status after 2 seconds
setTimeout(() => setStatus(''), 2000);
} else {
setStatus('Clipboard not available');
}
};
const pasteFromClipboard = async () => {
try {
// Modern browser API
if (navigator.clipboard && navigator.clipboard.readText) {
const text = await navigator.clipboard.readText();
setClipboardText(text);
setStatus('Pasted from clipboard!');
} else {
// Fallback for react-native-web implementation
const text = await Clipboard.getString();
setClipboardText(text);
setStatus('Retrieved from clipboard');
}
} catch (error) {
setStatus('Failed to read clipboard');
console.error('Clipboard error:', error);
}
};
return (
<View style={styles.container}>
<Text>Clipboard Operations</Text>
<TextInput
style={styles.input}
placeholder="Enter text to copy"
value={clipboardText}
onChangeText={setClipboardText}
/>
<View style={styles.buttonRow}>
<TouchableOpacity
style={styles.button}
onPress={() => copyToClipboard(clipboardText)}
>
<Text style={styles.buttonText}>Copy Text</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={pasteFromClipboard}
>
<Text style={styles.buttonText}>Paste Text</Text>
</TouchableOpacity>
</View>
{status ? <Text style={styles.status}>{status}</Text> : null}
<View style={styles.presetButtons}>
<TouchableOpacity
style={styles.presetButton}
onPress={() => copyToClipboard('https://react-native-web.js.org')}
>
<Text style={styles.buttonText}>Copy URL</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.presetButton}
onPress={() => copyToClipboard('contact@example.com')}
>
<Text style={styles.buttonText}>Copy Email</Text>
</TouchableOpacity>
</View>
</View>
);
}
// Enhanced clipboard with modern API
class EnhancedClipboard {
static async write(text) {
try {
if (navigator.clipboard && navigator.clipboard.writeText) {
await navigator.clipboard.writeText(text);
return true;
} else {
return Clipboard.setString(text);
}
} catch (error) {
console.error('Clipboard write failed:', error);
return false;
}
}
static async read() {
try {
if (navigator.clipboard && navigator.clipboard.readText) {
return await navigator.clipboard.readText();
} else {
return await Clipboard.getString();
}
} catch (error) {
console.error('Clipboard read failed:', error);
return '';
}
}
static async writeRichText(html, text) {
try {
if (navigator.clipboard && navigator.clipboard.write) {
const clipboardItems = [
new ClipboardItem({
'text/html': new Blob([html], { type: 'text/html' }),
'text/plain': new Blob([text], { type: 'text/plain' })
})
];
await navigator.clipboard.write(clipboardItems);
return true;
} else {
// Fallback to plain text
return await this.write(text);
}
} catch (error) {
console.error('Rich text clipboard failed:', error);
return false;
}
}
}URL handling and deep linking capabilities adapted for web environments with support for navigation, external links, and URL event handling.
const Linking: {
addEventListener: (eventType: string, callback: Function) => { remove: () => void };
removeEventListener: (eventType: string, callback: Function) => void;
canOpenURL: (url: string) => Promise<boolean>;
getInitialURL: () => Promise<string>;
openURL: (url: string, target?: string) => Promise<void>;
};Listen for URL change events and other linking-related events.
Linking.addEventListener(
eventType: string,
callback: (...args: any[]) => void
): { remove: () => void }Check if a URL can be opened (always returns true on web).
Linking.canOpenURL(url: string): Promise<boolean>Get the initial URL that opened the app (current page URL on web).
Linking.getInitialURL(): Promise<string>Open a URL in the browser with configurable target window.
Linking.openURL(url: string, target?: string): Promise<void>Usage:
import { Linking } from "react-native-web";
function LinkingDemo() {
const [currentUrl, setCurrentUrl] = React.useState('');
React.useEffect(() => {
// Get initial URL
Linking.getInitialURL().then(setCurrentUrl);
// Listen for URL changes (web-specific implementation)
const subscription = Linking.addEventListener('onOpen', (event) => {
console.log('URL opened:', event);
setCurrentUrl(event.url || window.location.href);
});
// Cleanup
return () => subscription.remove();
}, []);
const openExternalLink = (url) => {
Linking.canOpenURL(url).then(supported => {
if (supported) {
Linking.openURL(url, '_blank');
} else {
console.log("Don't know how to open URI: " + url);
}
});
};
const openInSameTab = (url) => {
Linking.openURL(url, '_self');
};
const openEmail = (email, subject = '', body = '') => {
const emailUrl = `mailto:${email}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
Linking.openURL(emailUrl);
};
const openPhone = (phoneNumber) => {
const phoneUrl = `tel:${phoneNumber}`;
Linking.openURL(phoneUrl);
};
return (
<View style={styles.container}>
<Text style={styles.title}>Linking Demo</Text>
<Text style={styles.currentUrl}>Current URL: {currentUrl}</Text>
<View style={styles.buttonContainer}>
<TouchableOpacity
style={styles.linkButton}
onPress={() => openExternalLink('https://github.com')}
>
<Text style={styles.buttonText}>Open GitHub (New Tab)</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.linkButton}
onPress={() => openInSameTab('https://react-native-web.js.org')}
>
<Text style={styles.buttonText}>Open RNW Docs (Same Tab)</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.linkButton}
onPress={() => openEmail('hello@example.com', 'Hello!', 'This is a test email.')}
>
<Text style={styles.buttonText}>Send Email</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.linkButton}
onPress={() => openPhone('+1234567890')}
>
<Text style={styles.buttonText}>Call Phone</Text>
</TouchableOpacity>
</View>
</View>
);
}
// Advanced URL handling
class URLHandler {
static parseURL(url) {
try {
const urlObj = new URL(url);
return {
protocol: urlObj.protocol,
host: urlObj.host,
pathname: urlObj.pathname,
search: urlObj.search,
hash: urlObj.hash,
searchParams: Object.fromEntries(urlObj.searchParams)
};
} catch (error) {
console.error('Invalid URL:', error);
return null;
}
}
static buildURL(base, params = {}) {
const url = new URL(base);
Object.entries(params).forEach(([key, value]) => {
url.searchParams.set(key, value);
});
return url.toString();
}
static async openWithConfirmation(url, message = 'Open this link?') {
if (window.confirm(message)) {
return Linking.openURL(url, '_blank');
}
}
static trackLinkClick(url, analytics = {}) {
// Track the link click
if (analytics.track) {
analytics.track('External Link Clicked', { url });
}
return Linking.openURL(url, '_blank');
}
}Web Share API integration for sharing content with native browser sharing capabilities and fallback implementations.
const Share: {
share: (content: ShareContent, options?: ShareOptions) => Promise<ShareResult>;
sharedAction: string;
dismissedAction: string;
};Share content using the Web Share API or fallback methods.
Share.share(
content: {
title?: string;
message?: string;
url?: string;
},
options?: {}
): Promise<{ action: string }>Usage:
import { Share } from "react-native-web";
function ShareDemo() {
const [shareResult, setShareResult] = React.useState('');
const shareContent = async (content) => {
try {
const result = await Share.share(content);
if (result.action === Share.sharedAction) {
setShareResult('Content shared successfully!');
} else if (result.action === Share.dismissedAction) {
setShareResult('Share dialog dismissed');
}
} catch (error) {
console.error('Share failed:', error);
setShareResult('Share not supported or failed');
// Fallback: copy to clipboard
if (content.url) {
navigator.clipboard?.writeText(content.url);
setShareResult('URL copied to clipboard as fallback');
}
}
};
const shareCurrentPage = () => {
shareContent({
title: document.title,
message: 'Check out this page!',
url: window.location.href
});
};
const shareCustomContent = () => {
shareContent({
title: 'React Native Web',
message: 'Build native web apps with React Native!',
url: 'https://necolas.github.io/react-native-web/'
});
};
const shareTextOnly = () => {
shareContent({
message: 'This is a text-only share with no URL'
});
};
return (
<View style={styles.container}>
<Text style={styles.title}>Share Demo</Text>
<View style={styles.buttonContainer}>
<TouchableOpacity style={styles.shareButton} onPress={shareCurrentPage}>
<Text style={styles.buttonText}>Share Current Page</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.shareButton} onPress={shareCustomContent}>
<Text style={styles.buttonText}>Share Custom Content</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.shareButton} onPress={shareTextOnly}>
<Text style={styles.buttonText}>Share Text Only</Text>
</TouchableOpacity>
</View>
{shareResult ? (
<Text style={styles.result}>{shareResult}</Text>
) : null}
</View>
);
}
// Enhanced sharing with multiple fallbacks
class EnhancedShare {
static async share(content, options = {}) {
// Try Web Share API first
if (navigator.share) {
try {
await navigator.share(content);
return { action: 'shared' };
} catch (error) {
if (error.name === 'AbortError') {
return { action: 'dismissed' };
}
// Fall through to other methods
}
}
// Fallback: Social media sharing
return this.fallbackShare(content, options);
}
static async fallbackShare(content, options) {
const { title, message, url } = content;
const shareText = `${title ? title + ': ' : ''}${message || ''}${url ? ' ' + url : ''}`;
if (options.preferredMethod === 'clipboard') {
return this.shareViaClipboard(shareText);
}
// Show custom share modal
return this.showShareModal(content);
}
static async shareViaClipboard(text) {
try {
await navigator.clipboard.writeText(text);
alert('Content copied to clipboard!');
return { action: 'shared' };
} catch (error) {
console.error('Clipboard share failed:', error);
return { action: 'failed' };
}
}
static showShareModal(content) {
return new Promise((resolve) => {
// Create custom share modal
const modal = document.createElement('div');
modal.innerHTML = `
<div style="position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.5); z-index: 1000; display: flex; align-items: center; justify-content: center;">
<div style="background: white; border-radius: 12px; padding: 20px; max-width: 400px; margin: 20px;">
<h3>Share Content</h3>
<p>${content.title || ''}</p>
<p>${content.message || ''}</p>
<div style="display: flex; gap: 10px; margin-top: 20px;">
<button onclick="window.shareViaTwitter('${content.url}', '${content.message}')">Twitter</button>
<button onclick="window.shareViaFacebook('${content.url}')">Facebook</button>
<button onclick="window.copyToClipboard('${content.url || content.message}')">Copy</button>
<button onclick="window.closeShareModal()">Cancel</button>
</div>
</div>
</div>
`;
document.body.appendChild(modal);
// Add global functions
window.closeShareModal = () => {
document.body.removeChild(modal);
resolve({ action: 'dismissed' });
};
window.shareViaTwitter = (url, text) => {
window.open(`https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}&text=${encodeURIComponent(text)}`);
window.closeShareModal();
resolve({ action: 'shared' });
};
window.shareViaFacebook = (url) => {
window.open(`https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url)}`);
window.closeShareModal();
resolve({ action: 'shared' });
};
window.copyToClipboard = async (text) => {
await navigator.clipboard.writeText(text);
window.closeShareModal();
resolve({ action: 'shared' });
};
});
}
}Vibration API wrapper for web with support for patterns and fallback behavior on non-supporting devices.
const Vibration: {
cancel: () => void;
vibrate: (pattern?: number | number[]) => void;
};Trigger device vibration with optional pattern support.
Vibration.vibrate(pattern?: number | number[] = 400): voidCancel any ongoing vibration.
Vibration.cancel(): voidUsage:
import { Vibration } from "react-native-web";
function VibrationDemo() {
const [isVibrationSupported, setIsVibrationSupported] = React.useState(false);
React.useEffect(() => {
// Check if vibration is supported
setIsVibrationSupported('vibrate' in navigator);
}, []);
const singleVibration = () => {
Vibration.vibrate(200);
};
const patternVibration = () => {
// Pattern: [vibrate, pause, vibrate, pause, ...]
Vibration.vibrate([100, 200, 100, 200, 300]);
};
const longVibration = () => {
Vibration.vibrate(1000);
};
const cancelVibration = () => {
Vibration.cancel();
};
// Haptic feedback patterns
const hapticPatterns = {
notification: [50, 50, 50],
warning: [100, 100, 100, 100, 200],
error: [200, 100, 200, 100, 200],
success: [50, 50, 100],
click: [10],
doubleClick: [10, 50, 10]
};
const playHaptic = (pattern) => {
if (isVibrationSupported) {
Vibration.vibrate(hapticPatterns[pattern]);
} else {
console.log(`Haptic feedback: ${pattern}`);
}
};
return (
<View style={styles.container}>
<Text style={styles.title}>Vibration Demo</Text>
<Text style={styles.status}>
Vibration Support: {isVibrationSupported ? 'Supported' : 'Not Supported'}
</Text>
<View style={styles.buttonContainer}>
<TouchableOpacity
style={styles.vibrationButton}
onPress={singleVibration}
>
<Text style={styles.buttonText}>Single Vibration</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.vibrationButton}
onPress={patternVibration}
>
<Text style={styles.buttonText}>Pattern Vibration</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.vibrationButton}
onPress={longVibration}
>
<Text style={styles.buttonText}>Long Vibration</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.vibrationButton, styles.cancelButton]}
onPress={cancelVibration}
>
<Text style={styles.buttonText}>Cancel Vibration</Text>
</TouchableOpacity>
</View>
<Text style={styles.sectionTitle}>Haptic Feedback Patterns</Text>
<View style={styles.hapticContainer}>
{Object.keys(hapticPatterns).map((pattern) => (
<TouchableOpacity
key={pattern}
style={styles.hapticButton}
onPress={() => playHaptic(pattern)}
>
<Text style={styles.hapticText}>{pattern}</Text>
</TouchableOpacity>
))}
</View>
</View>
);
}
// Enhanced vibration with game-like haptics
class GameHaptics {
static isSupported() {
return 'vibrate' in navigator;
}
static feedback = {
// UI Interactions
buttonPress: () => Vibration.vibrate(10),
buttonRelease: () => Vibration.vibrate(5),
// Game Events
powerUp: () => Vibration.vibrate([50, 50, 100, 50, 150]),
levelComplete: () => Vibration.vibrate([100, 100, 100, 100, 200]),
gameOver: () => Vibration.vibrate([200, 100, 200, 100, 400]),
// Notifications
message: () => Vibration.vibrate([80, 80, 80]),
alert: () => Vibration.vibrate([100, 200, 100, 200, 300]),
// Continuous effects
startEngine: () => {
const pattern = Array(10).fill([20, 30]).flat();
Vibration.vibrate(pattern);
},
stopEngine: () => Vibration.cancel()
};
static playSequence(sequence, callback) {
let index = 0;
const playNext = () => {
if (index < sequence.length) {
this.feedback[sequence[index]]();
index++;
setTimeout(playNext, 500); // Delay between haptics
} else if (callback) {
callback();
}
};
playNext();
}
}Internationalization manager for handling right-to-left (RTL) layouts and locale-specific formatting with web-compatible implementation.
const I18nManager: {
allowRTL: (allowRTL: boolean) => void;
forceRTL: (forceRTL: boolean) => void;
getConstants: () => { isRTL: boolean };
isRTL?: boolean;
};Allow RTL layout (web implementation is no-op).
I18nManager.allowRTL(allowRTL: boolean): voidForce RTL layout (web implementation is no-op).
I18nManager.forceRTL(forceRTL: boolean): voidGet internationalization constants including RTL status.
I18nManager.getConstants(): { isRTL: boolean }Usage:
import { I18nManager } from "react-native-web";
function I18nDemo() {
const [isRTL, setIsRTL] = React.useState(false);
React.useEffect(() => {
const constants = I18nManager.getConstants();
setIsRTL(constants.isRTL);
}, []);
// Web-specific RTL detection
const detectRTLFromDOM = () => {
const direction = document.dir || document.documentElement.dir || 'ltr';
return direction === 'rtl';
};
const detectRTLFromLanguage = (language) => {
const rtlLanguages = ['ar', 'he', 'fa', 'ur', 'yi'];
return rtlLanguages.includes(language.split('-')[0]);
};
return (
<View style={[styles.container, isRTL && styles.rtlContainer]}>
<Text style={styles.title}>
Internationalization Demo
</Text>
<Text>RTL Status: {isRTL ? 'Right-to-Left' : 'Left-to-Right'}</Text>
<Text>DOM Direction: {detectRTLFromDOM() ? 'RTL' : 'LTR'}</Text>
<View style={[styles.textContainer, isRTL && styles.rtlText]}>
<Text style={styles.label}>Name:</Text>
<Text style={styles.value}>John Doe</Text>
</View>
<View style={[styles.textContainer, isRTL && styles.rtlText]}>
<Text style={styles.label}>العربية:</Text>
<Text style={styles.value}>مرحبا بالعالم</Text>
</View>
</View>
);
}
// Enhanced I18n utilities for web
class WebI18nManager {
static detectDirection(locale) {
const rtlLocales = [
'ar', 'arc', 'dv', 'fa', 'ha', 'he', 'khw', 'ks',
'ku', 'ps', 'ur', 'yi'
];
const language = locale.split('-')[0];
return rtlLocales.includes(language) ? 'rtl' : 'ltr';
}
static setDocumentDirection(direction) {
document.documentElement.dir = direction;
document.documentElement.setAttribute('data-direction', direction);
}
static createRTLStyles(styles, isRTL) {
if (!isRTL) return styles;
const rtlStyles = { ...styles };
// Flip horizontal margins and padding
if (styles.marginLeft !== undefined) {
rtlStyles.marginRight = styles.marginLeft;
rtlStyles.marginLeft = styles.marginRight || 0;
}
if (styles.paddingLeft !== undefined) {
rtlStyles.paddingRight = styles.paddingLeft;
rtlStyles.paddingLeft = styles.paddingRight || 0;
}
// Flip text alignment
if (styles.textAlign === 'left') {
rtlStyles.textAlign = 'right';
} else if (styles.textAlign === 'right') {
rtlStyles.textAlign = 'left';
}
// Flip flex direction
if (styles.flexDirection === 'row') {
rtlStyles.flexDirection = 'row-reverse';
} else if (styles.flexDirection === 'row-reverse') {
rtlStyles.flexDirection = 'row';
}
return rtlStyles;
}
static useRTLLayout(locale) {
const [isRTL, setIsRTL] = React.useState(false);
React.useEffect(() => {
const direction = this.detectDirection(locale);
const rtl = direction === 'rtl';
setIsRTL(rtl);
this.setDocumentDirection(direction);
}, [locale]);
return isRTL;
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16
},
rtlContainer: {
flexDirection: 'row-reverse'
},
title: {
fontSize: 18,
fontWeight: 'bold',
marginBottom: 16
},
textContainer: {
flexDirection: 'row',
marginBottom: 8,
alignItems: 'center'
},
rtlText: {
flexDirection: 'row-reverse'
},
label: {
fontWeight: 'bold',
marginRight: 8
},
value: {
flex: 1
}
});interface AppParameters {
rootTag: Element;
initialProps?: Object;
hydrate?: boolean;
mode?: 'legacy' | 'concurrent';
callback?: () => void;
}
interface AppConfig {
appKey: string;
component?: () => React.ComponentType;
run?: Function;
section?: boolean;
}
type ComponentProviderInstrumentationHook = (component: () => React.ComponentType) => React.ComponentType;
type WrapperComponentProvider = (any) => React.ComponentType;
type ColorSchemeName = 'light' | 'dark';
interface AppearancePreferences {
colorScheme: ColorSchemeName;
}
interface ShareContent {
title?: string;
message?: string;
url?: string;
}
interface ShareOptions {}
interface ShareResult {
action: string;
}
type VibratePattern = number | number[];
interface I18nConstants {
isRTL: boolean;
}
type AlertButton = {
text: string;
onPress?: () => void;
style?: 'default' | 'cancel' | 'destructive';
};
type AlertOptions = {
cancelable?: boolean;
onDismiss?: () => void;
};
interface LinkingEventCallback {
(event: { url: string }): void;
}Install with Tessl CLI
npx tessl i tessl/npm-react-native-web