Documentation Index
Fetch the complete documentation index at: https://docs.go.gbgplc.com/llms.txt
Use this file to discover all available pages before exploring further.
Complete guide for using @gbgplc-internal/ggo-native-bridge-react in React applications.
Wrap your app (or the relevant subtree) with <BridgeProvider>:
import { BridgeProvider } from '@gbgplc-internal/ggo-native-bridge-react';
function App() {
return (
<BridgeProvider>
<YourApp />
</BridgeProvider>
);
}
The provider creates the NativeBridge singleton, auto-detects the host environment, discovers capabilities on mount, and makes the bridge available to all child components via context.
useBridge() — Access the bridge
useBridge() is the main hook for reading bridge state and reaching the underlying NativeBridge instance. It returns the environment, capability map, and helpers for capability checks:
import { useBridge } from '@gbgplc-internal/ggo-native-bridge-react';
function MyComponent() {
const {
bridge, // NativeBridge instance
environment, // 'ios' | 'android' | 'iframe' | 'standalone'
isEmbedded, // true if inside a host
capabilities, // CapabilityMap
capabilitiesReady, // true once discovery completes
hasCapability, // (id: string) => boolean
} = useBridge();
bridge.emit('journey.started', { timestamp: Date.now() });
}
Throws an Error if used outside a <BridgeProvider>.
Waiting for capabilities
function CapabilityGate({ children }: { children: React.ReactNode }) {
const { capabilitiesReady } = useBridge();
if (!capabilitiesReady) return <LoadingSpinner />;
return <>{children}</>;
}
useCapability(id) — Check a capability
Reactively check whether a specific capability is supported:
import { useCapability } from '@gbgplc-internal/ggo-native-bridge-react';
import { CAPABILITY_IDS } from '@gbgplc-internal/ggo-native-bridge';
function NfcCard() {
const { supported, ready, version } = useCapability(CAPABILITY_IDS.NFC_READ);
if (!ready) return <p>Checking NFC support...</p>;
if (!supported) {
return <p>NFC is not available on this device.</p>;
}
return (
<div>
<p>NFC ready (v{version})</p>
<button>Scan Passport</button>
</div>
);
}
useNativeCamera(type) — Camera capture
useNativeCamera() is a convenience hook that wraps the most common bridge request — a document or selfie capture — with the right capability check, action string, and timeout. It returns a flag for whether a native capture is available and a requestCapture() function you call when the user triggers capture:
import { useNativeCamera } from '@gbgplc-internal/ggo-native-bridge-react';
import { BridgeError, BridgeErrorCode } from '@gbgplc-internal/ggo-native-bridge';
function DocumentCapture() {
const { isNativeAvailable, requestCapture } = useNativeCamera('document');
async function handleCapture() {
if (!isNativeAvailable) {
openWebCamera();
return;
}
try {
const response = await requestCapture({
documentType: 'passport',
side: 'front',
});
processImage(response.data);
} catch (error) {
if (error instanceof BridgeError) {
if (error.code === BridgeErrorCode.CANCELLED) return;
if (error.recoverable) {
showRetryPrompt();
return;
}
}
showErrorMessage('Capture failed');
}
}
return (
<button onClick={handleCapture}>
{isNativeAvailable ? 'Capture with Native Camera' : 'Capture with Web Camera'}
</button>
);
}
Camera type mapping
Each type value maps to a specific bridge capability and capture action:
type | Capability checked | Action sent |
|---|
'document' | camera.document | camera.document.capture |
'selfie' | camera.selfie | camera.selfie.capture |
useNativeCamera works even without a <BridgeProvider>, returning isNativeAvailable: false. This makes it safe to use in components that may or may not have bridge access.
useBridgeEvent(action, callback) — Listen for host events
import { useBridgeEvent } from '@gbgplc-internal/ggo-native-bridge-react';
function HostEventListener() {
useBridgeEvent('host.navigation.back', (data) => {
navigateBack();
});
useBridgeEvent('host.theme.update', (data) => {
const theme = data.theme as Record<string, string>;
for (const [key, value] of Object.entries(theme)) {
document.documentElement.style.setProperty(key, value);
}
});
return null;
}
Key behaviours:
- Subscribes on mount, unsubscribes on unmount
- You do not need to wrap the callback in
useCallback — the hook uses a ref internally
- Resubscribes only if the
action string changes
Emitting events
function JourneyTracker() {
const { bridge } = useBridge();
useEffect(() => {
bridge.emit('journey.started', { journeyId: 'abc-123', timestamp: Date.now() });
return () => {
bridge.emit('journey.completed', { journeyId: 'abc-123', timestamp: Date.now() });
};
}, []);
return null;
}
Combining hooks
function VerificationStep() {
const { environment, hasCapability, bridge } = useBridge();
const { supported: hasDocCamera, ready } = useCapability('camera.document');
const { isNativeAvailable, requestCapture } = useNativeCamera('document');
useBridgeEvent('host.navigation.back', () => goToPreviousStep());
if (!ready) return <LoadingSpinner />;
return (
<div>
<p>Running in: {environment}</p>
{isNativeAvailable ? (
<button onClick={() => requestCapture({ side: 'front' })}>
Capture with Native Camera
</button>
) : (
<WebCamera />
)}
</div>
);
}
Testing
Use the environment and channel options to mock the bridge in tests:
import { render, screen } from '@testing-library/react';
import { BridgeProvider } from '@gbgplc-internal/ggo-native-bridge-react';
import { NativeBridge } from '@gbgplc-internal/ggo-native-bridge';
import type { BridgeMessage, MessageChannel } from '@gbgplc-internal/ggo-native-bridge';
function createMockChannel() {
let onMsg: ((msg: BridgeMessage) => void) | null = null;
const sent: BridgeMessage[] = [];
return {
channel: {
send(msg: BridgeMessage) { sent.push(msg); },
onMessage(cb: (msg: BridgeMessage) => void) { onMsg = cb; },
destroy() { onMsg = null; },
} satisfies MessageChannel,
sent,
simulateResponse(msg: BridgeMessage) { onMsg?.(msg); },
};
}
it('shows native camera button when capability exists', async () => {
const mock = createMockChannel();
render(
<BridgeProvider options={{ environment: 'ios', channel: mock.channel }}>
<DocumentCapture />
</BridgeProvider>,
);
mock.simulateResponse({
version: '1.0',
correlationId: mock.sent[0].correlationId,
type: 'response',
timestamp: Date.now(),
payload: {
action: 'capability.query',
status: 'success',
data: {
capabilities: {
'camera.document': { supported: true, version: '2.0' },
},
},
},
});
expect(await screen.findByText('Capture with Native Camera')).toBeTruthy();
});
afterEach(() => {
NativeBridge.resetInstance();
});