or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

accessibility.mdanimation.mdcore-utilities.mdform-controls.mdhooks.mdindex.mdinteractive-components.mdlayout-components.mdlist-components.mdmedia-components.mdplatform-apis.mdstylesheet.mdsystem-integration.mdtext-input.md

system-integration.mddocs/

0

# System Integration

1

2

React Native's system integration APIs adapted for web, providing access to device capabilities, clipboard operations, URL handling, sharing functionality, and internationalization support.

3

4

## AppRegistry

5

6

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.

7

8

```javascript { .api }

9

const AppRegistry: {

10

registerComponent: (appKey: string, componentProvider: () => React.ComponentType) => string;

11

runApplication: (appKey: string, appParameters: AppParameters) => void;

12

getAppKeys: () => string[];

13

getApplication: (appKey: string, appParameters?: AppParameters) => {element: React.ReactNode, getStyleElement: (any) => React.ReactNode};

14

registerConfig: (config: AppConfig[]) => void;

15

registerRunnable: (appKey: string, run: Function) => string;

16

unmountApplicationComponentAtRootTag: (rootTag: Element) => void;

17

setComponentProviderInstrumentationHook: (hook: ComponentProviderInstrumentationHook) => void;

18

setWrapperComponentProvider: (provider: WrapperComponentProvider) => void;

19

};

20

```

21

22

**Web Implementation:**

23

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.

24

25

### registerComponent()

26

27

Registers a React component as a runnable application that can be started with `runApplication`.

28

29

```javascript { .api }

30

AppRegistry.registerComponent(appKey: string, componentProvider: () => React.ComponentType): string

31

```

32

33

### runApplication()

34

35

Runs a registered application by mounting it to a DOM element. This is the primary method for starting React Native Web applications.

36

37

```javascript { .api }

38

AppRegistry.runApplication(appKey: string, appParameters: AppParameters): void

39

```

40

41

**Usage:**

42

```javascript

43

import React from "react";

44

import { AppRegistry, View, Text, StyleSheet } from "react-native-web";

45

46

// Define your app component

47

const App = () => (

48

<View style={styles.container}>

49

<Text style={styles.title}>Hello React Native Web!</Text>

50

</View>

51

);

52

53

const styles = StyleSheet.create({

54

container: {

55

flex: 1,

56

justifyContent: "center",

57

alignItems: "center",

58

backgroundColor: "#f5f5f5",

59

},

60

title: {

61

fontSize: 24,

62

fontWeight: "bold",

63

color: "#333",

64

},

65

});

66

67

// Register the component

68

AppRegistry.registerComponent("MyApp", () => App);

69

70

// Run the application (typically done once at app startup)

71

AppRegistry.runApplication("MyApp", {

72

rootTag: document.getElementById("root"),

73

});

74

```

75

76

### getAppKeys()

77

78

Returns an array of all registered application keys.

79

80

```javascript { .api }

81

AppRegistry.getAppKeys(): string[]

82

```

83

84

### getApplication()

85

86

Gets the application configuration for server-side rendering or advanced use cases.

87

88

```javascript { .api }

89

AppRegistry.getApplication(appKey: string, appParameters?: AppParameters): {element: React.ReactNode, getStyleElement: (any) => React.ReactNode}

90

```

91

92

## Appearance

93

94

System appearance and color scheme detection API that responds to user theme preferences and provides real-time updates when the color scheme changes.

95

96

```javascript { .api }

97

const Appearance: {

98

getColorScheme: () => 'light' | 'dark';

99

addChangeListener: (listener: (preferences: AppearancePreferences) => void) => {remove: () => void};

100

};

101

```

102

103

**Web Implementation:**

104

Uses the CSS media query `(prefers-color-scheme: dark)` to detect system theme preferences and provides listeners for theme changes.

105

106

### getColorScheme()

107

108

Returns the current color scheme preference based on system settings.

109

110

```javascript { .api }

111

Appearance.getColorScheme(): 'light' | 'dark'

112

```

113

114

### addChangeListener()

115

116

Adds a listener for color scheme changes. Returns an object with a `remove` method to unsubscribe.

117

118

```javascript { .api }

119

Appearance.addChangeListener(listener: (preferences: AppearancePreferences) => void): {remove: () => void}

120

```

121

122

**Usage:**

123

