react-native-permission-handler 0.1.0
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/LICENSE +21 -0
- package/README.md +407 -0
- package/dist/index.d.mts +146 -0
- package/dist/index.d.ts +146 -0
- package/dist/index.js +598 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +577 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +75 -0
- package/src/components/default-blocked-prompt.tsx +76 -0
- package/src/components/default-pre-prompt.tsx +87 -0
- package/src/components/permission-gate.tsx +105 -0
- package/src/core/state-machine.test.ts +234 -0
- package/src/core/state-machine.ts +87 -0
- package/src/hooks/use-multiple-permissions.test.ts +167 -0
- package/src/hooks/use-multiple-permissions.ts +196 -0
- package/src/hooks/use-permission-handler.test.ts +210 -0
- package/src/hooks/use-permission-handler.ts +158 -0
- package/src/index.ts +22 -0
- package/src/types.ts +114 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Radu Ghitescu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
# react-native-permission-handler
|
|
2
|
+
|
|
3
|
+
Smart permission UX flows for React Native. Pre-prompts, blocked handling, settings redirect, and foreground re-check — in one hook.
|
|
4
|
+
|
|
5
|
+
Built on [`react-native-permissions`](https://github.com/zoontek/react-native-permissions).
|
|
6
|
+
|
|
7
|
+
## Why
|
|
8
|
+
|
|
9
|
+
Every React Native app that uses device features needs runtime permissions. The low-level check/request API is solved by `react-native-permissions`. But the **UX flow** — pre-prompts, blocked state recovery, settings redirect, foreground re-check — is not. Every team builds the same 150+ lines of boilerplate for every permission, in every project.
|
|
10
|
+
|
|
11
|
+
This library handles the full flow in a single hook call.
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install react-native-permission-handler react-native-permissions
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Set up `react-native-permissions` for your platform ([iOS](https://github.com/zoontek/react-native-permissions#ios) / [Android](https://github.com/zoontek/react-native-permissions#android) / [Expo](https://github.com/zoontek/react-native-permissions#expo)).
|
|
20
|
+
|
|
21
|
+
Then:
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { usePermissionHandler } from "react-native-permission-handler";
|
|
25
|
+
import { PERMISSIONS } from "react-native-permissions";
|
|
26
|
+
|
|
27
|
+
function QRScannerScreen() {
|
|
28
|
+
const camera = usePermissionHandler({
|
|
29
|
+
permission: PERMISSIONS.IOS.CAMERA,
|
|
30
|
+
prePrompt: {
|
|
31
|
+
title: "Camera Access",
|
|
32
|
+
message: "We need your camera to scan QR codes.",
|
|
33
|
+
},
|
|
34
|
+
blockedPrompt: {
|
|
35
|
+
title: "Camera Blocked",
|
|
36
|
+
message: "Please enable camera in Settings.",
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (camera.isChecking) return <LoadingSpinner />;
|
|
41
|
+
if (camera.isGranted) return <QRScanner />;
|
|
42
|
+
if (camera.isUnavailable) return <Text>Camera not available.</Text>;
|
|
43
|
+
|
|
44
|
+
// Pre-prompt and blocked modals are rendered by the hook's
|
|
45
|
+
// default UI. Or build your own using camera.state.
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
That's it. The hook handles checking on mount, showing a pre-prompt before the system dialog, detecting blocked state, opening Settings, re-checking when the app returns, and firing callbacks.
|
|
51
|
+
|
|
52
|
+
## State Machine
|
|
53
|
+
|
|
54
|
+
The core of the library is a pure state machine that drives the entire permission flow:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
+-------+
|
|
58
|
+
| idle |
|
|
59
|
+
+---+---+
|
|
60
|
+
|
|
|
61
|
+
CHECK
|
|
62
|
+
|
|
|
63
|
+
+-----v-----+
|
|
64
|
+
| checking |
|
|
65
|
+
+-----+-----+
|
|
66
|
+
|
|
|
67
|
+
+---------------+---------------+
|
|
68
|
+
| | |
|
|
69
|
+
GRANTED DENIED BLOCKED
|
|
70
|
+
| | |
|
|
71
|
+
+-----v---+ +-----v-----+ +-----v-------+
|
|
72
|
+
| granted | | prePrompt | | blockedPrompt|
|
|
73
|
+
+---------+ +-----+-----+ +------+------+
|
|
74
|
+
| |
|
|
75
|
+
+--------+--------+ OPEN_SETTINGS
|
|
76
|
+
| | |
|
|
77
|
+
CONFIRM DISMISS +----v----------+
|
|
78
|
+
| | | openingSettings|
|
|
79
|
+
+-----v-----+ +-----v+ +----+----------+
|
|
80
|
+
| requesting | |denied| |
|
|
81
|
+
+-----+------+ +------+ SETTINGS_RETURN
|
|
82
|
+
| |
|
|
83
|
+
+--------+--------+ +---------v-----------+
|
|
84
|
+
| | | |recheckingAfterSettings|
|
|
85
|
+
GRANTED DENIED BLOCKED +---------+-----------+
|
|
86
|
+
| | | |
|
|
87
|
+
+-----v-+ +---v--+ +---v--------+ +---+---+
|
|
88
|
+
|granted| |denied| |blockedPrompt| |granted| or back
|
|
89
|
+
+-------+ +------+ +------------+ +-------+ to blockedPrompt
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**States:**
|
|
93
|
+
|
|
94
|
+
| State | Description |
|
|
95
|
+
|-------|-------------|
|
|
96
|
+
| `idle` | Initial state. Nothing has happened yet. |
|
|
97
|
+
| `checking` | Permission status is being checked. |
|
|
98
|
+
| `prePrompt` | Permission is requestable. Show a friendly explanation before the system dialog. |
|
|
99
|
+
| `requesting` | System permission dialog is showing. |
|
|
100
|
+
| `granted` | Permission is granted. Show the protected content. |
|
|
101
|
+
| `denied` | User dismissed the pre-prompt ("Not Now") or denied via system dialog. Permission is still requestable next time. |
|
|
102
|
+
| `blocked` | Permission is permanently denied. Only Settings can fix it. |
|
|
103
|
+
| `blockedPrompt` | Showing the "go to Settings" prompt. |
|
|
104
|
+
| `openingSettings` | User tapped "Open Settings". Waiting for app to return to foreground. |
|
|
105
|
+
| `recheckingAfterSettings` | App returned from Settings. Re-checking permission status. |
|
|
106
|
+
| `unavailable` | Device doesn't support this feature. Terminal state. |
|
|
107
|
+
|
|
108
|
+
## API Reference
|
|
109
|
+
|
|
110
|
+
### `usePermissionHandler(config)`
|
|
111
|
+
|
|
112
|
+
The main hook. Manages the full permission lifecycle.
|
|
113
|
+
|
|
114
|
+
**Config:**
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
{
|
|
118
|
+
// The permission to manage (from react-native-permissions PERMISSIONS constants)
|
|
119
|
+
permission: Permission | "notifications";
|
|
120
|
+
|
|
121
|
+
// Pre-prompt shown BEFORE the system dialog
|
|
122
|
+
prePrompt: {
|
|
123
|
+
title: string;
|
|
124
|
+
message: string;
|
|
125
|
+
confirmLabel?: string; // default: "Continue"
|
|
126
|
+
cancelLabel?: string; // default: "Not Now"
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// Prompt shown when permission is permanently blocked
|
|
130
|
+
blockedPrompt: {
|
|
131
|
+
title: string;
|
|
132
|
+
message: string;
|
|
133
|
+
settingsLabel?: string; // default: "Open Settings"
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// Callbacks for analytics
|
|
137
|
+
onGrant?: () => void;
|
|
138
|
+
onDeny?: () => void;
|
|
139
|
+
onBlock?: () => void;
|
|
140
|
+
onSettingsReturn?: (granted: boolean) => void;
|
|
141
|
+
|
|
142
|
+
// Options
|
|
143
|
+
autoCheck?: boolean; // default: true — check on mount
|
|
144
|
+
recheckOnForeground?: boolean; // default: false
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Returns:**
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
{
|
|
152
|
+
state: PermissionFlowState; // current state machine state
|
|
153
|
+
nativeStatus: PermissionStatus | null; // raw status from react-native-permissions
|
|
154
|
+
|
|
155
|
+
// Convenience booleans
|
|
156
|
+
isGranted: boolean;
|
|
157
|
+
isDenied: boolean;
|
|
158
|
+
isBlocked: boolean;
|
|
159
|
+
isChecking: boolean;
|
|
160
|
+
isUnavailable: boolean;
|
|
161
|
+
|
|
162
|
+
// Actions
|
|
163
|
+
request: () => void; // confirm pre-prompt → fire system dialog
|
|
164
|
+
check: () => void; // manually re-check permission status
|
|
165
|
+
dismiss: () => void; // dismiss pre-prompt ("Not Now")
|
|
166
|
+
openSettings: () => void; // open app settings for blocked permissions
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Example — full control over UI:**
|
|
171
|
+
|
|
172
|
+
```tsx
|
|
173
|
+
function CameraScreen() {
|
|
174
|
+
const camera = usePermissionHandler({
|
|
175
|
+
permission: PERMISSIONS.IOS.CAMERA,
|
|
176
|
+
prePrompt: {
|
|
177
|
+
title: "Camera Access",
|
|
178
|
+
message: "We need your camera to scan QR codes.",
|
|
179
|
+
},
|
|
180
|
+
blockedPrompt: {
|
|
181
|
+
title: "Camera Blocked",
|
|
182
|
+
message: "Please enable camera in Settings.",
|
|
183
|
+
},
|
|
184
|
+
onGrant: () => analytics.track("camera_granted"),
|
|
185
|
+
onDeny: () => analytics.track("camera_denied"),
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
if (camera.isGranted) return <CameraView />;
|
|
189
|
+
|
|
190
|
+
if (camera.state === "prePrompt") {
|
|
191
|
+
return (
|
|
192
|
+
<MyCustomModal>
|
|
193
|
+
<Text>We need camera access</Text>
|
|
194
|
+
<Button title="Allow" onPress={camera.request} />
|
|
195
|
+
<Button title="Not Now" onPress={camera.dismiss} />
|
|
196
|
+
</MyCustomModal>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (camera.state === "blockedPrompt") {
|
|
201
|
+
return (
|
|
202
|
+
<MyCustomModal>
|
|
203
|
+
<Text>Camera is blocked</Text>
|
|
204
|
+
<Button title="Open Settings" onPress={camera.openSettings} />
|
|
205
|
+
</MyCustomModal>
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return <LoadingSpinner />;
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
### `useMultiplePermissions(config)`
|
|
216
|
+
|
|
217
|
+
Orchestrates flows for features needing multiple permissions (e.g., video call = camera + microphone).
|
|
218
|
+
|
|
219
|
+
**Config:**
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
{
|
|
223
|
+
permissions: Array<{
|
|
224
|
+
permission: Permission | "notifications";
|
|
225
|
+
prePrompt: PrePromptConfig;
|
|
226
|
+
blockedPrompt: BlockedPromptConfig;
|
|
227
|
+
onGrant?: () => void;
|
|
228
|
+
onDeny?: () => void;
|
|
229
|
+
onBlock?: () => void;
|
|
230
|
+
}>;
|
|
231
|
+
|
|
232
|
+
strategy: "sequential" | "parallel";
|
|
233
|
+
// sequential: ask one at a time, stop on denial/block
|
|
234
|
+
// parallel: check all at once, then request denied ones
|
|
235
|
+
|
|
236
|
+
onAllGranted?: () => void;
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Returns:**
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
{
|
|
244
|
+
statuses: Record<string, PermissionFlowState>; // keyed by permission identifier
|
|
245
|
+
allGranted: boolean;
|
|
246
|
+
request: () => void; // start the multi-permission flow
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**Example:**
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
function VideoCallScreen() {
|
|
254
|
+
const perms = useMultiplePermissions({
|
|
255
|
+
permissions: [
|
|
256
|
+
{
|
|
257
|
+
permission: PERMISSIONS.IOS.CAMERA,
|
|
258
|
+
prePrompt: { title: "Camera", message: "Needed for video." },
|
|
259
|
+
blockedPrompt: { title: "Camera Blocked", message: "Enable in Settings." },
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
permission: PERMISSIONS.IOS.MICROPHONE,
|
|
263
|
+
prePrompt: { title: "Microphone", message: "Needed for audio." },
|
|
264
|
+
blockedPrompt: { title: "Mic Blocked", message: "Enable in Settings." },
|
|
265
|
+
},
|
|
266
|
+
],
|
|
267
|
+
strategy: "sequential",
|
|
268
|
+
onAllGranted: () => startCall(),
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
if (perms.allGranted) return <VideoCallUI />;
|
|
272
|
+
|
|
273
|
+
return <Button title="Start Call" onPress={perms.request} />;
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
### `<PermissionGate>`
|
|
280
|
+
|
|
281
|
+
Declarative component that renders children only when permission is granted.
|
|
282
|
+
|
|
283
|
+
**Props:**
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
{
|
|
287
|
+
permission: Permission | "notifications";
|
|
288
|
+
prePrompt: PrePromptConfig;
|
|
289
|
+
blockedPrompt: BlockedPromptConfig;
|
|
290
|
+
children: ReactNode; // shown when granted
|
|
291
|
+
fallback?: ReactNode; // shown while checking
|
|
292
|
+
onGrant?: () => void;
|
|
293
|
+
onDeny?: () => void;
|
|
294
|
+
onBlock?: () => void;
|
|
295
|
+
onSettingsReturn?: (granted: boolean) => void;
|
|
296
|
+
|
|
297
|
+
// Custom UI (optional — default modals are used if omitted)
|
|
298
|
+
renderPrePrompt?: (props: {
|
|
299
|
+
config: PrePromptConfig;
|
|
300
|
+
onConfirm: () => void;
|
|
301
|
+
onCancel: () => void;
|
|
302
|
+
}) => ReactNode;
|
|
303
|
+
renderBlockedPrompt?: (props: {
|
|
304
|
+
config: BlockedPromptConfig;
|
|
305
|
+
onOpenSettings: () => void;
|
|
306
|
+
}) => ReactNode;
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**Example:**
|
|
311
|
+
|
|
312
|
+
```tsx
|
|
313
|
+
<PermissionGate
|
|
314
|
+
permission={PERMISSIONS.IOS.CAMERA}
|
|
315
|
+
prePrompt={{ title: "Camera", message: "We need camera access." }}
|
|
316
|
+
blockedPrompt={{ title: "Blocked", message: "Enable in Settings." }}
|
|
317
|
+
fallback={<LoadingSpinner />}
|
|
318
|
+
>
|
|
319
|
+
<CameraView />
|
|
320
|
+
</PermissionGate>
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
### `<DefaultPrePrompt>` / `<DefaultBlockedPrompt>`
|
|
326
|
+
|
|
327
|
+
The default modal components used by `usePermissionHandler` and `PermissionGate`. You can import and use them directly if you want the default look with custom behavior.
|
|
328
|
+
|
|
329
|
+
```tsx
|
|
330
|
+
import { DefaultPrePrompt, DefaultBlockedPrompt } from "react-native-permission-handler";
|
|
331
|
+
|
|
332
|
+
<DefaultPrePrompt
|
|
333
|
+
visible={showPrePrompt}
|
|
334
|
+
title="Camera Access"
|
|
335
|
+
message="We need your camera."
|
|
336
|
+
confirmLabel="Allow"
|
|
337
|
+
cancelLabel="Not Now"
|
|
338
|
+
onConfirm={handleConfirm}
|
|
339
|
+
onCancel={handleCancel}
|
|
340
|
+
/>
|
|
341
|
+
|
|
342
|
+
<DefaultBlockedPrompt
|
|
343
|
+
visible={showBlocked}
|
|
344
|
+
title="Camera Blocked"
|
|
345
|
+
message="Please enable in Settings."
|
|
346
|
+
settingsLabel="Open Settings"
|
|
347
|
+
onOpenSettings={handleOpenSettings}
|
|
348
|
+
/>
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
These use only React Native primitives (`Modal`, `View`, `Text`, `TouchableOpacity`) — no third-party UI dependencies.
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
### `transition(state, event)`
|
|
356
|
+
|
|
357
|
+
The raw state machine function. For advanced use cases where you want to build your own hook or integrate with a state management library.
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
import { transition } from "react-native-permission-handler";
|
|
361
|
+
|
|
362
|
+
const next = transition("prePrompt", { type: "PRE_PROMPT_CONFIRM" });
|
|
363
|
+
// → "requesting"
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Pure function, no side effects, no React dependency.
|
|
367
|
+
|
|
368
|
+
## Platform Notes
|
|
369
|
+
|
|
370
|
+
**iOS:**
|
|
371
|
+
- The system permission dialog can only be shown **once** per permission. If the user denies it, you can never show it again programmatically. This is why the pre-prompt is critical — it preserves the one-time system dialog.
|
|
372
|
+
- `check()` returns `DENIED` for both "never asked" and "denied once" — both are still requestable.
|
|
373
|
+
- `BLOCKED` means the user denied via the system dialog or disabled the permission in Settings.
|
|
374
|
+
|
|
375
|
+
**Android:**
|
|
376
|
+
- After 2 denials, Android 11+ auto-blocks the permission. No more system dialogs.
|
|
377
|
+
- For notification permissions on Android 13+, `checkNotifications()` never returns `BLOCKED` — the library handles this by using `requestNotifications()` for accurate status.
|
|
378
|
+
|
|
379
|
+
**Notifications:**
|
|
380
|
+
- Pass `"notifications"` as the permission identifier. The library automatically routes to `checkNotifications`/`requestNotifications` instead of `check`/`request`.
|
|
381
|
+
|
|
382
|
+
## Requirements
|
|
383
|
+
|
|
384
|
+
- React Native >= 0.76
|
|
385
|
+
- React >= 18
|
|
386
|
+
- `react-native-permissions` >= 4.0.0
|
|
387
|
+
|
|
388
|
+
**Expo:** Add the config plugin to your `app.json`:
|
|
389
|
+
|
|
390
|
+
```json
|
|
391
|
+
{
|
|
392
|
+
"plugins": [
|
|
393
|
+
[
|
|
394
|
+
"react-native-permissions",
|
|
395
|
+
{
|
|
396
|
+
"iosPermissions": ["Camera", "Microphone", "LocationWhenInUse"]
|
|
397
|
+
}
|
|
398
|
+
]
|
|
399
|
+
]
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Bare React Native:** Follow the [react-native-permissions setup guide](https://github.com/zoontek/react-native-permissions#setup).
|
|
404
|
+
|
|
405
|
+
## License
|
|
406
|
+
|
|
407
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { Permission, PermissionStatus } from 'react-native-permissions';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* States of the permission flow state machine.
|
|
7
|
+
*/
|
|
8
|
+
type PermissionFlowState = "idle" | "checking" | "prePrompt" | "requesting" | "granted" | "denied" | "blocked" | "blockedPrompt" | "openingSettings" | "recheckingAfterSettings" | "unavailable";
|
|
9
|
+
/**
|
|
10
|
+
* Events that drive state transitions.
|
|
11
|
+
*/
|
|
12
|
+
type PermissionFlowEvent = {
|
|
13
|
+
type: "CHECK";
|
|
14
|
+
} | {
|
|
15
|
+
type: "CHECK_RESULT";
|
|
16
|
+
status: PermissionStatus;
|
|
17
|
+
} | {
|
|
18
|
+
type: "PRE_PROMPT_CONFIRM";
|
|
19
|
+
} | {
|
|
20
|
+
type: "PRE_PROMPT_DISMISS";
|
|
21
|
+
} | {
|
|
22
|
+
type: "REQUEST_RESULT";
|
|
23
|
+
status: PermissionStatus;
|
|
24
|
+
} | {
|
|
25
|
+
type: "OPEN_SETTINGS";
|
|
26
|
+
} | {
|
|
27
|
+
type: "SETTINGS_RETURN";
|
|
28
|
+
} | {
|
|
29
|
+
type: "RECHECK_RESULT";
|
|
30
|
+
status: PermissionStatus;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Configuration for the pre-prompt modal.
|
|
34
|
+
*/
|
|
35
|
+
interface PrePromptConfig {
|
|
36
|
+
title: string;
|
|
37
|
+
message: string;
|
|
38
|
+
confirmLabel?: string;
|
|
39
|
+
cancelLabel?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Configuration for the blocked-prompt modal.
|
|
43
|
+
*/
|
|
44
|
+
interface BlockedPromptConfig {
|
|
45
|
+
title: string;
|
|
46
|
+
message: string;
|
|
47
|
+
settingsLabel?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Callbacks for analytics and side effects.
|
|
51
|
+
*/
|
|
52
|
+
interface PermissionCallbacks {
|
|
53
|
+
onGrant?: () => void;
|
|
54
|
+
onDeny?: () => void;
|
|
55
|
+
onBlock?: () => void;
|
|
56
|
+
onSettingsReturn?: (granted: boolean) => void;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Configuration for usePermissionHandler.
|
|
60
|
+
*/
|
|
61
|
+
interface PermissionHandlerConfig extends PermissionCallbacks {
|
|
62
|
+
permission: Permission | "notifications";
|
|
63
|
+
prePrompt: PrePromptConfig;
|
|
64
|
+
blockedPrompt: BlockedPromptConfig;
|
|
65
|
+
autoCheck?: boolean;
|
|
66
|
+
recheckOnForeground?: boolean;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Return type of usePermissionHandler.
|
|
70
|
+
*/
|
|
71
|
+
interface PermissionHandlerResult {
|
|
72
|
+
state: PermissionFlowState;
|
|
73
|
+
nativeStatus: PermissionStatus | null;
|
|
74
|
+
isGranted: boolean;
|
|
75
|
+
isDenied: boolean;
|
|
76
|
+
isBlocked: boolean;
|
|
77
|
+
isChecking: boolean;
|
|
78
|
+
isUnavailable: boolean;
|
|
79
|
+
request: () => void;
|
|
80
|
+
check: () => void;
|
|
81
|
+
dismiss: () => void;
|
|
82
|
+
openSettings: () => void;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Configuration for a single permission within useMultiplePermissions.
|
|
86
|
+
*/
|
|
87
|
+
interface MultiPermissionEntry extends PermissionCallbacks {
|
|
88
|
+
permission: Permission | "notifications";
|
|
89
|
+
prePrompt: PrePromptConfig;
|
|
90
|
+
blockedPrompt: BlockedPromptConfig;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Configuration for useMultiplePermissions.
|
|
94
|
+
*/
|
|
95
|
+
interface MultiplePermissionsConfig {
|
|
96
|
+
permissions: MultiPermissionEntry[];
|
|
97
|
+
strategy: "sequential" | "parallel";
|
|
98
|
+
onAllGranted?: () => void;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Return type of useMultiplePermissions.
|
|
102
|
+
*/
|
|
103
|
+
interface MultiplePermissionsResult {
|
|
104
|
+
statuses: Record<string, PermissionFlowState>;
|
|
105
|
+
allGranted: boolean;
|
|
106
|
+
request: () => void;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
declare function transition(state: PermissionFlowState, event: PermissionFlowEvent): PermissionFlowState;
|
|
110
|
+
|
|
111
|
+
declare function usePermissionHandler(config: PermissionHandlerConfig): PermissionHandlerResult;
|
|
112
|
+
|
|
113
|
+
declare function useMultiplePermissions(config: MultiplePermissionsConfig): MultiplePermissionsResult;
|
|
114
|
+
|
|
115
|
+
interface PermissionGateProps extends PermissionCallbacks {
|
|
116
|
+
permission: Permission | "notifications";
|
|
117
|
+
prePrompt: PrePromptConfig;
|
|
118
|
+
blockedPrompt: BlockedPromptConfig;
|
|
119
|
+
children: ReactNode;
|
|
120
|
+
fallback?: ReactNode;
|
|
121
|
+
renderPrePrompt?: (props: {
|
|
122
|
+
config: PrePromptConfig;
|
|
123
|
+
onConfirm: () => void;
|
|
124
|
+
onCancel: () => void;
|
|
125
|
+
}) => ReactNode;
|
|
126
|
+
renderBlockedPrompt?: (props: {
|
|
127
|
+
config: BlockedPromptConfig;
|
|
128
|
+
onOpenSettings: () => void;
|
|
129
|
+
}) => ReactNode;
|
|
130
|
+
}
|
|
131
|
+
declare function PermissionGate({ permission, prePrompt, blockedPrompt, children, fallback, renderPrePrompt, renderBlockedPrompt, onGrant, onDeny, onBlock, onSettingsReturn, }: PermissionGateProps): react_jsx_runtime.JSX.Element;
|
|
132
|
+
|
|
133
|
+
interface DefaultPrePromptProps extends PrePromptConfig {
|
|
134
|
+
visible: boolean;
|
|
135
|
+
onConfirm: () => void;
|
|
136
|
+
onCancel: () => void;
|
|
137
|
+
}
|
|
138
|
+
declare function DefaultPrePrompt({ visible, title, message, confirmLabel, cancelLabel, onConfirm, onCancel, }: DefaultPrePromptProps): react_jsx_runtime.JSX.Element;
|
|
139
|
+
|
|
140
|
+
interface DefaultBlockedPromptProps extends BlockedPromptConfig {
|
|
141
|
+
visible: boolean;
|
|
142
|
+
onOpenSettings: () => void;
|
|
143
|
+
}
|
|
144
|
+
declare function DefaultBlockedPrompt({ visible, title, message, settingsLabel, onOpenSettings, }: DefaultBlockedPromptProps): react_jsx_runtime.JSX.Element;
|
|
145
|
+
|
|
146
|
+
export { type BlockedPromptConfig, DefaultBlockedPrompt, type DefaultBlockedPromptProps, DefaultPrePrompt, type DefaultPrePromptProps, type MultiPermissionEntry, type MultiplePermissionsConfig, type MultiplePermissionsResult, type PermissionCallbacks, type PermissionFlowEvent, type PermissionFlowState, PermissionGate, type PermissionGateProps, type PermissionHandlerConfig, type PermissionHandlerResult, type PrePromptConfig, transition, useMultiplePermissions, usePermissionHandler };
|