@take-out/docs 0.0.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/aggregates.md +584 -0
- package/cloudflare-dev-tunnel.md +41 -0
- package/database.md +229 -0
- package/docs.md +8 -0
- package/emitters.md +562 -0
- package/hot-updater.md +223 -0
- package/native-hot-update.md +252 -0
- package/one-components.md +234 -0
- package/one-hooks.md +570 -0
- package/one-routes.md +660 -0
- package/package-json.md +115 -0
- package/package.json +12 -0
- package/react-native-navigation-flow.md +184 -0
- package/scripts.md +147 -0
- package/sync-prompt.md +208 -0
- package/tamagui.md +478 -0
- package/testing-integration.md +564 -0
- package/triggers.md +450 -0
- package/xcodebuild-mcp.md +127 -0
- package/zero.md +719 -0
package/hot-updater.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hot-updater
|
|
3
|
+
description: Guide for implementing OTA updates and hot updates in React Native apps. INVOKE WHEN: hot updater, OTA updates, over-the-air updates, app updates, code push, deploy updates, @hot-updater/react-native, HotUpdaterProvider, useHotUpdater, update deployment.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Hot Updater Guide
|
|
7
|
+
|
|
8
|
+
This guide covers the hot update system for delivering over-the-air (OTA)
|
|
9
|
+
updates to React Native applications.
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
The hot updater system allows you to push JavaScript bundle updates to deployed
|
|
14
|
+
React Native apps without going through the app store review process. This
|
|
15
|
+
enables rapid bug fixes and feature deployments.
|
|
16
|
+
|
|
17
|
+
## Architecture
|
|
18
|
+
|
|
19
|
+
### Components
|
|
20
|
+
|
|
21
|
+
1. **@hot-updater/react-native** - React Native client library
|
|
22
|
+
2. **HotUpdaterProvider** - React context provider for update management
|
|
23
|
+
3. **Feature Flags** - Remote configuration via PostHog
|
|
24
|
+
4. **Update Server** - Hosts update bundles (configurable via feature flag)
|
|
25
|
+
|
|
26
|
+
## Setup
|
|
27
|
+
|
|
28
|
+
### Installation
|
|
29
|
+
|
|
30
|
+
The hot-updater package is already installed:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
bun add @hot-updater/react-native
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Configuration
|
|
37
|
+
|
|
38
|
+
In `app.config.ts`:
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
{
|
|
42
|
+
expo: {
|
|
43
|
+
version: "0.0.6",
|
|
44
|
+
runtimeVersion: version, // Required for appVersion strategy
|
|
45
|
+
plugins: [
|
|
46
|
+
[
|
|
47
|
+
"@hot-updater/react-native",
|
|
48
|
+
{
|
|
49
|
+
channel: APP_VARIANT, // development, preview, or production
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Feature Flags
|
|
58
|
+
|
|
59
|
+
Two feature flags control hot updates:
|
|
60
|
+
|
|
61
|
+
1. **ENABLE_HOT_UPDATES** - Boolean flag to enable/disable hot updates
|
|
62
|
+
2. **HOT_UPDATE_SERVER_URL** - Dynamic config for update server URL
|
|
63
|
+
|
|
64
|
+
Configure these in PostHog or your feature flag service.
|
|
65
|
+
|
|
66
|
+
## Implementation
|
|
67
|
+
|
|
68
|
+
### Provider Setup
|
|
69
|
+
|
|
70
|
+
Wrap your app with the HotUpdaterProvider:
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import { HotUpdaterProvider } from '~/features/hot-updater'
|
|
74
|
+
|
|
75
|
+
function App() {
|
|
76
|
+
return <HotUpdaterProvider>{/* Your app components */}</HotUpdaterProvider>
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Update Notification UI
|
|
81
|
+
|
|
82
|
+
Add the notification component to show update prompts:
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
import { HotUpdaterNotification } from '~/features/hot-updater'
|
|
86
|
+
|
|
87
|
+
function AppLayout() {
|
|
88
|
+
return (
|
|
89
|
+
<>
|
|
90
|
+
{/* Your app content */}
|
|
91
|
+
<HotUpdaterNotification />
|
|
92
|
+
</>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Using the Hook
|
|
98
|
+
|
|
99
|
+
Access hot updater functionality in components:
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
import { useHotUpdater } from '~/features/hot-updater'
|
|
103
|
+
|
|
104
|
+
function SettingsScreen() {
|
|
105
|
+
const {
|
|
106
|
+
isUpdateAvailable,
|
|
107
|
+
isDownloading,
|
|
108
|
+
downloadProgress,
|
|
109
|
+
checkForUpdate,
|
|
110
|
+
applyUpdate,
|
|
111
|
+
lastCheckTime,
|
|
112
|
+
} = useHotUpdater()
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<View>
|
|
116
|
+
{isUpdateAvailable && <Button onPress={applyUpdate}>Apply Update</Button>}
|
|
117
|
+
|
|
118
|
+
<Button onPress={checkForUpdate}>Check for Updates</Button>
|
|
119
|
+
|
|
120
|
+
{lastCheckTime && (
|
|
121
|
+
<Text>Last checked: {lastCheckTime.toLocaleString()}</Text>
|
|
122
|
+
)}
|
|
123
|
+
</View>
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Update Strategy
|
|
129
|
+
|
|
130
|
+
### Version Management
|
|
131
|
+
|
|
132
|
+
The app uses the "appVersion" strategy:
|
|
133
|
+
|
|
134
|
+
- Runtime version matches app version (e.g., "0.0.6")
|
|
135
|
+
- Updates are compatible within the same runtime version
|
|
136
|
+
- Native changes require a new app store release
|
|
137
|
+
|
|
138
|
+
### Channels
|
|
139
|
+
|
|
140
|
+
Updates are distributed through channels based on APP_VARIANT:
|
|
141
|
+
|
|
142
|
+
- **development** - For development builds
|
|
143
|
+
- **preview** - For staging/preview builds
|
|
144
|
+
- **production** - For production releases
|
|
145
|
+
|
|
146
|
+
### Update Check Frequency
|
|
147
|
+
|
|
148
|
+
- On app launch
|
|
149
|
+
- When app returns to foreground
|
|
150
|
+
- Every 30 minutes while app is active
|
|
151
|
+
- Manual check via UI
|
|
152
|
+
|
|
153
|
+
## Deployment
|
|
154
|
+
|
|
155
|
+
### Creating an Update
|
|
156
|
+
|
|
157
|
+
1. Make JavaScript/asset changes (no native code changes)
|
|
158
|
+
2. Build the update bundle:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
eas update --branch [branch-name] --message "[update message]"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
3. The update is automatically distributed to devices
|
|
165
|
+
|
|
166
|
+
### Update Server
|
|
167
|
+
|
|
168
|
+
Configure the update server URL via the HOT_UPDATE_SERVER_URL feature flag. The
|
|
169
|
+
default server handles:
|
|
170
|
+
|
|
171
|
+
- Bundle hosting
|
|
172
|
+
- Version compatibility checks
|
|
173
|
+
- Channel-based distribution
|
|
174
|
+
- Download progress tracking
|
|
175
|
+
|
|
176
|
+
## Monitoring
|
|
177
|
+
|
|
178
|
+
### Analytics Events
|
|
179
|
+
|
|
180
|
+
The system tracks these events via PostHog:
|
|
181
|
+
|
|
182
|
+
- `hot_update_available` - Update detected
|
|
183
|
+
- `hot_update_downloaded` - Update downloaded successfully
|
|
184
|
+
- `hot_update_check_error` - Error checking for updates
|
|
185
|
+
- `hot_update_apply_error` - Error applying update
|
|
186
|
+
|
|
187
|
+
### Debugging
|
|
188
|
+
|
|
189
|
+
Enable verbose logging:
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
// In development
|
|
193
|
+
console.info('Hot updates enabled:', isEnabled)
|
|
194
|
+
console.info('Server URL:', serverUrl)
|
|
195
|
+
console.info('Current version:', Updates.currentVersion)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Best Practices
|
|
199
|
+
|
|
200
|
+
### Do's
|
|
201
|
+
|
|
202
|
+
1. **Test updates thoroughly** in development/preview channels first
|
|
203
|
+
2. **Use feature flags** to control rollout
|
|
204
|
+
3. **Monitor analytics** after deploying updates
|
|
205
|
+
4. **Keep updates small** - large bundles take longer to download
|
|
206
|
+
5. **Version native changes** properly with runtime version bumps
|
|
207
|
+
|
|
208
|
+
### Don'ts
|
|
209
|
+
|
|
210
|
+
1. **Don't include native changes** in hot updates
|
|
211
|
+
2. **Don't skip testing** in preview environments
|
|
212
|
+
3. **Don't force updates** without user consent
|
|
213
|
+
4. **Don't update during critical user operations**
|
|
214
|
+
5. **Don't ignore error tracking**
|
|
215
|
+
|
|
216
|
+
## Rollback Strategy
|
|
217
|
+
|
|
218
|
+
If an update causes issues:
|
|
219
|
+
|
|
220
|
+
1. **Disable via feature flag** - Turn off ENABLE_HOT_UPDATES
|
|
221
|
+
2. **Deploy fix** - Create and test a fix
|
|
222
|
+
3. **Roll forward** - Deploy the fix as a new update
|
|
223
|
+
4. **Monitor** - Track analytics to ensure issues are resolved
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: native-hot-update
|
|
3
|
+
description: Native hot update (OTA/over-the-air) system guide for @take-out/native-hot-update. Use for HotUpdaterSplash, splash screen, deploy-hot-update scripts, update issues, or troubleshooting OTA updates.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Native Hot Update System
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
The app uses hot updates to deploy code changes to production without requiring
|
|
11
|
+
app store submissions. Updates are checked on app start and applied
|
|
12
|
+
automatically or after user confirmation.
|
|
13
|
+
|
|
14
|
+
## Architecture
|
|
15
|
+
|
|
16
|
+
### Package
|
|
17
|
+
|
|
18
|
+
Located at packages/native-hot-update, this is a reusable package that provides:
|
|
19
|
+
|
|
20
|
+
- Instance-based API via createHotUpdater()
|
|
21
|
+
- Pluggable storage interface (get/set/delete)
|
|
22
|
+
- Timeout protection (5s soft, 20s hard)
|
|
23
|
+
- Progress tracking during downloads
|
|
24
|
+
- Alert handling for critical updates
|
|
25
|
+
|
|
26
|
+
### Integration
|
|
27
|
+
|
|
28
|
+
Located at src/features/hot-updater, this integrates the package with the app:
|
|
29
|
+
|
|
30
|
+
- useHotUpdater hook with PostHog feature flags
|
|
31
|
+
- HotUpdaterSplash component for app initialization
|
|
32
|
+
- Analytics tracking for update events
|
|
33
|
+
|
|
34
|
+
## Update Flow
|
|
35
|
+
|
|
36
|
+
### On App Start
|
|
37
|
+
|
|
38
|
+
1. HotUpdaterSplash component renders
|
|
39
|
+
2. useHotUpdater hook checks PostHog feature flags
|
|
40
|
+
3. If enabled, queries update server for available updates
|
|
41
|
+
4. Shows splash screen during download with progress indicator
|
|
42
|
+
5. After timeout or completion, displays app content
|
|
43
|
+
|
|
44
|
+
### Update Types
|
|
45
|
+
|
|
46
|
+
Critical updates reload immediately if user hasn't accessed the app yet. If the
|
|
47
|
+
user is already in the app, an alert prompts them to reload now or later.
|
|
48
|
+
|
|
49
|
+
Non-critical updates download silently and apply on the next app restart.
|
|
50
|
+
|
|
51
|
+
Rollback updates check if a pre-release bundle is active and skip if the current
|
|
52
|
+
version is newer.
|
|
53
|
+
|
|
54
|
+
## Configuration
|
|
55
|
+
|
|
56
|
+
### Feature Flags
|
|
57
|
+
|
|
58
|
+
Controlled via PostHog:
|
|
59
|
+
|
|
60
|
+
- ENABLE_HOT_UPDATES: Master on/off switch
|
|
61
|
+
- HOT_UPDATE_SERVER_URL: Server endpoint for updates
|
|
62
|
+
|
|
63
|
+
### Environment
|
|
64
|
+
|
|
65
|
+
Required variables in .env:
|
|
66
|
+
|
|
67
|
+
- HOT_UPDATER_SUPABASE_URL
|
|
68
|
+
- HOT_UPDATER_SUPABASE_ANON_KEY
|
|
69
|
+
- HOT_UPDATER_SUPABASE_BUCKET_NAME
|
|
70
|
+
|
|
71
|
+
### Update Strategy
|
|
72
|
+
|
|
73
|
+
Uses appVersion strategy, which requires runtimeVersion set in app.config.ts to
|
|
74
|
+
match the version field.
|
|
75
|
+
|
|
76
|
+
## Deployment
|
|
77
|
+
|
|
78
|
+
### Manual
|
|
79
|
+
|
|
80
|
+
Run deployment scripts for specific platforms:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
bun deploy-hot-update:ios
|
|
84
|
+
bun deploy-hot-update:android
|
|
85
|
+
bun deploy-hot-update
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Automated
|
|
89
|
+
|
|
90
|
+
Two GitHub Actions workflows handle deployments.
|
|
91
|
+
|
|
92
|
+
Manual deployment via Actions tab:
|
|
93
|
+
- Workflow: deploy-hot-update.yml
|
|
94
|
+
- Choose platform, channel, and critical flag
|
|
95
|
+
- Triggered manually from GitHub Actions UI
|
|
96
|
+
|
|
97
|
+
Automatic deployment after CI success:
|
|
98
|
+
- Workflow: auto-deploy-hot-update.yml
|
|
99
|
+
- Runs when CI completes on main branch
|
|
100
|
+
- Deploys to production-pre channel
|
|
101
|
+
- Non-critical updates only
|
|
102
|
+
|
|
103
|
+
Required GitHub secrets:
|
|
104
|
+
- HOT_UPDATER_SUPABASE_URL
|
|
105
|
+
- HOT_UPDATER_SUPABASE_ANON_KEY
|
|
106
|
+
- HOT_UPDATER_SUPABASE_BUCKET_NAME
|
|
107
|
+
|
|
108
|
+
### Channels
|
|
109
|
+
|
|
110
|
+
- production-pre: Pre-release testing channel
|
|
111
|
+
- production: Stable release channel
|
|
112
|
+
|
|
113
|
+
## Usage
|
|
114
|
+
|
|
115
|
+
### Basic Integration
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import { HotUpdaterSplash } from '~/features/hot-updater/HotUpdaterSplash'
|
|
119
|
+
|
|
120
|
+
export function Layout() {
|
|
121
|
+
return (
|
|
122
|
+
<HotUpdaterSplash>
|
|
123
|
+
<App />
|
|
124
|
+
</HotUpdaterSplash>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The component handles update checks automatically and shows a splash screen
|
|
130
|
+
during downloads.
|
|
131
|
+
|
|
132
|
+
### Custom Behavior
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { useHotUpdater } from '~/features/hot-updater/useHotUpdater'
|
|
136
|
+
|
|
137
|
+
export function CustomUpdater() {
|
|
138
|
+
const { userClearedForAccess, progress } = useHotUpdater()
|
|
139
|
+
|
|
140
|
+
if (!userClearedForAccess) {
|
|
141
|
+
return <CustomSplash progress={progress} />
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return <App />
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Debugging
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
import { hotUpdater } from '@take-out/native-hot-update'
|
|
152
|
+
|
|
153
|
+
console.info('Applied OTA:', hotUpdater.getAppliedOta())
|
|
154
|
+
console.info('Short ID:', hotUpdater.getShortOtaId())
|
|
155
|
+
console.info('Channel:', hotUpdater.getChannel())
|
|
156
|
+
console.info('Pending:', hotUpdater.getIsUpdatePending())
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Alert Behavior
|
|
160
|
+
|
|
161
|
+
### Critical Updates
|
|
162
|
+
|
|
163
|
+
Before user accesses app: Reloads automatically After user accesses app: Shows
|
|
164
|
+
alert with "Later" and "Reload Now" options
|
|
165
|
+
|
|
166
|
+
### Non-Critical Updates
|
|
167
|
+
|
|
168
|
+
No alerts shown. Updates apply silently on next app restart.
|
|
169
|
+
|
|
170
|
+
### Rollback Protection
|
|
171
|
+
|
|
172
|
+
If using a pre-release bundle and a rollback is detected, shows alert: "Update
|
|
173
|
+
Skipped - Skipped rollback because you are using a newer pre-release bundle."
|
|
174
|
+
|
|
175
|
+
## Storage
|
|
176
|
+
|
|
177
|
+
The package uses a pluggable storage interface. The app provides MMKV storage:
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
import { MMKV } from 'react-native-mmkv'
|
|
181
|
+
import { createMMKVStorage } from '@take-out/native-hot-update/mmkv'
|
|
182
|
+
|
|
183
|
+
const mmkv = new MMKV({ id: 'hot-updater' })
|
|
184
|
+
const storage = createMMKVStorage(mmkv)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Storage persists:
|
|
188
|
+
|
|
189
|
+
- Bundle IDs per app version
|
|
190
|
+
- Pre-release bundle markers
|
|
191
|
+
- Update state across app restarts
|
|
192
|
+
|
|
193
|
+
## Analytics
|
|
194
|
+
|
|
195
|
+
Update events are automatically tracked via PostHog:
|
|
196
|
+
|
|
197
|
+
- ota_update_downloaded: When update completes
|
|
198
|
+
- ota_update_error: When update fails
|
|
199
|
+
|
|
200
|
+
Event properties include bundle ID, critical flag, file URL, and error details.
|
|
201
|
+
|
|
202
|
+
## Timeout Protection
|
|
203
|
+
|
|
204
|
+
Soft timeout at 5 seconds: Shows app if no update is downloading Hard timeout at
|
|
205
|
+
20 seconds: Always shows app regardless of update state
|
|
206
|
+
|
|
207
|
+
This prevents slow servers or network issues from blocking user access.
|
|
208
|
+
|
|
209
|
+
## Build Configuration
|
|
210
|
+
|
|
211
|
+
The hot-updater.config.ts file at the project root configures:
|
|
212
|
+
|
|
213
|
+
- Build adapter: bare (with Hermes enabled)
|
|
214
|
+
- Storage: Supabase
|
|
215
|
+
- Database: Supabase
|
|
216
|
+
- Update strategy: appVersion
|
|
217
|
+
|
|
218
|
+
## Platform Support
|
|
219
|
+
|
|
220
|
+
iOS and Android both supported. Web is a no-op (splash component renders
|
|
221
|
+
children immediately).
|
|
222
|
+
|
|
223
|
+
Updates are deployed per platform and can be triggered independently.
|
|
224
|
+
|
|
225
|
+
## Security
|
|
226
|
+
|
|
227
|
+
Updates are served via Supabase with configured access controls. The anon key is
|
|
228
|
+
used for read access to the update bundles.
|
|
229
|
+
|
|
230
|
+
Pre-release updates use a separate channel and are marked in storage to prevent
|
|
231
|
+
accidental rollbacks.
|
|
232
|
+
|
|
233
|
+
## Troubleshooting
|
|
234
|
+
|
|
235
|
+
### Updates not applying
|
|
236
|
+
|
|
237
|
+
Check feature flags in PostHog, verify server URL is configured, confirm
|
|
238
|
+
.env.hotupdater has correct credentials.
|
|
239
|
+
|
|
240
|
+
### Splash screen stuck
|
|
241
|
+
|
|
242
|
+
Check network connectivity, verify server is responding, review timeout logs.
|
|
243
|
+
|
|
244
|
+
### Wrong version shown
|
|
245
|
+
|
|
246
|
+
Use hotUpdater.getAppliedOta() to check current bundle, compare with server to
|
|
247
|
+
verify latest version is available.
|
|
248
|
+
|
|
249
|
+
## References
|
|
250
|
+
|
|
251
|
+
- Package README: packages/native-hot-update/README.md
|
|
252
|
+
- Integration guide: packages/native-hot-update/INTEGRATION.md
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: one-components
|
|
3
|
+
description: One framework components guide for navigation, layouts, and UI elements. INVOKE WHEN: Link, Redirect, navigation, Head, meta tags, SEO, SafeAreaView, StatusBar, device safe areas, Stack, Tabs, Slot, layout components, LoadProgressBar, ScrollBehavior.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# one framework: components
|
|
7
|
+
|
|
8
|
+
comprehensive guide to built-in components in one framework for navigation,
|
|
9
|
+
layouts, and ui enhancements.
|
|
10
|
+
|
|
11
|
+
## navigation components
|
|
12
|
+
|
|
13
|
+
### Link
|
|
14
|
+
|
|
15
|
+
type-safe navigation component for both web and native.
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { Link } from 'one'
|
|
19
|
+
|
|
20
|
+
<Link href="/blog">go to blog</Link>
|
|
21
|
+
<Link href="/blog/post" replace>replace history</Link>
|
|
22
|
+
<Link href="https://example.com" target="_blank">external</Link>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**props:**
|
|
26
|
+
|
|
27
|
+
- `href` (required): typed route path
|
|
28
|
+
- `asChild`: forward props to child component
|
|
29
|
+
- `replace`: replace history instead of push
|
|
30
|
+
- `push`: explicitly push to history
|
|
31
|
+
- `className`: web class, native css interop
|
|
32
|
+
- `target`: web-only (\_blank, \_self, \_top, \_parent)
|
|
33
|
+
- `rel`: web-only (nofollow, noopener, noreferrer, etc.)
|
|
34
|
+
- `download`: web-only download attribute
|
|
35
|
+
|
|
36
|
+
**examples:**
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
// basic navigation
|
|
40
|
+
<Link href="/home/profile">view profile</Link>
|
|
41
|
+
|
|
42
|
+
// dynamic routes (type-safe)
|
|
43
|
+
<Link href={`/user/${userId}`}>user page</Link>
|
|
44
|
+
|
|
45
|
+
// replace history
|
|
46
|
+
<Link href="/login" replace>login</Link>
|
|
47
|
+
|
|
48
|
+
// external link
|
|
49
|
+
<Link href="https://github.com" target="_blank" rel="noopener">
|
|
50
|
+
github
|
|
51
|
+
</Link>
|
|
52
|
+
|
|
53
|
+
// as child (forward to custom component)
|
|
54
|
+
<Link href="/about" asChild>
|
|
55
|
+
<CustomButton>about us</CustomButton>
|
|
56
|
+
</Link>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Redirect
|
|
60
|
+
|
|
61
|
+
redirects when route is focused. uses `useFocusEffect` internally.
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import { Redirect } from 'one'
|
|
65
|
+
|
|
66
|
+
export default function Page() {
|
|
67
|
+
const { isAuthenticated } = useAuth()
|
|
68
|
+
|
|
69
|
+
if (!isAuthenticated) {
|
|
70
|
+
return <Redirect href="/login" />
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return <Content />
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**props:**
|
|
78
|
+
|
|
79
|
+
- `href`: destination route
|
|
80
|
+
|
|
81
|
+
**note:** prefer using `~/interface/Link` over One's Link component in this project.
|
|
82
|
+
|
|
83
|
+
## ui components
|
|
84
|
+
|
|
85
|
+
### Head
|
|
86
|
+
|
|
87
|
+
control `<head>` on web and app meta on native.
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
import { Head } from 'one'
|
|
91
|
+
|
|
92
|
+
export default function Page() {
|
|
93
|
+
return (
|
|
94
|
+
<>
|
|
95
|
+
<Head>
|
|
96
|
+
<title>my page title</title>
|
|
97
|
+
<meta name="description" content="page description" />
|
|
98
|
+
<meta property="og:image" content="/og-image.png" />
|
|
99
|
+
</Head>
|
|
100
|
+
<Content />
|
|
101
|
+
</>
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
can be used in any route or component. web: renders into `<head>`, native:
|
|
107
|
+
controls app metadata.
|
|
108
|
+
|
|
109
|
+
### SafeAreaView
|
|
110
|
+
|
|
111
|
+
re-exports from `react-native-safe-area-context`. respects device safe areas
|
|
112
|
+
(notches, status bars).
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
import { SafeAreaView } from 'one'
|
|
116
|
+
|
|
117
|
+
export default function Page() {
|
|
118
|
+
return (
|
|
119
|
+
<SafeAreaView edges={['top', 'left', 'right']}>
|
|
120
|
+
<Content />
|
|
121
|
+
</SafeAreaView>
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**props:**
|
|
127
|
+
|
|
128
|
+
- `edges`: array of edges to apply safe area ('top' | 'bottom' | 'left' |
|
|
129
|
+
'right')
|
|
130
|
+
|
|
131
|
+
one uses `SafeAreaProvider` from react navigation automatically.
|
|
132
|
+
|
|
133
|
+
### LoadProgressBar
|
|
134
|
+
|
|
135
|
+
web-only loading bar during page transitions.
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
// app/_layout.tsx
|
|
139
|
+
import { LoadProgressBar, Slot } from 'one'
|
|
140
|
+
|
|
141
|
+
export default function Layout() {
|
|
142
|
+
return (
|
|
143
|
+
<>
|
|
144
|
+
<LoadProgressBar
|
|
145
|
+
startDelay={100}
|
|
146
|
+
finishDelay={100}
|
|
147
|
+
initialPercent={20}
|
|
148
|
+
updateInterval={100}
|
|
149
|
+
sporadicness={0.3}
|
|
150
|
+
/>
|
|
151
|
+
<Slot />
|
|
152
|
+
</>
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**props:**
|
|
158
|
+
|
|
159
|
+
- `startDelay`: delay before showing (ms)
|
|
160
|
+
- `finishDelay`: delay before hiding (ms)
|
|
161
|
+
- `initialPercent`: starting percentage (0-100)
|
|
162
|
+
- `updateInterval`: update frequency (ms)
|
|
163
|
+
- `sporadicness`: randomness factor (0-1)
|
|
164
|
+
|
|
165
|
+
### ScrollBehavior
|
|
166
|
+
|
|
167
|
+
automatic scroll restoration for web. resets to top on new page, restores
|
|
168
|
+
position on back/forward.
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
// app/_layout.tsx
|
|
172
|
+
import { ScrollBehavior, Slot } from 'one'
|
|
173
|
+
|
|
174
|
+
export default function Layout() {
|
|
175
|
+
return (
|
|
176
|
+
<>
|
|
177
|
+
<ScrollBehavior />
|
|
178
|
+
<Slot />
|
|
179
|
+
</>
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**props:**
|
|
185
|
+
|
|
186
|
+
- `disabled`: boolean | 'restore' - disable completely or only restoration
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
// disable restoration, keep reset behavior
|
|
190
|
+
<ScrollBehavior disabled="restore" />
|
|
191
|
+
|
|
192
|
+
// disable completely
|
|
193
|
+
<ScrollBehavior disabled={true} />
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## practical patterns
|
|
197
|
+
|
|
198
|
+
### safe area with scroll
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
import { SafeAreaView, ScrollView } from 'one'
|
|
202
|
+
|
|
203
|
+
export default function Page() {
|
|
204
|
+
return (
|
|
205
|
+
<SafeAreaView edges={['top']} style={{ flex: 1 }}>
|
|
206
|
+
<ScrollView>
|
|
207
|
+
<Content />
|
|
208
|
+
</ScrollView>
|
|
209
|
+
</SafeAreaView>
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### progressive loading indicator
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
// app/_layout.tsx
|
|
218
|
+
import { LoadProgressBar, Slot } from 'one'
|
|
219
|
+
|
|
220
|
+
export default function Layout() {
|
|
221
|
+
return (
|
|
222
|
+
<>
|
|
223
|
+
<LoadProgressBar
|
|
224
|
+
startDelay={200} // wait 200ms before showing
|
|
225
|
+
finishDelay={300} // wait 300ms before hiding
|
|
226
|
+
initialPercent={30} // start at 30%
|
|
227
|
+
updateInterval={80} // update every 80ms
|
|
228
|
+
sporadicness={0.4} // moderate randomness
|
|
229
|
+
/>
|
|
230
|
+
<Slot />
|
|
231
|
+
</>
|
|
232
|
+
)
|
|
233
|
+
}
|
|
234
|
+
```
|