```javascript

124

import React, { useState, useEffect } from "react";

125

import { Appearance, View, Text, StyleSheet } from "react-native-web";

126

127

function ThemedApp() {

128

const [colorScheme, setColorScheme] = useState(Appearance.getColorScheme());

129

130

useEffect(() => {

131

const subscription = Appearance.addChangeListener(({ colorScheme }) => {

132

setColorScheme(colorScheme);

133

});

134

135

return () => subscription.remove();

136

}, []);

137

138

const styles = colorScheme === 'dark' ? darkStyles : lightStyles;

139

140

return (

141

<View style={styles.container}>

142

<Text style={styles.title}>

143

Current theme: {colorScheme}

144

</Text>

145

</View>

146

);

147

}

148

149

const lightStyles = StyleSheet.create({

150

container: {

151

flex: 1,

152

backgroundColor: '#ffffff',

153

justifyContent: 'center',

154

alignItems: 'center',

155

},

156

title: {

157

color: '#000000',

158

fontSize: 18,

159

},

160

});

161

162

const darkStyles = StyleSheet.create({

163

container: {

164

flex: 1,

165

backgroundColor: '#000000',

166

justifyContent: 'center',

167

alignItems: 'center',

168

},

169

title: {

170

color: '#ffffff',

171

fontSize: 18,

172

},

173

});

174

```

175

176

## Alert

177

178

Browser-compatible alert system for displaying modal dialogs and user notifications with customizable actions and styling.

179

180

```javascript { .api }

181

const Alert: {

182

alert: (title?: string, message?: string, buttons?: AlertButton[], options?: AlertOptions) => void;

183

};

184

```

185

186

**Web Implementation:**

187

The web implementation provides a minimal interface that can be extended with custom modal implementations. The default implementation uses browser APIs where available.

188

189

```javascript { .api }

190

Alert.alert(): void

191

```

192

193

**Usage:**

194

```javascript

195

import { Alert } from "react-native-web";

196

197

// Basic usage (web implementation is minimal)

198

function ShowAlert() {

199

const handlePress = () => {

200

Alert.alert();

201

};

202

203

return (

204

<TouchableOpacity onPress={handlePress}>

205

<Text>Show Alert</Text>

206

</TouchableOpacity>

207

);

208

}

209

210

// Custom alert implementation for web

211

function CustomAlert({ visible, title, message, buttons, onDismiss }) {

212

if (!visible) return null;

213

214

return (

215

<View style={styles.overlay}>

216

<View style={styles.alertContainer}>

217

{title && <Text style={styles.title}>{title}</Text>}

218

{message && <Text style={styles.message}>{message}</Text>}

219

220

<View style={styles.buttonContainer}>

221

{buttons?.map((button, index) => (

222

<TouchableOpacity

223

key={index}

224

style={[styles.button, button.style === 'destructive' && styles.destructiveButton]}

225

onPress={() => {

226

button.onPress?.();

227

onDismiss();

228

}}

229

>

230

<Text style={[styles.buttonText, button.style === 'destructive' && styles.destructiveText]}>

231

{button.text}

232

</Text>

233

</TouchableOpacity>

234

))}

235

</View>

236

</View>

237

</View>

238

);

239

}

240

241

const styles = StyleSheet.create({

242

overlay: {

243

position: 'absolute',

244

top: 0,

245

left: 0,

246

right: 0,

247

bottom: 0,

248

backgroundColor: 'rgba(0,0,0,0.5)',

249

justifyContent: 'center',

250

alignItems: 'center',

251

zIndex: 1000

252

},

253

alertContainer: {

254

backgroundColor: 'white',

255

borderRadius: 12,

256

padding: 20,

257

minWidth: 300,

258

maxWidth: 400,

259

margin: 20

260

},

261

title: {

262

fontSize: 18,

263

fontWeight: 'bold',

264

marginBottom: 8,

265

textAlign: 'center'

266

},

267

message: {

268

fontSize: 14,

269

marginBottom: 20,

270

textAlign: 'center',

271

color: '#666'

272

},

273

buttonContainer: {

274

flexDirection: 'row',

275

justifyContent: 'space-between'

276

},

277

button: {

278

flex: 1,

279

padding: 12,

280

marginHorizontal: 4,

281

backgroundColor: '#007AFF',

282

borderRadius: 8,

283

alignItems: 'center'

284

},

285

destructiveButton: {

286

backgroundColor: '#FF3B30'

287

},

288

buttonText: {

289

color: 'white',

290

fontWeight: '600'

291

},

292

destructiveText: {

293

color: 'white'

294

}

295

});

296

```

297

298

## Clipboard

299

300

Web-compatible clipboard operations for reading and writing text content with fallback implementations for older browsers.

301

302

```javascript { .api }

303

const Clipboard: {

304

isAvailable: () => boolean;

305

getString: () => Promise<string>;

306

setString: (text: string) => boolean;

307

};

308

```

309

310

### isAvailable()

311

Check if clipboard operations are supported in the current browser.

312

313

