# @yandeu/js-bridge

TypeScript/JavaScript helper for communicating between a Flutter `WebView` and the page inside it. It provides a small, typed API for common app actions (fullscreen, status/navigation bar, orientation, storage, device/package info), plus optional plugins like vibration and in‑app browser.

## Installation

```bash
npm install @yandeu/js-bridge
```

## Quick Start

```ts
import { WebView } from "@yandeu/js-bridge";
// Optional plugins (import by path):
import { InAppBrowser } from "@yandeu/js-bridge/lib/plugins/inAppBrowser.js";
import { Vibration } from "@yandeu/js-bridge/lib/plugins/vibration.js";

async function init() {
  // Detect environment
  const platform = await WebView.getPlatform(); // 'android' | 'ios' | 'web' | 'unknown'
  if (!WebView.isReady) {
    console.log("Not running inside Flutter WebView");
    return;
  }

  // Status bar & navigation bar
  await WebView.statusBar.setColor("#000000");
  await WebView.statusBar.setIconsBrightness("light");
  await WebView.navigationBar.setColor("#000000");

  // Orientation
  WebView.orientation.setPortrait();

  // Persistent storage
  await WebView.persistentStorage.setItem("token", "abc123");
  const token = await WebView.persistentStorage.getItem("token");

  // Plugins
  await InAppBrowser.openUrl("https://example.com");
  Vibration.vibrate();
}

init();
```

## Core API

All core APIs are available on the singleton `WebView`.

- `WebView.isWebView: boolean` — true if the user agent matches Flutter WebView.
- `WebView.isReady: boolean` — set after bridge init when running in Flutter WebView.
- `WebView.getPlatform(): Promise<'android'|'ios'|'web'|'unknown'>` — platform detection via Flutter.

### Fullscreen

- `WebView.fullscreen.enter(): void`
- `WebView.fullscreen.exit(): void`

### Persistent Storage

- `persistentStorage.setItem(key: string, value: string): Promise<boolean>`
- `persistentStorage.getItem(key: string): Promise<string|null>`
- `persistentStorage.removeItem(key: string): Promise<boolean>`
- `persistentStorage.clear(): Promise<boolean>`

### Status Bar

- `statusBar.setColor(color: string): Promise<MessageResponse<{}>>` — color `#RRGGBB` or `#RRGGBBAA`.
- `statusBar.setIconsBrightness(brightness: 'light'|'dark'): Promise<MessageResponse<{}>>`

### Navigation Bar

- `navigationBar.setColor(color: string): Promise<MessageResponse<{}>>`

### Orientation

- `orientation.setLandscape(): void`
- `orientation.setPortrait(): void`

### App Lifecycle

- `exitApp(): void`

### Device & Package Info

- `deviceInfo(): Promise<MessageResponse<DeviceInfo>>`
- `packageInfo(): Promise<MessageResponse<PackageInfo>>`

### Events from Flutter

- `on(event: string, listener: (...args:any[]) => void): void` — subscribe to action events sent by Flutter (e.g., a back button action your Flutter side emits).
- `off(event: string, listener: (...args:any[]) => void): void`
- `offMany(events: string): void` — comma‑separated list of event names.

### Bridge Lifecycle

The bridge automatically initializes when you first import `WebView` if running inside a Flutter WebView. However, you can manually control the lifecycle:

#### Cleanup

```ts
import { WebView } from "@yandeu/js-bridge";

// When done with the bridge (e.g., unmounting component, navigating away)
WebView.destroy();
```

#### Reinitialization

```ts
import { WebView, communication } from "@yandeu/js-bridge";

// After calling destroy(), reinitialize if needed
communication.init();

// Now WebView and all plugins are ready to use again
if (WebView.isReady) {
  await WebView.statusBar.setColor("#000000");
}
```

## Plugins

Import plugins from `@yandeu/js-bridge/lib/plugins/*.js`.

### Vibration

```ts
import { Vibration } from "@yandeu/js-bridge/lib/plugins/vibration.js";

// Simple vibration (500ms default)
Vibration.vibrate();

// Custom duration (ms) and amplitude (1-255)
Vibration.vibrate(1000, 255);

// Custom pattern [wait, vibrate, wait, vibrate, ...] and optional intensities (0-255)
await Vibration.vibrateWithPattern([0, 500, 100, 500], [0, 255, 0, 128]);

// Check device capabilities
const hasVibrator = await Vibration.hasVibrator();
const hasAmplitude = await Vibration.hasAmplitudeControl();
const hasCustom = await Vibration.hasCustomVibrationsSupport();
```

### InAppBrowser

```ts
import { InAppBrowser } from "@yandeu/js-bridge/lib/plugins/inAppBrowser.js";
await InAppBrowser.openUrl("https://example.com");
```

### Ads

```ts
import { Ads } from "@yandeu/js-bridge/lib/plugins/ads.js";

// Set ad unit IDs once
Ads.banner.setAdUnitId("ca-app-pub-XXXX/YYYY");
Ads.interstitial.setAdUnitId("ca-app-pub-XXXX/ZZZZ");
Ads.rewarded.setAdUnitId("ca-app-pub-XXXX/WWWW");

// Banner
Ads.banner.show();
Ads.banner.dispose();

// Interstitial (resolves when the ad is dismissed)
const loaded = await Ads.interstitial.load();
if (loaded) {
  const dismissed = await Ads.interstitial.show();
  console.log("Ad dismissed:", dismissed);
}

// Rewarded (resolves when the ad is dismissed)
const rewardLoaded = await Ads.rewarded.load();
if (rewardLoaded) {
  const result = await Ads.rewarded.show();
  if (result.ok) {
    console.log("Reward amount:", result.amount);
  }
}

// Privacy
if (await Ads.isPrivacyOptionsRequired()) {
  Ads.presentPrivacyOptionsForm();
}
```

## Message Shapes & Responses

All request/response messages conform to these shapes:

```ts
export type MessageResponse<T extends Record<string, any>> =
  | { ok: true; payload: T }
  | { ok: false; errorMessage: string };
```

## Error Handling

- For async calls, check the returned `MessageResponse<T>`. When `ok` is `false`, an `errorMessage` is provided.
- Some convenience methods return `boolean` and log errors internally (e.g., persistent storage helpers).
