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/dist/index.mjs
ADDED
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
// src/core/state-machine.ts
|
|
2
|
+
function transition(state, event) {
|
|
3
|
+
switch (state) {
|
|
4
|
+
case "idle":
|
|
5
|
+
if (event.type === "CHECK") return "checking";
|
|
6
|
+
return state;
|
|
7
|
+
case "checking":
|
|
8
|
+
if (event.type === "CHECK_RESULT") {
|
|
9
|
+
switch (event.status) {
|
|
10
|
+
case "granted":
|
|
11
|
+
case "limited":
|
|
12
|
+
return "granted";
|
|
13
|
+
case "denied":
|
|
14
|
+
return "prePrompt";
|
|
15
|
+
case "blocked":
|
|
16
|
+
return "blockedPrompt";
|
|
17
|
+
case "unavailable":
|
|
18
|
+
return "unavailable";
|
|
19
|
+
default:
|
|
20
|
+
return state;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return state;
|
|
24
|
+
case "prePrompt":
|
|
25
|
+
if (event.type === "PRE_PROMPT_CONFIRM") return "requesting";
|
|
26
|
+
if (event.type === "PRE_PROMPT_DISMISS") return "denied";
|
|
27
|
+
return state;
|
|
28
|
+
case "requesting":
|
|
29
|
+
if (event.type === "REQUEST_RESULT") {
|
|
30
|
+
switch (event.status) {
|
|
31
|
+
case "granted":
|
|
32
|
+
case "limited":
|
|
33
|
+
return "granted";
|
|
34
|
+
case "denied":
|
|
35
|
+
return "denied";
|
|
36
|
+
case "blocked":
|
|
37
|
+
return "blockedPrompt";
|
|
38
|
+
default:
|
|
39
|
+
return state;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return state;
|
|
43
|
+
case "blockedPrompt":
|
|
44
|
+
if (event.type === "OPEN_SETTINGS") return "openingSettings";
|
|
45
|
+
return state;
|
|
46
|
+
case "openingSettings":
|
|
47
|
+
if (event.type === "SETTINGS_RETURN") return "recheckingAfterSettings";
|
|
48
|
+
return state;
|
|
49
|
+
case "recheckingAfterSettings":
|
|
50
|
+
if (event.type === "RECHECK_RESULT") {
|
|
51
|
+
switch (event.status) {
|
|
52
|
+
case "granted":
|
|
53
|
+
case "limited":
|
|
54
|
+
return "granted";
|
|
55
|
+
case "blocked":
|
|
56
|
+
return "blockedPrompt";
|
|
57
|
+
case "denied":
|
|
58
|
+
return "blockedPrompt";
|
|
59
|
+
default:
|
|
60
|
+
return state;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return state;
|
|
64
|
+
case "granted":
|
|
65
|
+
case "denied":
|
|
66
|
+
case "unavailable":
|
|
67
|
+
if (event.type === "CHECK") return "checking";
|
|
68
|
+
return state;
|
|
69
|
+
case "blocked":
|
|
70
|
+
return state;
|
|
71
|
+
default:
|
|
72
|
+
return state;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// src/hooks/use-permission-handler.ts
|
|
77
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
78
|
+
import { AppState } from "react-native";
|
|
79
|
+
import {
|
|
80
|
+
check,
|
|
81
|
+
checkNotifications,
|
|
82
|
+
openSettings,
|
|
83
|
+
request,
|
|
84
|
+
requestNotifications
|
|
85
|
+
} from "react-native-permissions";
|
|
86
|
+
function isNotifications(permission) {
|
|
87
|
+
return permission === "notifications";
|
|
88
|
+
}
|
|
89
|
+
function usePermissionHandler(config) {
|
|
90
|
+
const [flowState, setFlowState] = useState("idle");
|
|
91
|
+
const [nativeStatus, setNativeStatus] = useState(null);
|
|
92
|
+
const isRequesting = useRef(false);
|
|
93
|
+
const waitingForSettings = useRef(false);
|
|
94
|
+
const appStateRef = useRef(AppState.currentState);
|
|
95
|
+
const { permission, autoCheck = true, onGrant, onDeny, onBlock, onSettingsReturn } = config;
|
|
96
|
+
const checkPermission = useCallback(async () => {
|
|
97
|
+
setFlowState((s) => transition(s, { type: "CHECK" }));
|
|
98
|
+
try {
|
|
99
|
+
let status;
|
|
100
|
+
if (isNotifications(permission)) {
|
|
101
|
+
const result = await checkNotifications();
|
|
102
|
+
status = result.status;
|
|
103
|
+
} else {
|
|
104
|
+
status = await check(permission);
|
|
105
|
+
}
|
|
106
|
+
setNativeStatus(status);
|
|
107
|
+
setFlowState((s) => {
|
|
108
|
+
const next = transition(s, { type: "CHECK_RESULT", status });
|
|
109
|
+
if (next === "granted" && s !== "granted") onGrant?.();
|
|
110
|
+
return next;
|
|
111
|
+
});
|
|
112
|
+
} catch {
|
|
113
|
+
setFlowState("idle");
|
|
114
|
+
}
|
|
115
|
+
}, [permission, onGrant]);
|
|
116
|
+
const requestPermission = useCallback(async () => {
|
|
117
|
+
if (isRequesting.current) return;
|
|
118
|
+
isRequesting.current = true;
|
|
119
|
+
setFlowState((s) => transition(s, { type: "PRE_PROMPT_CONFIRM" }));
|
|
120
|
+
try {
|
|
121
|
+
let status;
|
|
122
|
+
if (isNotifications(permission)) {
|
|
123
|
+
const result = await requestNotifications(["alert", "badge", "sound"]);
|
|
124
|
+
status = result.status;
|
|
125
|
+
} else {
|
|
126
|
+
status = await request(permission);
|
|
127
|
+
}
|
|
128
|
+
setNativeStatus(status);
|
|
129
|
+
setFlowState((s) => {
|
|
130
|
+
const next = transition(s, { type: "REQUEST_RESULT", status });
|
|
131
|
+
if (next === "granted") onGrant?.();
|
|
132
|
+
if (next === "denied") onDeny?.();
|
|
133
|
+
if (next === "blockedPrompt") onBlock?.();
|
|
134
|
+
return next;
|
|
135
|
+
});
|
|
136
|
+
} catch {
|
|
137
|
+
setFlowState("denied");
|
|
138
|
+
} finally {
|
|
139
|
+
isRequesting.current = false;
|
|
140
|
+
}
|
|
141
|
+
}, [permission, onGrant, onDeny, onBlock]);
|
|
142
|
+
const dismiss = useCallback(() => {
|
|
143
|
+
setFlowState((s) => transition(s, { type: "PRE_PROMPT_DISMISS" }));
|
|
144
|
+
onDeny?.();
|
|
145
|
+
}, [onDeny]);
|
|
146
|
+
const goToSettings = useCallback(async () => {
|
|
147
|
+
setFlowState((s) => transition(s, { type: "OPEN_SETTINGS" }));
|
|
148
|
+
waitingForSettings.current = true;
|
|
149
|
+
try {
|
|
150
|
+
await openSettings();
|
|
151
|
+
} catch {
|
|
152
|
+
waitingForSettings.current = false;
|
|
153
|
+
setFlowState("blockedPrompt");
|
|
154
|
+
}
|
|
155
|
+
}, []);
|
|
156
|
+
const recheckAfterSettings = useCallback(async () => {
|
|
157
|
+
setFlowState((s) => transition(s, { type: "SETTINGS_RETURN" }));
|
|
158
|
+
try {
|
|
159
|
+
let status;
|
|
160
|
+
if (isNotifications(permission)) {
|
|
161
|
+
const result = await checkNotifications();
|
|
162
|
+
status = result.status;
|
|
163
|
+
} else {
|
|
164
|
+
status = await check(permission);
|
|
165
|
+
}
|
|
166
|
+
setNativeStatus(status);
|
|
167
|
+
setFlowState((s) => {
|
|
168
|
+
const next = transition(s, { type: "RECHECK_RESULT", status });
|
|
169
|
+
if (next === "granted") onGrant?.();
|
|
170
|
+
onSettingsReturn?.(next === "granted");
|
|
171
|
+
return next;
|
|
172
|
+
});
|
|
173
|
+
} catch {
|
|
174
|
+
setFlowState("blockedPrompt");
|
|
175
|
+
}
|
|
176
|
+
}, [permission, onGrant, onSettingsReturn]);
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
if (autoCheck) {
|
|
179
|
+
checkPermission();
|
|
180
|
+
}
|
|
181
|
+
}, []);
|
|
182
|
+
useEffect(() => {
|
|
183
|
+
const subscription = AppState.addEventListener("change", (nextAppState) => {
|
|
184
|
+
if (appStateRef.current.match(/inactive|background/) && nextAppState === "active" && waitingForSettings.current) {
|
|
185
|
+
waitingForSettings.current = false;
|
|
186
|
+
recheckAfterSettings();
|
|
187
|
+
}
|
|
188
|
+
appStateRef.current = nextAppState;
|
|
189
|
+
});
|
|
190
|
+
return () => subscription.remove();
|
|
191
|
+
}, [recheckAfterSettings]);
|
|
192
|
+
return {
|
|
193
|
+
state: flowState,
|
|
194
|
+
nativeStatus,
|
|
195
|
+
isGranted: flowState === "granted",
|
|
196
|
+
isDenied: flowState === "denied",
|
|
197
|
+
isBlocked: flowState === "blocked" || flowState === "blockedPrompt" || flowState === "openingSettings",
|
|
198
|
+
isChecking: flowState === "checking" || flowState === "recheckingAfterSettings",
|
|
199
|
+
isUnavailable: flowState === "unavailable",
|
|
200
|
+
request: requestPermission,
|
|
201
|
+
check: checkPermission,
|
|
202
|
+
dismiss,
|
|
203
|
+
openSettings: goToSettings
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// src/hooks/use-multiple-permissions.ts
|
|
208
|
+
import { useCallback as useCallback2, useRef as useRef2, useState as useState2 } from "react";
|
|
209
|
+
import {
|
|
210
|
+
check as check2,
|
|
211
|
+
checkNotifications as checkNotifications2,
|
|
212
|
+
request as request2,
|
|
213
|
+
requestNotifications as requestNotifications2
|
|
214
|
+
} from "react-native-permissions";
|
|
215
|
+
function isNotifications2(permission) {
|
|
216
|
+
return permission === "notifications";
|
|
217
|
+
}
|
|
218
|
+
async function checkOne(entry) {
|
|
219
|
+
if (isNotifications2(entry.permission)) {
|
|
220
|
+
const result = await checkNotifications2();
|
|
221
|
+
return result.status;
|
|
222
|
+
}
|
|
223
|
+
return check2(entry.permission);
|
|
224
|
+
}
|
|
225
|
+
async function requestOne(entry) {
|
|
226
|
+
if (isNotifications2(entry.permission)) {
|
|
227
|
+
const result = await requestNotifications2(["alert", "badge", "sound"]);
|
|
228
|
+
return result.status;
|
|
229
|
+
}
|
|
230
|
+
return request2(entry.permission);
|
|
231
|
+
}
|
|
232
|
+
function permissionKey(entry) {
|
|
233
|
+
return String(entry.permission);
|
|
234
|
+
}
|
|
235
|
+
function isGrantedStatus(status) {
|
|
236
|
+
return status === "granted" || status === "limited";
|
|
237
|
+
}
|
|
238
|
+
function useMultiplePermissions(config) {
|
|
239
|
+
const { permissions, strategy, onAllGranted } = config;
|
|
240
|
+
const [statuses, setStatuses] = useState2(() => {
|
|
241
|
+
const initial = {};
|
|
242
|
+
for (const entry of permissions) {
|
|
243
|
+
initial[permissionKey(entry)] = "idle";
|
|
244
|
+
}
|
|
245
|
+
return initial;
|
|
246
|
+
});
|
|
247
|
+
const isRunning = useRef2(false);
|
|
248
|
+
const allGranted = permissions.every((entry) => statuses[permissionKey(entry)] === "granted");
|
|
249
|
+
const requestAll = useCallback2(async () => {
|
|
250
|
+
if (isRunning.current) return;
|
|
251
|
+
isRunning.current = true;
|
|
252
|
+
const update = (key, state) => {
|
|
253
|
+
setStatuses((prev) => ({ ...prev, [key]: state }));
|
|
254
|
+
};
|
|
255
|
+
try {
|
|
256
|
+
if (strategy === "sequential") {
|
|
257
|
+
await runSequential(permissions, update);
|
|
258
|
+
} else {
|
|
259
|
+
await runParallel(permissions, update);
|
|
260
|
+
}
|
|
261
|
+
let allDone = true;
|
|
262
|
+
for (const entry of permissions) {
|
|
263
|
+
const finalStatus = await checkOne(entry);
|
|
264
|
+
if (!isGrantedStatus(finalStatus)) {
|
|
265
|
+
allDone = false;
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (allDone) {
|
|
270
|
+
onAllGranted?.();
|
|
271
|
+
}
|
|
272
|
+
} finally {
|
|
273
|
+
isRunning.current = false;
|
|
274
|
+
}
|
|
275
|
+
}, [permissions, strategy, onAllGranted]);
|
|
276
|
+
return {
|
|
277
|
+
statuses,
|
|
278
|
+
allGranted,
|
|
279
|
+
request: requestAll
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
async function runSequential(permissions, updateStatus) {
|
|
283
|
+
for (const entry of permissions) {
|
|
284
|
+
const key = permissionKey(entry);
|
|
285
|
+
updateStatus(key, "checking");
|
|
286
|
+
const checkStatus = await checkOne(entry);
|
|
287
|
+
if (isGrantedStatus(checkStatus)) {
|
|
288
|
+
updateStatus(key, "granted");
|
|
289
|
+
entry.onGrant?.();
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
if (checkStatus === "unavailable") {
|
|
293
|
+
updateStatus(key, "unavailable");
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
if (checkStatus === "blocked") {
|
|
297
|
+
updateStatus(key, "blockedPrompt");
|
|
298
|
+
entry.onBlock?.();
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
updateStatus(key, "requesting");
|
|
302
|
+
const requestStatus = await requestOne(entry);
|
|
303
|
+
if (isGrantedStatus(requestStatus)) {
|
|
304
|
+
updateStatus(key, "granted");
|
|
305
|
+
entry.onGrant?.();
|
|
306
|
+
} else if (requestStatus === "blocked") {
|
|
307
|
+
updateStatus(key, "blockedPrompt");
|
|
308
|
+
entry.onBlock?.();
|
|
309
|
+
break;
|
|
310
|
+
} else {
|
|
311
|
+
updateStatus(key, "denied");
|
|
312
|
+
entry.onDeny?.();
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
async function runParallel(permissions, updateStatus) {
|
|
318
|
+
const checkResults = await Promise.all(
|
|
319
|
+
permissions.map(async (entry) => {
|
|
320
|
+
const key = permissionKey(entry);
|
|
321
|
+
updateStatus(key, "checking");
|
|
322
|
+
const status = await checkOne(entry);
|
|
323
|
+
return { entry, key, status };
|
|
324
|
+
})
|
|
325
|
+
);
|
|
326
|
+
for (const { entry, key, status } of checkResults) {
|
|
327
|
+
if (isGrantedStatus(status)) {
|
|
328
|
+
updateStatus(key, "granted");
|
|
329
|
+
entry.onGrant?.();
|
|
330
|
+
} else if (status === "unavailable") {
|
|
331
|
+
updateStatus(key, "unavailable");
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const needsAction = checkResults.filter(
|
|
335
|
+
({ status }) => status === "denied" || status === "blocked"
|
|
336
|
+
);
|
|
337
|
+
for (const { entry, key, status } of needsAction) {
|
|
338
|
+
if (status === "blocked") {
|
|
339
|
+
updateStatus(key, "blockedPrompt");
|
|
340
|
+
entry.onBlock?.();
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
updateStatus(key, "requesting");
|
|
344
|
+
const requestStatus = await requestOne(entry);
|
|
345
|
+
if (isGrantedStatus(requestStatus)) {
|
|
346
|
+
updateStatus(key, "granted");
|
|
347
|
+
entry.onGrant?.();
|
|
348
|
+
} else if (requestStatus === "blocked") {
|
|
349
|
+
updateStatus(key, "blockedPrompt");
|
|
350
|
+
entry.onBlock?.();
|
|
351
|
+
} else {
|
|
352
|
+
updateStatus(key, "denied");
|
|
353
|
+
entry.onDeny?.();
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// src/components/default-blocked-prompt.tsx
|
|
359
|
+
import { Modal, StyleSheet, Text, TouchableOpacity, View } from "react-native";
|
|
360
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
361
|
+
function DefaultBlockedPrompt({
|
|
362
|
+
visible,
|
|
363
|
+
title,
|
|
364
|
+
message,
|
|
365
|
+
settingsLabel = "Open Settings",
|
|
366
|
+
onOpenSettings
|
|
367
|
+
}) {
|
|
368
|
+
return /* @__PURE__ */ jsx(Modal, { visible, transparent: true, animationType: "fade", children: /* @__PURE__ */ jsx(View, { style: styles.overlay, children: /* @__PURE__ */ jsxs(View, { style: styles.modal, children: [
|
|
369
|
+
/* @__PURE__ */ jsx(Text, { style: styles.title, children: title }),
|
|
370
|
+
/* @__PURE__ */ jsx(Text, { style: styles.message, children: message }),
|
|
371
|
+
/* @__PURE__ */ jsx(
|
|
372
|
+
TouchableOpacity,
|
|
373
|
+
{
|
|
374
|
+
style: styles.settingsButton,
|
|
375
|
+
onPress: onOpenSettings,
|
|
376
|
+
accessibilityRole: "button",
|
|
377
|
+
children: /* @__PURE__ */ jsx(Text, { style: styles.settingsText, children: settingsLabel })
|
|
378
|
+
}
|
|
379
|
+
)
|
|
380
|
+
] }) }) });
|
|
381
|
+
}
|
|
382
|
+
var styles = StyleSheet.create({
|
|
383
|
+
overlay: {
|
|
384
|
+
flex: 1,
|
|
385
|
+
backgroundColor: "rgba(0,0,0,0.5)",
|
|
386
|
+
justifyContent: "center",
|
|
387
|
+
alignItems: "center"
|
|
388
|
+
},
|
|
389
|
+
modal: {
|
|
390
|
+
backgroundColor: "white",
|
|
391
|
+
borderRadius: 16,
|
|
392
|
+
padding: 24,
|
|
393
|
+
width: "85%",
|
|
394
|
+
alignItems: "center"
|
|
395
|
+
},
|
|
396
|
+
title: {
|
|
397
|
+
fontSize: 20,
|
|
398
|
+
fontWeight: "600",
|
|
399
|
+
marginBottom: 12,
|
|
400
|
+
textAlign: "center"
|
|
401
|
+
},
|
|
402
|
+
message: {
|
|
403
|
+
fontSize: 15,
|
|
404
|
+
color: "#666",
|
|
405
|
+
textAlign: "center",
|
|
406
|
+
marginBottom: 24,
|
|
407
|
+
lineHeight: 22
|
|
408
|
+
},
|
|
409
|
+
settingsButton: {
|
|
410
|
+
backgroundColor: "#007AFF",
|
|
411
|
+
borderRadius: 12,
|
|
412
|
+
paddingVertical: 14,
|
|
413
|
+
paddingHorizontal: 32,
|
|
414
|
+
width: "100%",
|
|
415
|
+
alignItems: "center"
|
|
416
|
+
},
|
|
417
|
+
settingsText: {
|
|
418
|
+
color: "white",
|
|
419
|
+
fontSize: 16,
|
|
420
|
+
fontWeight: "600"
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// src/components/default-pre-prompt.tsx
|
|
425
|
+
import { Modal as Modal2, StyleSheet as StyleSheet2, Text as Text2, TouchableOpacity as TouchableOpacity2, View as View2 } from "react-native";
|
|
426
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
427
|
+
function DefaultPrePrompt({
|
|
428
|
+
visible,
|
|
429
|
+
title,
|
|
430
|
+
message,
|
|
431
|
+
confirmLabel = "Continue",
|
|
432
|
+
cancelLabel = "Not Now",
|
|
433
|
+
onConfirm,
|
|
434
|
+
onCancel
|
|
435
|
+
}) {
|
|
436
|
+
return /* @__PURE__ */ jsx2(Modal2, { visible, transparent: true, animationType: "fade", children: /* @__PURE__ */ jsx2(View2, { style: styles2.overlay, children: /* @__PURE__ */ jsxs2(View2, { style: styles2.modal, children: [
|
|
437
|
+
/* @__PURE__ */ jsx2(Text2, { style: styles2.title, children: title }),
|
|
438
|
+
/* @__PURE__ */ jsx2(Text2, { style: styles2.message, children: message }),
|
|
439
|
+
/* @__PURE__ */ jsx2(
|
|
440
|
+
TouchableOpacity2,
|
|
441
|
+
{
|
|
442
|
+
style: styles2.confirmButton,
|
|
443
|
+
onPress: onConfirm,
|
|
444
|
+
accessibilityRole: "button",
|
|
445
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: styles2.confirmText, children: confirmLabel })
|
|
446
|
+
}
|
|
447
|
+
),
|
|
448
|
+
/* @__PURE__ */ jsx2(TouchableOpacity2, { onPress: onCancel, accessibilityRole: "button", children: /* @__PURE__ */ jsx2(Text2, { style: styles2.cancelText, children: cancelLabel }) })
|
|
449
|
+
] }) }) });
|
|
450
|
+
}
|
|
451
|
+
var styles2 = StyleSheet2.create({
|
|
452
|
+
overlay: {
|
|
453
|
+
flex: 1,
|
|
454
|
+
backgroundColor: "rgba(0,0,0,0.5)",
|
|
455
|
+
justifyContent: "center",
|
|
456
|
+
alignItems: "center"
|
|
457
|
+
},
|
|
458
|
+
modal: {
|
|
459
|
+
backgroundColor: "white",
|
|
460
|
+
borderRadius: 16,
|
|
461
|
+
padding: 24,
|
|
462
|
+
width: "85%",
|
|
463
|
+
alignItems: "center"
|
|
464
|
+
},
|
|
465
|
+
title: {
|
|
466
|
+
fontSize: 20,
|
|
467
|
+
fontWeight: "600",
|
|
468
|
+
marginBottom: 12,
|
|
469
|
+
textAlign: "center"
|
|
470
|
+
},
|
|
471
|
+
message: {
|
|
472
|
+
fontSize: 15,
|
|
473
|
+
color: "#666",
|
|
474
|
+
textAlign: "center",
|
|
475
|
+
marginBottom: 24,
|
|
476
|
+
lineHeight: 22
|
|
477
|
+
},
|
|
478
|
+
confirmButton: {
|
|
479
|
+
backgroundColor: "#007AFF",
|
|
480
|
+
borderRadius: 12,
|
|
481
|
+
paddingVertical: 14,
|
|
482
|
+
paddingHorizontal: 32,
|
|
483
|
+
width: "100%",
|
|
484
|
+
alignItems: "center",
|
|
485
|
+
marginBottom: 12
|
|
486
|
+
},
|
|
487
|
+
confirmText: {
|
|
488
|
+
color: "white",
|
|
489
|
+
fontSize: 16,
|
|
490
|
+
fontWeight: "600"
|
|
491
|
+
},
|
|
492
|
+
cancelText: {
|
|
493
|
+
color: "#007AFF",
|
|
494
|
+
fontSize: 15
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
// src/components/permission-gate.tsx
|
|
499
|
+
import { Fragment, jsx as jsx3 } from "react/jsx-runtime";
|
|
500
|
+
function PermissionGate({
|
|
501
|
+
permission,
|
|
502
|
+
prePrompt,
|
|
503
|
+
blockedPrompt,
|
|
504
|
+
children,
|
|
505
|
+
fallback = null,
|
|
506
|
+
renderPrePrompt,
|
|
507
|
+
renderBlockedPrompt,
|
|
508
|
+
onGrant,
|
|
509
|
+
onDeny,
|
|
510
|
+
onBlock,
|
|
511
|
+
onSettingsReturn
|
|
512
|
+
}) {
|
|
513
|
+
const handler = usePermissionHandler({
|
|
514
|
+
permission,
|
|
515
|
+
prePrompt,
|
|
516
|
+
blockedPrompt,
|
|
517
|
+
onGrant,
|
|
518
|
+
onDeny,
|
|
519
|
+
onBlock,
|
|
520
|
+
onSettingsReturn
|
|
521
|
+
});
|
|
522
|
+
if (handler.isGranted) {
|
|
523
|
+
return /* @__PURE__ */ jsx3(Fragment, { children });
|
|
524
|
+
}
|
|
525
|
+
if (handler.isChecking || handler.isUnavailable) {
|
|
526
|
+
return /* @__PURE__ */ jsx3(Fragment, { children: fallback });
|
|
527
|
+
}
|
|
528
|
+
if (handler.state === "prePrompt") {
|
|
529
|
+
if (renderPrePrompt) {
|
|
530
|
+
return /* @__PURE__ */ jsx3(Fragment, { children: renderPrePrompt({
|
|
531
|
+
config: prePrompt,
|
|
532
|
+
onConfirm: handler.request,
|
|
533
|
+
onCancel: handler.dismiss
|
|
534
|
+
}) });
|
|
535
|
+
}
|
|
536
|
+
return /* @__PURE__ */ jsx3(
|
|
537
|
+
DefaultPrePrompt,
|
|
538
|
+
{
|
|
539
|
+
visible: true,
|
|
540
|
+
title: prePrompt.title,
|
|
541
|
+
message: prePrompt.message,
|
|
542
|
+
confirmLabel: prePrompt.confirmLabel,
|
|
543
|
+
cancelLabel: prePrompt.cancelLabel,
|
|
544
|
+
onConfirm: handler.request,
|
|
545
|
+
onCancel: handler.dismiss
|
|
546
|
+
}
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
if (handler.state === "blockedPrompt") {
|
|
550
|
+
if (renderBlockedPrompt) {
|
|
551
|
+
return /* @__PURE__ */ jsx3(Fragment, { children: renderBlockedPrompt({
|
|
552
|
+
config: blockedPrompt,
|
|
553
|
+
onOpenSettings: handler.openSettings
|
|
554
|
+
}) });
|
|
555
|
+
}
|
|
556
|
+
return /* @__PURE__ */ jsx3(
|
|
557
|
+
DefaultBlockedPrompt,
|
|
558
|
+
{
|
|
559
|
+
visible: true,
|
|
560
|
+
title: blockedPrompt.title,
|
|
561
|
+
message: blockedPrompt.message,
|
|
562
|
+
settingsLabel: blockedPrompt.settingsLabel,
|
|
563
|
+
onOpenSettings: handler.openSettings
|
|
564
|
+
}
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
return /* @__PURE__ */ jsx3(Fragment, { children: fallback });
|
|
568
|
+
}
|
|
569
|
+
export {
|
|
570
|
+
DefaultBlockedPrompt,
|
|
571
|
+
DefaultPrePrompt,
|
|
572
|
+
PermissionGate,
|
|
573
|
+
transition,
|
|
574
|
+
useMultiplePermissions,
|
|
575
|
+
usePermissionHandler
|
|
576
|
+
};
|
|
577
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/state-machine.ts","../src/hooks/use-permission-handler.ts","../src/hooks/use-multiple-permissions.ts","../src/components/default-blocked-prompt.tsx","../src/components/default-pre-prompt.tsx","../src/components/permission-gate.tsx"],"sourcesContent":["import type { PermissionFlowEvent, PermissionFlowState } from \"../types\";\n\nexport function transition(\n state: PermissionFlowState,\n event: PermissionFlowEvent,\n): PermissionFlowState {\n switch (state) {\n case \"idle\":\n if (event.type === \"CHECK\") return \"checking\";\n return state;\n\n case \"checking\":\n if (event.type === \"CHECK_RESULT\") {\n switch (event.status) {\n case \"granted\":\n case \"limited\":\n return \"granted\";\n case \"denied\":\n return \"prePrompt\";\n case \"blocked\":\n return \"blockedPrompt\";\n case \"unavailable\":\n return \"unavailable\";\n default:\n return state;\n }\n }\n return state;\n\n case \"prePrompt\":\n if (event.type === \"PRE_PROMPT_CONFIRM\") return \"requesting\";\n if (event.type === \"PRE_PROMPT_DISMISS\") return \"denied\";\n return state;\n\n case \"requesting\":\n if (event.type === \"REQUEST_RESULT\") {\n switch (event.status) {\n case \"granted\":\n case \"limited\":\n return \"granted\";\n case \"denied\":\n return \"denied\";\n case \"blocked\":\n return \"blockedPrompt\";\n default:\n return state;\n }\n }\n return state;\n\n case \"blockedPrompt\":\n if (event.type === \"OPEN_SETTINGS\") return \"openingSettings\";\n return state;\n\n case \"openingSettings\":\n if (event.type === \"SETTINGS_RETURN\") return \"recheckingAfterSettings\";\n return state;\n\n case \"recheckingAfterSettings\":\n if (event.type === \"RECHECK_RESULT\") {\n switch (event.status) {\n case \"granted\":\n case \"limited\":\n return \"granted\";\n case \"blocked\":\n return \"blockedPrompt\";\n case \"denied\":\n return \"blockedPrompt\";\n default:\n return state;\n }\n }\n return state;\n\n case \"granted\":\n case \"denied\":\n case \"unavailable\":\n if (event.type === \"CHECK\") return \"checking\";\n return state;\n\n case \"blocked\":\n return state;\n\n default:\n return state;\n }\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { AppState } from \"react-native\";\nimport {\n type PermissionStatus,\n check,\n checkNotifications,\n openSettings,\n request,\n requestNotifications,\n} from \"react-native-permissions\";\nimport { transition } from \"../core/state-machine\";\nimport type {\n PermissionFlowState,\n PermissionHandlerConfig,\n PermissionHandlerResult,\n} from \"../types\";\n\nfunction isNotifications(\n permission: PermissionHandlerConfig[\"permission\"],\n): permission is \"notifications\" {\n return permission === \"notifications\";\n}\n\nexport function usePermissionHandler(config: PermissionHandlerConfig): PermissionHandlerResult {\n const [flowState, setFlowState] = useState<PermissionFlowState>(\"idle\");\n const [nativeStatus, setNativeStatus] = useState<PermissionStatus | null>(null);\n const isRequesting = useRef(false);\n const waitingForSettings = useRef(false);\n const appStateRef = useRef(AppState.currentState);\n\n const { permission, autoCheck = true, onGrant, onDeny, onBlock, onSettingsReturn } = config;\n\n const checkPermission = useCallback(async () => {\n setFlowState((s) => transition(s, { type: \"CHECK\" }));\n try {\n let status: PermissionStatus;\n if (isNotifications(permission)) {\n const result = await checkNotifications();\n status = result.status;\n } else {\n status = await check(permission);\n }\n setNativeStatus(status);\n setFlowState((s) => {\n const next = transition(s, { type: \"CHECK_RESULT\", status });\n if (next === \"granted\" && s !== \"granted\") onGrant?.();\n return next;\n });\n } catch {\n setFlowState(\"idle\");\n }\n }, [permission, onGrant]);\n\n const requestPermission = useCallback(async () => {\n if (isRequesting.current) return;\n isRequesting.current = true;\n\n setFlowState((s) => transition(s, { type: \"PRE_PROMPT_CONFIRM\" }));\n try {\n let status: PermissionStatus;\n if (isNotifications(permission)) {\n const result = await requestNotifications([\"alert\", \"badge\", \"sound\"]);\n status = result.status;\n } else {\n status = await request(permission);\n }\n setNativeStatus(status);\n setFlowState((s) => {\n const next = transition(s, { type: \"REQUEST_RESULT\", status });\n if (next === \"granted\") onGrant?.();\n if (next === \"denied\") onDeny?.();\n if (next === \"blockedPrompt\") onBlock?.();\n return next;\n });\n } catch {\n setFlowState(\"denied\");\n } finally {\n isRequesting.current = false;\n }\n }, [permission, onGrant, onDeny, onBlock]);\n\n const dismiss = useCallback(() => {\n setFlowState((s) => transition(s, { type: \"PRE_PROMPT_DISMISS\" }));\n onDeny?.();\n }, [onDeny]);\n\n const goToSettings = useCallback(async () => {\n setFlowState((s) => transition(s, { type: \"OPEN_SETTINGS\" }));\n waitingForSettings.current = true;\n try {\n await openSettings();\n } catch {\n waitingForSettings.current = false;\n setFlowState(\"blockedPrompt\");\n }\n }, []);\n\n const recheckAfterSettings = useCallback(async () => {\n setFlowState((s) => transition(s, { type: \"SETTINGS_RETURN\" }));\n try {\n let status: PermissionStatus;\n if (isNotifications(permission)) {\n const result = await checkNotifications();\n status = result.status;\n } else {\n status = await check(permission);\n }\n setNativeStatus(status);\n setFlowState((s) => {\n const next = transition(s, { type: \"RECHECK_RESULT\", status });\n if (next === \"granted\") onGrant?.();\n onSettingsReturn?.(next === \"granted\");\n return next;\n });\n } catch {\n setFlowState(\"blockedPrompt\");\n }\n }, [permission, onGrant, onSettingsReturn]);\n\n // Auto-check on mount\n // biome-ignore lint/correctness/useExhaustiveDependencies: intentional mount-only effect\n useEffect(() => {\n if (autoCheck) {\n checkPermission();\n }\n }, []);\n\n // AppState listener for settings return\n useEffect(() => {\n const subscription = AppState.addEventListener(\"change\", (nextAppState) => {\n if (\n appStateRef.current.match(/inactive|background/) &&\n nextAppState === \"active\" &&\n waitingForSettings.current\n ) {\n waitingForSettings.current = false;\n recheckAfterSettings();\n }\n appStateRef.current = nextAppState;\n });\n return () => subscription.remove();\n }, [recheckAfterSettings]);\n\n return {\n state: flowState,\n nativeStatus,\n isGranted: flowState === \"granted\",\n isDenied: flowState === \"denied\",\n isBlocked:\n flowState === \"blocked\" || flowState === \"blockedPrompt\" || flowState === \"openingSettings\",\n isChecking: flowState === \"checking\" || flowState === \"recheckingAfterSettings\",\n isUnavailable: flowState === \"unavailable\",\n request: requestPermission,\n check: checkPermission,\n dismiss,\n openSettings: goToSettings,\n };\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport {\n type PermissionStatus,\n check,\n checkNotifications,\n request,\n requestNotifications,\n} from \"react-native-permissions\";\nimport type {\n MultiPermissionEntry,\n MultiplePermissionsConfig,\n MultiplePermissionsResult,\n PermissionFlowState,\n} from \"../types\";\n\nfunction isNotifications(\n permission: MultiPermissionEntry[\"permission\"],\n): permission is \"notifications\" {\n return permission === \"notifications\";\n}\n\nasync function checkOne(entry: MultiPermissionEntry): Promise<PermissionStatus> {\n if (isNotifications(entry.permission)) {\n const result = await checkNotifications();\n return result.status;\n }\n return check(entry.permission);\n}\n\nasync function requestOne(entry: MultiPermissionEntry): Promise<PermissionStatus> {\n if (isNotifications(entry.permission)) {\n const result = await requestNotifications([\"alert\", \"badge\", \"sound\"]);\n return result.status;\n }\n return request(entry.permission);\n}\n\nfunction permissionKey(entry: MultiPermissionEntry): string {\n return String(entry.permission);\n}\n\nfunction isGrantedStatus(status: PermissionStatus): boolean {\n return status === \"granted\" || status === \"limited\";\n}\n\nexport function useMultiplePermissions(\n config: MultiplePermissionsConfig,\n): MultiplePermissionsResult {\n const { permissions, strategy, onAllGranted } = config;\n const [statuses, setStatuses] = useState<Record<string, PermissionFlowState>>(() => {\n const initial: Record<string, PermissionFlowState> = {};\n for (const entry of permissions) {\n initial[permissionKey(entry)] = \"idle\";\n }\n return initial;\n });\n const isRunning = useRef(false);\n\n const allGranted = permissions.every((entry) => statuses[permissionKey(entry)] === \"granted\");\n\n const requestAll = useCallback(async () => {\n if (isRunning.current) return;\n isRunning.current = true;\n\n const update = (key: string, state: PermissionFlowState) => {\n setStatuses((prev) => ({ ...prev, [key]: state }));\n };\n\n try {\n if (strategy === \"sequential\") {\n await runSequential(permissions, update);\n } else {\n await runParallel(permissions, update);\n }\n\n // Final check: are all granted?\n let allDone = true;\n for (const entry of permissions) {\n const finalStatus = await checkOne(entry);\n if (!isGrantedStatus(finalStatus)) {\n allDone = false;\n break;\n }\n }\n if (allDone) {\n onAllGranted?.();\n }\n } finally {\n isRunning.current = false;\n }\n }, [permissions, strategy, onAllGranted]);\n\n return {\n statuses,\n allGranted,\n request: requestAll,\n };\n}\n\nasync function runSequential(\n permissions: MultiPermissionEntry[],\n updateStatus: (key: string, state: PermissionFlowState) => void,\n): Promise<void> {\n for (const entry of permissions) {\n const key = permissionKey(entry);\n\n updateStatus(key, \"checking\");\n const checkStatus = await checkOne(entry);\n\n if (isGrantedStatus(checkStatus)) {\n updateStatus(key, \"granted\");\n entry.onGrant?.();\n continue;\n }\n\n if (checkStatus === \"unavailable\") {\n updateStatus(key, \"unavailable\");\n continue;\n }\n\n if (checkStatus === \"blocked\") {\n updateStatus(key, \"blockedPrompt\");\n entry.onBlock?.();\n break;\n }\n\n // Denied — request it\n updateStatus(key, \"requesting\");\n const requestStatus = await requestOne(entry);\n\n if (isGrantedStatus(requestStatus)) {\n updateStatus(key, \"granted\");\n entry.onGrant?.();\n } else if (requestStatus === \"blocked\") {\n updateStatus(key, \"blockedPrompt\");\n entry.onBlock?.();\n break;\n } else {\n updateStatus(key, \"denied\");\n entry.onDeny?.();\n break;\n }\n }\n}\n\nasync function runParallel(\n permissions: MultiPermissionEntry[],\n updateStatus: (key: string, state: PermissionFlowState) => void,\n): Promise<void> {\n // Check all in parallel\n const checkResults = await Promise.all(\n permissions.map(async (entry) => {\n const key = permissionKey(entry);\n updateStatus(key, \"checking\");\n const status = await checkOne(entry);\n return { entry, key, status };\n }),\n );\n\n // Update granted/unavailable immediately\n for (const { entry, key, status } of checkResults) {\n if (isGrantedStatus(status)) {\n updateStatus(key, \"granted\");\n entry.onGrant?.();\n } else if (status === \"unavailable\") {\n updateStatus(key, \"unavailable\");\n }\n }\n\n // Request denied/blocked ones sequentially (system dialogs are sequential)\n const needsAction = checkResults.filter(\n ({ status }) => status === \"denied\" || status === \"blocked\",\n );\n\n for (const { entry, key, status } of needsAction) {\n if (status === \"blocked\") {\n updateStatus(key, \"blockedPrompt\");\n entry.onBlock?.();\n continue;\n }\n\n updateStatus(key, \"requesting\");\n const requestStatus = await requestOne(entry);\n\n if (isGrantedStatus(requestStatus)) {\n updateStatus(key, \"granted\");\n entry.onGrant?.();\n } else if (requestStatus === \"blocked\") {\n updateStatus(key, \"blockedPrompt\");\n entry.onBlock?.();\n } else {\n updateStatus(key, \"denied\");\n entry.onDeny?.();\n }\n }\n}\n","import React from \"react\";\nimport { Modal, StyleSheet, Text, TouchableOpacity, View } from \"react-native\";\nimport type { BlockedPromptConfig } from \"../types\";\n\nexport interface DefaultBlockedPromptProps extends BlockedPromptConfig {\n visible: boolean;\n onOpenSettings: () => void;\n}\n\nexport function DefaultBlockedPrompt({\n visible,\n title,\n message,\n settingsLabel = \"Open Settings\",\n onOpenSettings,\n}: DefaultBlockedPromptProps) {\n return (\n <Modal visible={visible} transparent animationType=\"fade\">\n <View style={styles.overlay}>\n <View style={styles.modal}>\n <Text style={styles.title}>{title}</Text>\n <Text style={styles.message}>{message}</Text>\n <TouchableOpacity\n style={styles.settingsButton}\n onPress={onOpenSettings}\n accessibilityRole=\"button\"\n >\n <Text style={styles.settingsText}>{settingsLabel}</Text>\n </TouchableOpacity>\n </View>\n </View>\n </Modal>\n );\n}\n\nconst styles = StyleSheet.create({\n overlay: {\n flex: 1,\n backgroundColor: \"rgba(0,0,0,0.5)\",\n justifyContent: \"center\",\n alignItems: \"center\",\n },\n modal: {\n backgroundColor: \"white\",\n borderRadius: 16,\n padding: 24,\n width: \"85%\",\n alignItems: \"center\",\n },\n title: {\n fontSize: 20,\n fontWeight: \"600\",\n marginBottom: 12,\n textAlign: \"center\",\n },\n message: {\n fontSize: 15,\n color: \"#666\",\n textAlign: \"center\",\n marginBottom: 24,\n lineHeight: 22,\n },\n settingsButton: {\n backgroundColor: \"#007AFF\",\n borderRadius: 12,\n paddingVertical: 14,\n paddingHorizontal: 32,\n width: \"100%\",\n alignItems: \"center\",\n },\n settingsText: {\n color: \"white\",\n fontSize: 16,\n fontWeight: \"600\",\n },\n});\n","import React from \"react\";\nimport { Modal, StyleSheet, Text, TouchableOpacity, View } from \"react-native\";\nimport type { PrePromptConfig } from \"../types\";\n\nexport interface DefaultPrePromptProps extends PrePromptConfig {\n visible: boolean;\n onConfirm: () => void;\n onCancel: () => void;\n}\n\nexport function DefaultPrePrompt({\n visible,\n title,\n message,\n confirmLabel = \"Continue\",\n cancelLabel = \"Not Now\",\n onConfirm,\n onCancel,\n}: DefaultPrePromptProps) {\n return (\n <Modal visible={visible} transparent animationType=\"fade\">\n <View style={styles.overlay}>\n <View style={styles.modal}>\n <Text style={styles.title}>{title}</Text>\n <Text style={styles.message}>{message}</Text>\n <TouchableOpacity\n style={styles.confirmButton}\n onPress={onConfirm}\n accessibilityRole=\"button\"\n >\n <Text style={styles.confirmText}>{confirmLabel}</Text>\n </TouchableOpacity>\n <TouchableOpacity onPress={onCancel} accessibilityRole=\"button\">\n <Text style={styles.cancelText}>{cancelLabel}</Text>\n </TouchableOpacity>\n </View>\n </View>\n </Modal>\n );\n}\n\nconst styles = StyleSheet.create({\n overlay: {\n flex: 1,\n backgroundColor: \"rgba(0,0,0,0.5)\",\n justifyContent: \"center\",\n alignItems: \"center\",\n },\n modal: {\n backgroundColor: \"white\",\n borderRadius: 16,\n padding: 24,\n width: \"85%\",\n alignItems: \"center\",\n },\n title: {\n fontSize: 20,\n fontWeight: \"600\",\n marginBottom: 12,\n textAlign: \"center\",\n },\n message: {\n fontSize: 15,\n color: \"#666\",\n textAlign: \"center\",\n marginBottom: 24,\n lineHeight: 22,\n },\n confirmButton: {\n backgroundColor: \"#007AFF\",\n borderRadius: 12,\n paddingVertical: 14,\n paddingHorizontal: 32,\n width: \"100%\",\n alignItems: \"center\",\n marginBottom: 12,\n },\n confirmText: {\n color: \"white\",\n fontSize: 16,\n fontWeight: \"600\",\n },\n cancelText: {\n color: \"#007AFF\",\n fontSize: 15,\n },\n});\n","import React from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { Permission } from \"react-native-permissions\";\nimport { usePermissionHandler } from \"../hooks/use-permission-handler\";\nimport type { BlockedPromptConfig, PermissionCallbacks, PrePromptConfig } from \"../types\";\nimport { DefaultBlockedPrompt } from \"./default-blocked-prompt\";\nimport { DefaultPrePrompt } from \"./default-pre-prompt\";\n\nexport interface PermissionGateProps extends PermissionCallbacks {\n permission: Permission | \"notifications\";\n prePrompt: PrePromptConfig;\n blockedPrompt: BlockedPromptConfig;\n children: ReactNode;\n fallback?: ReactNode;\n renderPrePrompt?: (props: {\n config: PrePromptConfig;\n onConfirm: () => void;\n onCancel: () => void;\n }) => ReactNode;\n renderBlockedPrompt?: (props: {\n config: BlockedPromptConfig;\n onOpenSettings: () => void;\n }) => ReactNode;\n}\n\nexport function PermissionGate({\n permission,\n prePrompt,\n blockedPrompt,\n children,\n fallback = null,\n renderPrePrompt,\n renderBlockedPrompt,\n onGrant,\n onDeny,\n onBlock,\n onSettingsReturn,\n}: PermissionGateProps) {\n const handler = usePermissionHandler({\n permission,\n prePrompt,\n blockedPrompt,\n onGrant,\n onDeny,\n onBlock,\n onSettingsReturn,\n });\n\n if (handler.isGranted) {\n return <>{children}</>;\n }\n\n if (handler.isChecking || handler.isUnavailable) {\n return <>{fallback}</>;\n }\n\n if (handler.state === \"prePrompt\") {\n if (renderPrePrompt) {\n return (\n <>\n {renderPrePrompt({\n config: prePrompt,\n onConfirm: handler.request,\n onCancel: handler.dismiss,\n })}\n </>\n );\n }\n return (\n <DefaultPrePrompt\n visible\n title={prePrompt.title}\n message={prePrompt.message}\n confirmLabel={prePrompt.confirmLabel}\n cancelLabel={prePrompt.cancelLabel}\n onConfirm={handler.request}\n onCancel={handler.dismiss}\n />\n );\n }\n\n if (handler.state === \"blockedPrompt\") {\n if (renderBlockedPrompt) {\n return (\n <>\n {renderBlockedPrompt({\n config: blockedPrompt,\n onOpenSettings: handler.openSettings,\n })}\n </>\n );\n }\n return (\n <DefaultBlockedPrompt\n visible\n title={blockedPrompt.title}\n message={blockedPrompt.message}\n settingsLabel={blockedPrompt.settingsLabel}\n onOpenSettings={handler.openSettings}\n />\n );\n }\n\n return <>{fallback}</>;\n}\n"],"mappings":"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","names":["useCallback","useRef","useState","check","checkNotifications","request","requestNotifications","isNotifications","Modal","StyleSheet","Text","TouchableOpacity","View","jsx","jsxs","styles","jsx"]}
|