```javascript { .api }

314

Clipboard.isAvailable(): boolean

315

```

316

317

### getString()

318

Get text content from the clipboard (web implementation returns empty string).

319

320

```javascript { .api }

321

Clipboard.getString(): Promise<string>

322

```

323

324

### setString()

325

Set text content to the clipboard using browser APIs.

326

327

```javascript { .api }

328

Clipboard.setString(text: string): boolean

329

```

330

331

**Usage:**

332

```javascript

333

import { Clipboard } from "react-native-web";

334

335

function ClipboardDemo() {

336

const [clipboardText, setClipboardText] = React.useState('');

337

const [status, setStatus] = React.useState('');

338

339

const copyToClipboard = (text) => {

340

if (Clipboard.isAvailable()) {

341

const success = Clipboard.setString(text);

342

setStatus(success ? 'Copied to clipboard!' : 'Failed to copy');

343

344

// Clear status after 2 seconds

345

setTimeout(() => setStatus(''), 2000);

346

} else {

347

setStatus('Clipboard not available');

348

}

349

};

350

351

const pasteFromClipboard = async () => {

352

try {

353

// Modern browser API

354

if (navigator.clipboard && navigator.clipboard.readText) {

355

const text = await navigator.clipboard.readText();

356

setClipboardText(text);

357

setStatus('Pasted from clipboard!');

358

} else {

359

// Fallback for react-native-web implementation

360

const text = await Clipboard.getString();

361

setClipboardText(text);

362

setStatus('Retrieved from clipboard');

363

}

364

} catch (error) {

365

setStatus('Failed to read clipboard');

366

console.error('Clipboard error:', error);

367

}

368

};

369

370

return (

371

<View style={styles.container}>

372

<Text>Clipboard Operations</Text>

373

374

<TextInput

375

style={styles.input}

376

placeholder="Enter text to copy"

377

value={clipboardText}

378

onChangeText={setClipboardText}

379

/>

380

381

<View style={styles.buttonRow}>

382

<TouchableOpacity

383

style={styles.button}

384

onPress={() => copyToClipboard(clipboardText)}

385

>

386

<Text style={styles.buttonText}>Copy Text</Text>

387

</TouchableOpacity>

388

389

<TouchableOpacity

390

style={styles.button}

391

onPress={pasteFromClipboard}

392

>

393

<Text style={styles.buttonText}>Paste Text</Text>

394

</TouchableOpacity>

395

</View>

396

397

{status ? <Text style={styles.status}>{status}</Text> : null}

398

399

<View style={styles.presetButtons}>

400

<TouchableOpacity

401

style={styles.presetButton}

402

onPress={() => copyToClipboard('https://react-native-web.js.org')}

403

>

404

<Text style={styles.buttonText}>Copy URL</Text>

405

</TouchableOpacity>

406

407

<TouchableOpacity

408

style={styles.presetButton}

409

onPress={() => copyToClipboard('contact@example.com')}

410

>

411

<Text style={styles.buttonText}>Copy Email</Text>

412

</TouchableOpacity>

413

</View>

414

</View>

415

);

416

}

417

418

// Enhanced clipboard with modern API

419

class EnhancedClipboard {

420

static async write(text) {

421

try {

422

if (navigator.clipboard && navigator.clipboard.writeText) {

423

await navigator.clipboard.writeText(text);

424

return true;

425

} else {

426

return Clipboard.setString(text);

427

}

428

} catch (error) {

429

console.error('Clipboard write failed:', error);

430

return false;

431

}

432

}

433

434

static async read() {

435

try {

436

if (navigator.clipboard && navigator.clipboard.readText) {

437

return await navigator.clipboard.readText();

438

} else {

439

return await Clipboard.getString();

440

}

441

} catch (error) {

442

console.error('Clipboard read failed:', error);

443

return '';

444

}

445

}

446

447

static async writeRichText(html, text) {

448

try {

449

if (navigator.clipboard && navigator.clipboard.write) {

450

const clipboardItems = [

451

new ClipboardItem({

452

'text/html': new Blob([html], { type: 'text/html' }),

453

'text/plain': new Blob([text], { type: 'text/plain' })

454

})

455

];

456

await navigator.clipboard.write(clipboardItems);

457

return true;

458

} else {

459

// Fallback to plain text

460

return await this.write(text);

461

}

462

} catch (error) {

463

console.error('Rich text clipboard failed:', error);

464

return false;

465

}

466

}

467

}

468

```

469

470

## Linking

471

472

URL handling and deep linking capabilities adapted for web environments with support for navigation, external links, and URL event handling.

473

474

