Skip to content

Commit ded8658

Browse files
committed
docs: add brownfield-navigation docs
1 parent 7b0be42 commit ded8658

6 files changed

Lines changed: 302 additions & 0 deletions

File tree

docs/docs/docs/api-reference/_meta.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
"name": "react-native-brownfield",
55
"label": "ReactNativeBrownfield"
66
},
7+
{
8+
"type": "dir",
9+
"name": "brownfield-navigation.mdx",
10+
"label": "BrownfieldNavigation"
11+
},
712
{
813
"type": "dir",
914
"name": "brownie",
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[
2+
{
3+
"type": "file",
4+
"name": "brownfield-navigation",
5+
"label": "Overview"
6+
},
7+
{
8+
"type": "file",
9+
"name": "setup-and-codegen",
10+
"label": "Setup and Codegen"
11+
},
12+
{
13+
"type": "file",
14+
"name": "native-integration",
15+
"label": "Native Integration"
16+
},
17+
{
18+
"type": "file",
19+
"name": "javascript-usage",
20+
"label": "JavaScript Usage"
21+
}
22+
]
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Brownfield Navigation
2+
3+
`@callstack/brownfield-navigation` lets React Native code call into your host app navigation.
4+
You define a TypeScript contract once, generate native bridge files, and implement that contract in Android/iOS delegates.
5+
6+
## How It Works
7+
8+
1. You create a `brownfield.navigation.ts` spec in your React Native app.
9+
2. You run `brownfield-navigation-codegen` to generate native bridge/delegate files.
10+
3. Native host code implements `BrownfieldNavigationDelegate`.
11+
4. You register the delegate at startup.
12+
5. JavaScript calls `BrownfieldNavigation.<method>()`.
13+
14+
## Guides
15+
16+
- [Setup and Codegen](/docs/api-reference/brownfield-navigation.mdx/setup-and-codegen)
17+
- [Native Integration](/docs/api-reference/brownfield-navigation.mdx/native-integration)
18+
- [JavaScript Usage](/docs/api-reference/brownfield-navigation.mdx/javascript-usage)
19+
20+
## Example Projects
21+
22+
Use these apps as end-to-end references:
23+
24+
- `apps/RNApp` for the spec file and JavaScript calls
25+
- `apps/AndroidApp` for Android delegate implementation
26+
- `apps/AppleApp` for iOS delegate implementation
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# JavaScript Usage
2+
3+
Use the generated JavaScript API after native delegate registration is complete.
4+
5+
## Import and call methods
6+
7+
```ts
8+
import BrownfieldNavigation from '@callstack/brownfield-navigation';
9+
10+
BrownfieldNavigation.navigateToSettings();
11+
BrownfieldNavigation.navigateToReferrals('user-123');
12+
```
13+
14+
## Example screen usage
15+
16+
```tsx
17+
import { Button, View } from 'react-native';
18+
import BrownfieldNavigation from '@callstack/brownfield-navigation';
19+
20+
export function NativeLinks() {
21+
return (
22+
<View>
23+
<Button
24+
title="Open native settings"
25+
onPress={() => BrownfieldNavigation.navigateToSettings()}
26+
/>
27+
<Button
28+
title="Open native referrals"
29+
onPress={() => BrownfieldNavigation.navigateToReferrals('user-123')}
30+
/>
31+
</View>
32+
);
33+
}
34+
```
35+
36+
## Best practices
37+
38+
- Keep JS method names aligned with actual native destinations.
39+
- Pass stable, explicit params (`userId`, IDs, flags) rather than derived UI state.
40+
- Add runtime guards in app startup so delegate registration always happens first.
41+
42+
## When to run codegen again
43+
44+
Rerun codegen if any of these change:
45+
46+
- Method names
47+
- Method parameters
48+
- Method return types
49+
50+
```bash
51+
yarn brownfield:navigation-codegen
52+
```
53+
54+
## Common errors
55+
56+
- **`undefined is not a function` on method call**:
57+
method was changed in spec, but app was not regenerated/rebuilt.
58+
- **Native crash on method call**:
59+
delegate was not registered before JS usage.
60+
- **Method exists but does nothing**:
61+
native delegate method was generated but not implemented in host app.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Native Integration
2+
3+
After codegen, implement the generated delegate interface in your host app and register it before JavaScript uses the module.
4+
5+
## Android
6+
7+
### 1) Implement `BrownfieldNavigationDelegate`
8+
9+
Implement the generated delegate methods in your host `Activity` (or another class with access to navigation context):
10+
11+
```kotlin
12+
import android.content.Intent
13+
import androidx.appcompat.app.AppCompatActivity
14+
import com.callstack.nativebrownfieldnavigation.BrownfieldNavigationDelegate
15+
16+
class MainActivity : AppCompatActivity(), BrownfieldNavigationDelegate {
17+
override fun navigateToSettings() {
18+
startActivity(Intent(this, SettingsActivity::class.java))
19+
}
20+
21+
override fun navigateToReferrals(userId: String) {
22+
startActivity(
23+
Intent(this, ReferralsActivity::class.java)
24+
.putExtra(ReferralsActivity.EXTRA_USER_ID, userId)
25+
)
26+
}
27+
}
28+
```
29+
30+
### 2) Register the delegate during startup
31+
32+
Register before any React Native screen can call `BrownfieldNavigation.*`:
33+
34+
```kotlin
35+
import android.os.Bundle
36+
import com.callstack.nativebrownfieldnavigation.BrownfieldNavigationManager
37+
38+
override fun onCreate(savedInstanceState: Bundle?) {
39+
super.onCreate(savedInstanceState)
40+
BrownfieldNavigationManager.setDelegate(this)
41+
// Initialize React Native host
42+
}
43+
```
44+
45+
## iOS
46+
47+
### 1) Implement `BrownfieldNavigationDelegate`
48+
49+
```swift
50+
import BrownfieldNavigation
51+
import SwiftUI
52+
import UIKit
53+
54+
public final class RNNavigationDelegate: BrownfieldNavigationDelegate {
55+
public func navigateToSettings() {
56+
present(SettingsScreen())
57+
}
58+
59+
public func navigateToReferrals(userId: String) {
60+
present(ReferralsScreen(userId: userId))
61+
}
62+
63+
private func present<Content: View>(_ view: Content) {
64+
DispatchQueue.main.async {
65+
let hostingController = UIHostingController(rootView: view)
66+
UIApplication.shared.topMostViewController()?
67+
.present(hostingController, animated: true)
68+
}
69+
}
70+
}
71+
```
72+
73+
### 2) Register the delegate at app startup
74+
75+
```swift
76+
import BrownfieldNavigation
77+
78+
@main
79+
struct BrownfieldAppleApp: App {
80+
init() {
81+
BrownfieldNavigationManager.shared.setDelegate(
82+
navigationDelegate: RNNavigationDelegate()
83+
)
84+
}
85+
}
86+
```
87+
88+
## Lifecycle Requirements
89+
90+
- Register delegate before rendering JS that might call the module.
91+
- Keep navigation on main/UI thread.
92+
- Re-register delegate if your host object is recreated.
93+
- Treat missing delegate as a startup bug: runtime calls require a registered delegate.
94+
95+
## Troubleshooting
96+
97+
- **Method added in TS but not visible natively**: rerun codegen and rebuild.
98+
- **Calls crash on app launch**: verify delegate registration happens before RN route rendering.
99+
- **Wrong screen opens**: check native delegate method wiring and params mapping.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Setup and Codegen
2+
3+
This guide covers the required setup to define your navigation contract and generate bridge files for `@callstack/brownfield-navigation`.
4+
5+
## Prerequisites
6+
7+
Before you start:
8+
9+
- Your React Native app has `@callstack/brownfield-navigation` installed.
10+
- Your app has Babel dependencies available (`@babel/core`, `@react-native/babel-preset`), which are used during codegen.
11+
- You know where your app root is (the folder containing your app `package.json`).
12+
13+
## 1) Create `brownfield.navigation.ts`
14+
15+
Create a new file named `brownfield.navigation.ts` in your React Native app root.
16+
17+
Example:
18+
19+
```ts
20+
// brownfield.navigation.ts
21+
export interface BrownfieldNavigationSpec {
22+
/**
23+
* Navigate to a native Settings screen.
24+
*/
25+
navigateToSettings(): void;
26+
27+
/**
28+
* Navigate to a native Referrals screen.
29+
*/
30+
navigateToReferrals(userId: string): void;
31+
}
32+
```
33+
34+
### Supported method signatures
35+
36+
- Method name: any valid TypeScript identifier.
37+
- Params: typed and optional params are supported (for example `userId?: string`).
38+
- Return type: `void` is the common and recommended type for navigation actions.
39+
- Interface name: `BrownfieldNavigationSpec` (or `Spec`) is supported by the parser.
40+
41+
:::info
42+
Prefer simple synchronous navigation methods (`void`).
43+
:::
44+
45+
## 2) Add a codegen script
46+
47+
Add a script to your app `package.json`:
48+
49+
```json
50+
{
51+
"scripts": {
52+
"brownfield:navigation-codegen": "brownfield-navigation-codegen brownfield.navigation.ts"
53+
}
54+
}
55+
```
56+
57+
## 3) Run codegen
58+
59+
From your app root:
60+
61+
```bash
62+
yarn brownfield:navigation-codegen
63+
```
64+
65+
## 4) What gets generated
66+
67+
Codegen updates `@callstack/brownfield-navigation` with your contract:
68+
69+
- `src/NativeBrownfieldNavigation.ts` (TurboModule spec)
70+
- `src/index.ts` (JavaScript API surface)
71+
- `ios/BrownfieldNavigationDelegate.swift` (delegate protocol)
72+
- `ios/NativeBrownfieldNavigation.mm` (native module implementation)
73+
- Android delegate/module files under:
74+
`android/src/main/java/com/callstack/nativebrownfieldnavigation/`
75+
76+
## 5) Regenerate when contract changes
77+
78+
Any time you add, remove, or rename methods in `brownfield.navigation.ts`, rerun:
79+
80+
```bash
81+
yarn brownfield:navigation-codegen
82+
```
83+
84+
Then recompile native apps.
85+
86+
## Next
87+
88+
- Continue with [Native Integration](/docs/api-reference/brownfield-navigation.mdx/native-integration)
89+
- Then wire JS calls from [JavaScript Usage](/docs/api-reference/brownfield-navigation.mdx/javascript-usage)

0 commit comments

Comments
 (0)