```javascript { .api }

475

const Linking: {

476

addEventListener: (eventType: string, callback: Function) => { remove: () => void };

477

removeEventListener: (eventType: string, callback: Function) => void;

478

canOpenURL: (url: string) => Promise<boolean>;

479

getInitialURL: () => Promise<string>;

480

openURL: (url: string, target?: string) => Promise<void>;

481

};

482

```

483

484

### addEventListener()

485

Listen for URL change events and other linking-related events.

486

487

```javascript { .api }

488

Linking.addEventListener(

489

eventType: string,

490

callback: (...args: any[]) => void

491

): { remove: () => void }

492

```

493

494

### canOpenURL()

495

Check if a URL can be opened (always returns true on web).

496

497

```javascript { .api }

498

Linking.canOpenURL(url: string): Promise<boolean>

499

```

500

501

### getInitialURL()

502

Get the initial URL that opened the app (current page URL on web).

503

504

```javascript { .api }

505

Linking.getInitialURL(): Promise<string>

506

```

507

508

### openURL()

509

Open a URL in the browser with configurable target window.

510

511

```javascript { .api }

512

Linking.openURL(url: string, target?: string): Promise<void>

513

```

514

515

**Usage:**

516

```javascript

517

import { Linking } from "react-native-web";

518

519

function LinkingDemo() {

520

const [currentUrl, setCurrentUrl] = React.useState('');

521

522

React.useEffect(() => {

523

// Get initial URL

524

Linking.getInitialURL().then(setCurrentUrl);

525

526

// Listen for URL changes (web-specific implementation)

527

const subscription = Linking.addEventListener('onOpen', (event) => {

528

console.log('URL opened:', event);

529

setCurrentUrl(event.url || window.location.href);

530

});

531

532

// Cleanup

533

return () => subscription.remove();

534

}, []);

535

536

const openExternalLink = (url) => {

537

Linking.canOpenURL(url).then(supported => {

538

if (supported) {

539

Linking.openURL(url, '_blank');

540

} else {

541

console.log("Don't know how to open URI: " + url);

542

}

543

});

544

};

545

546

const openInSameTab = (url) => {

547

Linking.openURL(url, '_self');

548

};

549

550

const openEmail = (email, subject = '', body = '') => {

551

const emailUrl = `mailto:${email}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;

552

Linking.openURL(emailUrl);

553

};

554

555

const openPhone = (phoneNumber) => {

556

const phoneUrl = `tel:${phoneNumber}`;

557

Linking.openURL(phoneUrl);

558

};

559

560

return (

561

<View style={styles.container}>

562

<Text style={styles.title}>Linking Demo</Text>

563

<Text style={styles.currentUrl}>Current URL: {currentUrl}</Text>

564

565

<View style={styles.buttonContainer}>

566

<TouchableOpacity

567

style={styles.linkButton}

568

onPress={() => openExternalLink('https://github.com')}

569

>

570

<Text style={styles.buttonText}>Open GitHub (New Tab)</Text>

571

</TouchableOpacity>

572

573

<TouchableOpacity

574

style={styles.linkButton}

575

onPress={() => openInSameTab('https://react-native-web.js.org')}

576

>

577

<Text style={styles.buttonText}>Open RNW Docs (Same Tab)</Text>

578

</TouchableOpacity>

579

580

<TouchableOpacity

581

style={styles.linkButton}

582

onPress={() => openEmail('hello@example.com', 'Hello!', 'This is a test email.')}

583

>

584

<Text style={styles.buttonText}>Send Email</Text>

585

</TouchableOpacity>

586

587

<TouchableOpacity

588

style={styles.linkButton}

589

onPress={() => openPhone('+1234567890')}

590

>

591

<Text style={styles.buttonText}>Call Phone</Text>

592

</TouchableOpacity>

593

</View>

594

</View>

595

);

596

}

597

598

// Advanced URL handling

599

class URLHandler {

600

static parseURL(url) {

601

try {

602

const urlObj = new URL(url);

603

return {

604

protocol: urlObj.protocol,

605

host: urlObj.host,

606

pathname: urlObj.pathname,

607

search: urlObj.search,

608

hash: urlObj.hash,

609

searchParams: Object.fromEntries(urlObj.searchParams)

610

};

611

} catch (error) {

612

console.error('Invalid URL:', error);

613

return null;

614

}

615

}

616

617

static buildURL(base, params = {}) {

618

const url = new URL(base);

619

Object.entries(params).forEach(([key, value]) => {

620

url.searchParams.set(key, value);

621

});

622

return url.toString();

623

}

624

625

static async openWithConfirmation(url, message = 'Open this link?') {

626

if (window.confirm(message)) {

627

return Linking.openURL(url, '_blank');

628

}

629

}

630

631

static trackLinkClick(url, analytics = {}) {

632

// Track the link click

633

if (analytics.track) {

634

analytics.track('External Link Clicked', { url });

635

}

636

return Linking.openURL(url, '_blank');

637

}

638

}

639

```

640

641

## Share

642

643

Web Share API integration for sharing content with native browser sharing capabilities and fallback implementations.

644

645

```javascript { .api }

646

const Share: {

647

share: (content: ShareContent, options?: ShareOptions) => Promise<ShareResult>;

648

sharedAction: string;

649

dismissedAction: string;

650

};

651

```

652

653

### share()

654

Share content using the Web Share API or fallback methods.

655

656

```javascript { .api }

657

Share.share(

658

content: {

659

title?: string;

660

message?: string;

661

url?: string;

662

},

663

options?: {}

664

): Promise<{ action: string }>

665

```

666

667

**Usage:**

668

```javascript

669

import { Share } from "react-native-web";

670

671

function ShareDemo() {

672

const [shareResult, setShareResult] = React.useState('');

673

674

const shareContent = async (content) => {

675

try {

676

const result = await Share.share(content);

677

678

if (result.action === Share.sharedAction) {

679

setShareResult('Content shared successfully!');

680

} else if (result.action === Share.dismissedAction) {

681

setShareResult('Share dialog dismissed');

682

}

683

} catch (error) {

684

console.error('Share failed:', error);

685

setShareResult('Share not supported or failed');

686

687

// Fallback: copy to clipboard

688

if (content.url) {

689

navigator.clipboard?.writeText(content.url);

690

setShareResult('URL copied to clipboard as fallback');

691

}

692

}

693

};

694

695

const shareCurrentPage = () => {

696

shareContent({

697

title: document.title,

698

message: 'Check out this page!',

699

url: window.location.href

700

});

701

};

702

703

const shareCustomContent = () => {

704

shareContent({

705

title: 'React Native Web',

706

message: 'Build native web apps with React Native!',

707

url: 'https://necolas.github.io/react-native-web/'

708

});

709

};

710

711

const shareTextOnly = () => {

712

shareContent({

713

message: 'This is a text-only share with no URL'

714

});

715

};

716

717

return (

718

<View style={styles.container}>

719

<Text style={styles.title}>Share Demo</Text>

720

721

<View style={styles.buttonContainer}>

722

<TouchableOpacity style={styles.shareButton} onPress={shareCurrentPage}>

723

<Text style={styles.buttonText}>Share Current Page</Text>

724

</TouchableOpacity>

725

726

<TouchableOpacity style={styles.shareButton} onPress={shareCustomContent}>

727

<Text style={styles.buttonText}>Share Custom Content</Text>

728

</TouchableOpacity>

729

730

<TouchableOpacity style={styles.shareButton} onPress={shareTextOnly}>

731

<Text style={styles.buttonText}>Share Text Only</Text>

732

</TouchableOpacity>

733

</View>

734

735

{shareResult ? (

736

<Text style={styles.result}>{shareResult}</Text>

737

) : null}

738

</View>

739

);

740

}

741

742

// Enhanced sharing with multiple fallbacks

743

class EnhancedShare {

744

static async share(content, options = {}) {

745

// Try Web Share API first

746

if (navigator.share) {

747

try {

748

await navigator.share(content);

749

return { action: 'shared' };

750

} catch (error) {

751

if (error.name === 'AbortError') {

752

return { action: 'dismissed' };

753

}

754

// Fall through to other methods

755

}

756

}

757

758

// Fallback: Social media sharing

759

return this.fallbackShare(content, options);

760

}

761

762

static async fallbackShare(content, options) {

763

const { title, message, url } = content;

764

const shareText = `${title ? title + ': ' : ''}${message || ''}${url ? ' ' + url : ''}`;

765

766

if (options.preferredMethod === 'clipboard') {

767

return this.shareViaClipboard(shareText);

768

}

769

770

// Show custom share modal

771

return this.showShareModal(content);

772

}

773

774

static async shareViaClipboard(text) {

775

try {

776

await navigator.clipboard.writeText(text);

777

alert('Content copied to clipboard!');

778

return { action: 'shared' };

779

} catch (error) {

780

console.error('Clipboard share failed:', error);

781

return { action: 'failed' };

782

}

783

}

784

785

static showShareModal(content) {

786

return new Promise((resolve) => {

787

// Create custom share modal

788

const modal = document.createElement('div');

789

modal.innerHTML = `

790

<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;">

791

<div style="background: white; border-radius: 12px; padding: 20px; max-width: 400px; margin: 20px;">

792

<h3>Share Content</h3>

793

<p>${content.title || ''}</p>

794

<p>${content.message || ''}</p>

795

<div style="display: flex; gap: 10px; margin-top: 20px;">

796

<button onclick="window.shareViaTwitter('${content.url}', '${content.message}')">Twitter</button>

797

<button onclick="window.shareViaFacebook('${content.url}')">Facebook</button>

798

<button onclick="window.copyToClipboard('${content.url || content.message}')">Copy</button>

799

<button onclick="window.closeShareModal()">Cancel</button>

800

</div>

801

</div>

802

</div>

803

`;

804

805

document.body.appendChild(modal);

806

807

// Add global functions

808

window.closeShareModal = () => {

809

document.body.removeChild(modal);

810

resolve({ action: 'dismissed' });

811

};

812

813

window.shareViaTwitter = (url, text) => {

814

window.open(`https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}&text=${encodeURIComponent(text)}`);

815

window.closeShareModal();

816

resolve({ action: 'shared' });

817

};

818

819

window.shareViaFacebook = (url) => {

820

window.open(`https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url)}`);

821

window.closeShareModal();

822

resolve({ action: 'shared' });

823

};

824

825

window.copyToClipboard = async (text) => {

826

await navigator.clipboard.writeText(text);

827

window.closeShareModal();

828

resolve({ action: 'shared' });

829

};

830

});

831

}

832

}

833

```

834

835

## Vibration

836

837

Vibration API wrapper for web with support for patterns and fallback behavior on non-supporting devices.

838

839

```javascript { .api }

840

const Vibration: {

841

cancel: () => void;

842

vibrate: (pattern?: number | number[]) => void;

843

};

844

```

845

846

### vibrate()

847

Trigger device vibration with optional pattern support.

848

849

```javascript { .api }

850

Vibration.vibrate(pattern?: number | number[] = 400): void

851

```

852

853

### cancel()

854

Cancel any ongoing vibration.

855

856

```javascript { .api }

857

Vibration.cancel(): void

858

```

859

860

**Usage:**

861

```javascript

862

import { Vibration } from "react-native-web";

863

864

function VibrationDemo() {

865

const [isVibrationSupported, setIsVibrationSupported] = React.useState(false);

866

867

React.useEffect(() => {

868

// Check if vibration is supported

869

setIsVibrationSupported('vibrate' in navigator);

870

}, []);

871

872

const singleVibration = () => {

873

Vibration.vibrate(200);

874

};

875

876

const patternVibration = () => {

877

// Pattern: [vibrate, pause, vibrate, pause, ...]

878

Vibration.vibrate([100, 200, 100, 200, 300]);

879

};

880

881

const longVibration = () => {

882

Vibration.vibrate(1000);

883

};

884

885

const cancelVibration = () => {

886

Vibration.cancel();

887

};

888

889

// Haptic feedback patterns

890

const hapticPatterns = {

891

notification: [50, 50, 50],

892

warning: [100, 100, 100, 100, 200],

893

error: [200, 100, 200, 100, 200],

894

success: [50, 50, 100],

895

click: [10],

896

doubleClick: [10, 50, 10]

897

};

898

899

const playHaptic = (pattern) => {

900

if (isVibrationSupported) {

901

Vibration.vibrate(hapticPatterns[pattern]);

902

} else {

903

console.log(`Haptic feedback: ${pattern}`);

904

}

905

};

906

907

return (

908

<View style={styles.container}>

909

<Text style={styles.title}>Vibration Demo</Text>

910

911

<Text style={styles.status}>

912

Vibration Support: {isVibrationSupported ? 'Supported' : 'Not Supported'}

913

</Text>

914

915

<View style={styles.buttonContainer}>

916

<TouchableOpacity

917

style={styles.vibrationButton}

918

onPress={singleVibration}

919

>

920

<Text style={styles.buttonText}>Single Vibration</Text>

921

</TouchableOpacity>

922

923

<TouchableOpacity

924

style={styles.vibrationButton}

925

onPress={patternVibration}

926

>

927

<Text style={styles.buttonText}>Pattern Vibration</Text>

928

</TouchableOpacity>

929

930

<TouchableOpacity

931

style={styles.vibrationButton}

932

onPress={longVibration}

933

>

934

<Text style={styles.buttonText}>Long Vibration</Text>

935

</TouchableOpacity>

936

937

<TouchableOpacity

938

style={[styles.vibrationButton, styles.cancelButton]}

939

onPress={cancelVibration}

940

>

941

<Text style={styles.buttonText}>Cancel Vibration</Text>

942

</TouchableOpacity>

943

</View>

944

945

<Text style={styles.sectionTitle}>Haptic Feedback Patterns</Text>

946

<View style={styles.hapticContainer}>

947

{Object.keys(hapticPatterns).map((pattern) => (

948

<TouchableOpacity

949

key={pattern}

950

style={styles.hapticButton}

951

onPress={() => playHaptic(pattern)}

952

>

953

<Text style={styles.hapticText}>{pattern}</Text>

954

</TouchableOpacity>

955

))}

956

</View>

957

</View>

958

);

959

}

960

961

// Enhanced vibration with game-like haptics

962

class GameHaptics {

963

static isSupported() {

964

return 'vibrate' in navigator;

965

}

966

967

static feedback = {

968

// UI Interactions

969

buttonPress: () => Vibration.vibrate(10),

970

buttonRelease: () => Vibration.vibrate(5),

971

972

// Game Events

973

powerUp: () => Vibration.vibrate([50, 50, 100, 50, 150]),

974

levelComplete: () => Vibration.vibrate([100, 100, 100, 100, 200]),

975

gameOver: () => Vibration.vibrate([200, 100, 200, 100, 400]),

976

977

// Notifications

978

message: () => Vibration.vibrate([80, 80, 80]),

979

alert: () => Vibration.vibrate([100, 200, 100, 200, 300]),

980

981

// Continuous effects

982

startEngine: () => {

983

const pattern = Array(10).fill([20, 30]).flat();

984

Vibration.vibrate(pattern);

985

},

986

987

stopEngine: () => Vibration.cancel()

988

};

989

990

static playSequence(sequence, callback) {

991

let index = 0;

992

993

const playNext = () => {

994

if (index < sequence.length) {

995

this.feedback[sequence[index]]();

996

index++;

997

setTimeout(playNext, 500); // Delay between haptics

998

} else if (callback) {

999

callback();

1000

}

1001

};

1002

1003

playNext();

1004

}

1005

}

1006

```

1007

1008

## I18nManager

1009

1010

Internationalization manager for handling right-to-left (RTL) layouts and locale-specific formatting with web-compatible implementation.

1011

1012

```javascript { .api }

1013

const I18nManager: {

1014

allowRTL: (allowRTL: boolean) => void;

1015

forceRTL: (forceRTL: boolean) => void;

1016

getConstants: () => { isRTL: boolean };

1017

isRTL?: boolean;

1018

};

1019

```

1020

1021

### allowRTL()

1022

Allow RTL layout (web implementation is no-op).

1023

1024

```javascript { .api }

1025

I18nManager.allowRTL(allowRTL: boolean): void

1026

```

1027

1028

### forceRTL()

1029

Force RTL layout (web implementation is no-op).

1030

1031

```javascript { .api }

1032

I18nManager.forceRTL(forceRTL: boolean): void

1033

```

1034

1035

### getConstants()

1036

Get internationalization constants including RTL status.

1037

1038

```javascript { .api }

1039

I18nManager.getConstants(): { isRTL: boolean }

1040

```

1041

1042

**Usage:**

1043

```javascript

1044

import { I18nManager } from "react-native-web";

1045

1046

function I18nDemo() {

1047

const [isRTL, setIsRTL] = React.useState(false);

1048

1049

React.useEffect(() => {

1050

const constants = I18nManager.getConstants();

1051

setIsRTL(constants.isRTL);

1052

}, []);

1053

1054

// Web-specific RTL detection

1055

const detectRTLFromDOM = () => {

1056

const direction = document.dir || document.documentElement.dir || 'ltr';

1057

return direction === 'rtl';

1058

};

1059

1060

const detectRTLFromLanguage = (language) => {

1061

const rtlLanguages = ['ar', 'he', 'fa', 'ur', 'yi'];

1062

return rtlLanguages.includes(language.split('-')[0]);

1063

};

1064

1065

return (

1066

<View style={[styles.container, isRTL && styles.rtlContainer]}>

1067

<Text style={styles.title}>

1068

Internationalization Demo

1069

</Text>

1070

1071

<Text>RTL Status: {isRTL ? 'Right-to-Left' : 'Left-to-Right'}</Text>

1072

<Text>DOM Direction: {detectRTLFromDOM() ? 'RTL' : 'LTR'}</Text>

1073

1074

<View style={[styles.textContainer, isRTL && styles.rtlText]}>

1075

<Text style={styles.label}>Name:</Text>

1076

<Text style={styles.value}>John Doe</Text>

1077

</View>

1078

1079

<View style={[styles.textContainer, isRTL && styles.rtlText]}>

1080

<Text style={styles.label}>العربية:</Text>

1081

<Text style={styles.value}>مرحبا بالعالم</Text>

1082

</View>

1083

</View>

1084

);

1085

}

1086

1087

// Enhanced I18n utilities for web

1088

class WebI18nManager {

1089

static detectDirection(locale) {

1090

const rtlLocales = [

1091

'ar', 'arc', 'dv', 'fa', 'ha', 'he', 'khw', 'ks',

1092

'ku', 'ps', 'ur', 'yi'

1093

];

1094

1095

const language = locale.split('-')[0];

1096

return rtlLocales.includes(language) ? 'rtl' : 'ltr';

1097

}

1098

1099

static setDocumentDirection(direction) {

1100

document.documentElement.dir = direction;

1101

document.documentElement.setAttribute('data-direction', direction);

1102

}

1103

1104

static createRTLStyles(styles, isRTL) {

1105

if (!isRTL) return styles;

1106

1107

const rtlStyles = { ...styles };

1108

1109

// Flip horizontal margins and padding

1110

if (styles.marginLeft !== undefined) {

1111

rtlStyles.marginRight = styles.marginLeft;

1112

rtlStyles.marginLeft = styles.marginRight || 0;

1113

}

1114

1115

if (styles.paddingLeft !== undefined) {

1116

rtlStyles.paddingRight = styles.paddingLeft;

1117

rtlStyles.paddingLeft = styles.paddingRight || 0;

1118

}

1119

1120

// Flip text alignment

1121

if (styles.textAlign === 'left') {

1122

rtlStyles.textAlign = 'right';

1123

} else if (styles.textAlign === 'right') {

1124

rtlStyles.textAlign = 'left';

1125

}

1126

1127

// Flip flex direction

1128

if (styles.flexDirection === 'row') {

1129

rtlStyles.flexDirection = 'row-reverse';

1130

} else if (styles.flexDirection === 'row-reverse') {

1131

rtlStyles.flexDirection = 'row';

1132

}

1133

1134

return rtlStyles;

1135

}

1136

1137

static useRTLLayout(locale) {

1138

const [isRTL, setIsRTL] = React.useState(false);

1139

1140

React.useEffect(() => {

1141

const direction = this.detectDirection(locale);

1142

const rtl = direction === 'rtl';

1143

1144

setIsRTL(rtl);

1145

this.setDocumentDirection(direction);

1146

}, [locale]);

1147

1148

return isRTL;

1149

}

1150

}

1151

1152

const styles = StyleSheet.create({

1153

container: {

1154

flex: 1,

1155

padding: 16

1156

},

1157

rtlContainer: {

1158

flexDirection: 'row-reverse'

1159

},

1160

title: {

1161

fontSize: 18,

1162

fontWeight: 'bold',

1163

marginBottom: 16

1164

},

1165

textContainer: {

1166

flexDirection: 'row',

1167

marginBottom: 8,

1168

alignItems: 'center'

1169

},

1170

rtlText: {

1171

flexDirection: 'row-reverse'

1172

},

1173

label: {

1174

fontWeight: 'bold',

1175

marginRight: 8

1176

},

1177

value: {

1178

flex: 1

1179

}

1180

});

1181

```

1182

1183

## Types

1184

1185

```javascript { .api }

1186

interface AppParameters {

1187

rootTag: Element;

1188

initialProps?: Object;

1189

hydrate?: boolean;

1190

mode?: 'legacy' | 'concurrent';

1191

callback?: () => void;

1192

}

1193

1194

interface AppConfig {

1195

appKey: string;

1196

component?: () => React.ComponentType;

1197

run?: Function;

1198

section?: boolean;

1199

}

1200

1201

type ComponentProviderInstrumentationHook = (component: () => React.ComponentType) => React.ComponentType;

1202

type WrapperComponentProvider = (any) => React.ComponentType;

1203

1204

type ColorSchemeName = 'light' | 'dark';

1205

1206

interface AppearancePreferences {

1207

colorScheme: ColorSchemeName;

1208

}

1209

1210

interface ShareContent {

1211

title?: string;

1212

message?: string;

1213

url?: string;

1214

}

1215

1216

interface ShareOptions {}

1217

1218

interface ShareResult {

1219

action: string;

1220

}

1221

1222

type VibratePattern = number | number[];

1223

1224

interface I18nConstants {

1225

isRTL: boolean;

1226

}

1227

1228

type AlertButton = {

1229

text: string;

1230

onPress?: () => void;

1231

style?: 'default' | 'cancel' | 'destructive';

1232

};

1233

1234

type AlertOptions = {

1235

cancelable?: boolean;

1236

onDismiss?: () => void;

1237

};

1238

1239

interface LinkingEventCallback {

1240

(event: { url: string }): void;

1241

}

1242

```