react-native-permission-gate 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.
Files changed (50) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +225 -0
  3. package/lib/module/adapters/reactNativePermissions.js +97 -0
  4. package/lib/module/adapters/reactNativePermissions.js.map +1 -0
  5. package/lib/module/components/PermissionGate.js +60 -0
  6. package/lib/module/components/PermissionGate.js.map +1 -0
  7. package/lib/module/context.js +29 -0
  8. package/lib/module/context.js.map +1 -0
  9. package/lib/module/core/machine.js +107 -0
  10. package/lib/module/core/machine.js.map +1 -0
  11. package/lib/module/hooks/usePermission.js +162 -0
  12. package/lib/module/hooks/usePermission.js.map +1 -0
  13. package/lib/module/hooks/usePermissions.js +165 -0
  14. package/lib/module/hooks/usePermissions.js.map +1 -0
  15. package/lib/module/imperative.js +24 -0
  16. package/lib/module/imperative.js.map +1 -0
  17. package/lib/module/index.js +15 -0
  18. package/lib/module/index.js.map +1 -0
  19. package/lib/module/package.json +1 -0
  20. package/lib/module/types.js +2 -0
  21. package/lib/module/types.js.map +1 -0
  22. package/lib/typescript/package.json +1 -0
  23. package/lib/typescript/src/adapters/reactNativePermissions.d.ts +8 -0
  24. package/lib/typescript/src/adapters/reactNativePermissions.d.ts.map +1 -0
  25. package/lib/typescript/src/components/PermissionGate.d.ts +34 -0
  26. package/lib/typescript/src/components/PermissionGate.d.ts.map +1 -0
  27. package/lib/typescript/src/context.d.ts +22 -0
  28. package/lib/typescript/src/context.d.ts.map +1 -0
  29. package/lib/typescript/src/core/machine.d.ts +47 -0
  30. package/lib/typescript/src/core/machine.d.ts.map +1 -0
  31. package/lib/typescript/src/hooks/usePermission.d.ts +8 -0
  32. package/lib/typescript/src/hooks/usePermission.d.ts.map +1 -0
  33. package/lib/typescript/src/hooks/usePermissions.d.ts +32 -0
  34. package/lib/typescript/src/hooks/usePermissions.d.ts.map +1 -0
  35. package/lib/typescript/src/imperative.d.ts +13 -0
  36. package/lib/typescript/src/imperative.d.ts.map +1 -0
  37. package/lib/typescript/src/index.d.ts +11 -0
  38. package/lib/typescript/src/index.d.ts.map +1 -0
  39. package/lib/typescript/src/types.d.ts +89 -0
  40. package/lib/typescript/src/types.d.ts.map +1 -0
  41. package/package.json +145 -0
  42. package/src/adapters/reactNativePermissions.ts +119 -0
  43. package/src/components/PermissionGate.tsx +81 -0
  44. package/src/context.tsx +43 -0
  45. package/src/core/machine.ts +98 -0
  46. package/src/hooks/usePermission.ts +205 -0
  47. package/src/hooks/usePermissions.ts +241 -0
  48. package/src/imperative.ts +35 -0
  49. package/src/index.tsx +42 -0
  50. package/src/types.ts +114 -0
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+
3
+ import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
4
+ import { AppState } from 'react-native';
5
+ import { reduce } from "../core/machine.js";
6
+ import { PermissionContext } from "../context.js";
7
+ /**
8
+ * Headless permission-flow controller. Owns the state machine and wires its
9
+ * effects to the native adapter; renders nothing. Bring your own rationale and
10
+ * "blocked" UI and drive it off `phase` / `status`.
11
+ */
12
+ export function usePermission(name, options = {}) {
13
+ const ctx = useContext(PermissionContext);
14
+ const rationale = options.rationale ?? ctx.defaults.rationale ?? false;
15
+ const revalidateOnFocus = options.revalidateOnFocus ?? ctx.defaults.revalidateOnFocus ?? true;
16
+ const requestOnMount = options.requestOnMount ?? ctx.defaults.requestOnMount ?? false;
17
+ const onStatusChange = options.onStatusChange;
18
+ const adapter = options.adapter ?? ctx.adapter;
19
+ const supported = adapter.isSupported(name);
20
+ const neutral = () => ({
21
+ status: supported ? 'requestable' : 'unavailable',
22
+ phase: 'idle'
23
+ });
24
+ const [state, setState] = useState(neutral);
25
+
26
+ // Mirror volatile values in refs so async effect callbacks read fresh data
27
+ // and the public callbacks stay referentially stable.
28
+ const stateRef = useRef(state);
29
+ stateRef.current = state;
30
+ const rationaleRef = useRef(rationale);
31
+ rationaleRef.current = rationale;
32
+ const onStatusChangeRef = useRef(onStatusChange);
33
+ onStatusChangeRef.current = onStatusChange;
34
+ const requestOnMountRef = useRef(requestOnMount);
35
+ requestOnMountRef.current = requestOnMount;
36
+
37
+ // Single in-flight request. Dedupes concurrent/double `request()` calls so a
38
+ // double-tap can never orphan a promise or fire two native prompts.
39
+ const pendingRef = useRef(null);
40
+ const mountedRef = useRef(true);
41
+ const dispatch = useCallback(event => {
42
+ const {
43
+ state: next,
44
+ effects
45
+ } = reduce(stateRef.current, event, {
46
+ rationale: rationaleRef.current
47
+ });
48
+ stateRef.current = next;
49
+ if (mountedRef.current) setState(next);
50
+ for (const effect of effects) {
51
+ if (effect.type === 'resolve') {
52
+ const pending = pendingRef.current;
53
+ pendingRef.current = null;
54
+ pending?.resolve(effect.status);
55
+ } else if (effect.type === 'runRequest') {
56
+ adapter.request(name).then(status => dispatchRef.current({
57
+ type: 'REQUEST_RESULT',
58
+ status
59
+ })).catch(() => dispatchRef.current({
60
+ type: 'REQUEST_RESULT',
61
+ status: stateRef.current.status
62
+ }));
63
+ }
64
+ }
65
+ }, [adapter, name]);
66
+ const dispatchRef = useRef(dispatch);
67
+ dispatchRef.current = dispatch;
68
+ const request = useCallback(() => {
69
+ // Reuse the in-flight promise instead of starting a second flow.
70
+ if (pendingRef.current) return pendingRef.current.promise;
71
+ let resolve;
72
+ const promise = new Promise(r => {
73
+ resolve = r;
74
+ });
75
+ pendingRef.current = {
76
+ promise,
77
+ resolve
78
+ };
79
+ dispatchRef.current({
80
+ type: 'REQUEST'
81
+ });
82
+ return promise;
83
+ }, []);
84
+ const requestRef = useRef(request);
85
+ requestRef.current = request;
86
+ const confirmRationale = useCallback(() => dispatchRef.current({
87
+ type: 'CONFIRM_RATIONALE'
88
+ }), []);
89
+ const cancelRationale = useCallback(() => dispatchRef.current({
90
+ type: 'CANCEL_RATIONALE'
91
+ }), []);
92
+ const refresh = useCallback(async () => {
93
+ if (!supported) return 'unavailable';
94
+ const status = await adapter.check(name);
95
+ dispatchRef.current({
96
+ type: 'REFRESH_RESULT',
97
+ status
98
+ });
99
+ return status;
100
+ }, [adapter, name, supported]);
101
+ const refreshRef = useRef(refresh);
102
+ refreshRef.current = refresh;
103
+ const openSettings = useCallback(() => adapter.openSettings(), [adapter]);
104
+
105
+ // Initial check on mount and whenever the permission identity changes. On a
106
+ // change we reset to a neutral state first so a stale status never lingers.
107
+ const firstRunRef = useRef(true);
108
+ useEffect(() => {
109
+ mountedRef.current = true;
110
+ if (!firstRunRef.current) {
111
+ const reset = neutral();
112
+ stateRef.current = reset;
113
+ setState(reset);
114
+ pendingRef.current = null;
115
+ }
116
+ firstRunRef.current = false;
117
+ if (supported) {
118
+ adapter.check(name).then(status => {
119
+ dispatchRef.current({
120
+ type: 'CHECK_RESULT',
121
+ status
122
+ });
123
+ if (requestOnMountRef.current) requestRef.current();
124
+ }).catch(() => {});
125
+ }
126
+ return () => {
127
+ mountedRef.current = false;
128
+ };
129
+ // `neutral` is derived from supported; requestOnMount is read via ref.
130
+ // eslint-disable-next-line react-hooks/exhaustive-deps
131
+ }, [adapter, name, supported]);
132
+
133
+ // Re-check when the app returns to the foreground.
134
+ useEffect(() => {
135
+ if (!revalidateOnFocus || !supported) return;
136
+ const sub = AppState.addEventListener('change', next => {
137
+ if (next === 'active') refreshRef.current();
138
+ });
139
+ return () => sub.remove();
140
+ }, [revalidateOnFocus, supported]);
141
+
142
+ // Notify on resolved-status changes.
143
+ const prevStatusRef = useRef(state.status);
144
+ useEffect(() => {
145
+ if (prevStatusRef.current !== state.status) {
146
+ prevStatusRef.current = state.status;
147
+ onStatusChangeRef.current?.(state.status);
148
+ }
149
+ }, [state.status]);
150
+ return useMemo(() => ({
151
+ status: state.status,
152
+ phase: state.phase,
153
+ isGranted: state.status === 'granted',
154
+ isBlocked: state.status === 'blocked',
155
+ request,
156
+ confirmRationale,
157
+ cancelRationale,
158
+ openSettings,
159
+ refresh
160
+ }), [state.status, state.phase, request, confirmRationale, cancelRationale, openSettings, refresh]);
161
+ }
162
+ //# sourceMappingURL=usePermission.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useCallback","useContext","useEffect","useMemo","useRef","useState","AppState","reduce","PermissionContext","usePermission","name","options","ctx","rationale","defaults","revalidateOnFocus","requestOnMount","onStatusChange","adapter","supported","isSupported","neutral","status","phase","state","setState","stateRef","current","rationaleRef","onStatusChangeRef","requestOnMountRef","pendingRef","mountedRef","dispatch","event","next","effects","effect","type","pending","resolve","request","then","dispatchRef","catch","promise","Promise","r","requestRef","confirmRationale","cancelRationale","refresh","check","refreshRef","openSettings","firstRunRef","reset","sub","addEventListener","remove","prevStatusRef","isGranted","isBlocked"],"sourceRoot":"../../../src","sources":["hooks/usePermission.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+
3
+ import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
4
+ import { AppState } from 'react-native';
5
+ import { PermissionContext } from "../context.js";
6
+ /**
7
+ * Aggregate variant of {@link usePermission} for permissions acquired together
8
+ * (e.g. camera + microphone for video). One shared rationale gate, one
9
+ * `request()`, one status map. The `names` array is treated as a stable set -
10
+ * pass a constant or memoized array.
11
+ */
12
+ export function usePermissions(names, options = {}) {
13
+ const ctx = useContext(PermissionContext);
14
+ const rationale = options.rationale ?? ctx.defaults.rationale ?? false;
15
+ const revalidateOnFocus = options.revalidateOnFocus ?? ctx.defaults.revalidateOnFocus ?? true;
16
+ const requestOnMount = options.requestOnMount ?? ctx.defaults.requestOnMount ?? false;
17
+ const adapter = options.adapter ?? ctx.adapter;
18
+
19
+ // Stable identity for the set so effects don't re-run on every new array.
20
+ const key = names.join(',');
21
+ const buildInitial = useCallback(() => {
22
+ const map = {};
23
+ for (const name of names) {
24
+ map[name] = adapter.isSupported(name) ? 'requestable' : 'unavailable';
25
+ }
26
+ return map;
27
+ // eslint-disable-next-line react-hooks/exhaustive-deps
28
+ }, [adapter, key]);
29
+ const [statuses, setStatuses] = useState(buildInitial);
30
+ const [phase, setPhase] = useState('idle');
31
+ const statusesRef = useRef(statuses);
32
+ statusesRef.current = statuses;
33
+ const phaseRef = useRef(phase);
34
+ phaseRef.current = phase;
35
+ const rationaleRef = useRef(rationale);
36
+ rationaleRef.current = rationale;
37
+ const requestOnMountRef = useRef(requestOnMount);
38
+ requestOnMountRef.current = requestOnMount;
39
+ const pendingRef = useRef(null);
40
+ const requestableRef = useRef([]);
41
+ const mountedRef = useRef(true);
42
+ const commit = useCallback(next => {
43
+ statusesRef.current = next;
44
+ if (mountedRef.current) setStatuses(next);
45
+ }, []);
46
+ const settle = useCallback(() => {
47
+ if (mountedRef.current) setPhase('settled');
48
+ const pending = pendingRef.current;
49
+ pendingRef.current = null;
50
+ pending?.resolve(statusesRef.current);
51
+ }, []);
52
+ const runBatch = useCallback(async list => {
53
+ if (mountedRef.current) setPhase('requesting');
54
+ for (const name of list) {
55
+ try {
56
+ const status = await adapter.request(name);
57
+ commit({
58
+ ...statusesRef.current,
59
+ [name]: status
60
+ });
61
+ } catch {
62
+ // Keep the previous status for this permission on failure.
63
+ }
64
+ }
65
+ settle();
66
+ }, [adapter, commit, settle]);
67
+ const runBatchRef = useRef(runBatch);
68
+ runBatchRef.current = runBatch;
69
+ const request = useCallback(() => {
70
+ if (pendingRef.current) return pendingRef.current.promise;
71
+ let resolve;
72
+ const promise = new Promise(r => {
73
+ resolve = r;
74
+ });
75
+ pendingRef.current = {
76
+ promise,
77
+ resolve
78
+ };
79
+ const requestable = names.filter(name => statusesRef.current[name] === 'requestable');
80
+ requestableRef.current = requestable;
81
+ if (requestable.length === 0) {
82
+ settle();
83
+ } else if (rationaleRef.current) {
84
+ if (mountedRef.current) setPhase('rationale');
85
+ } else {
86
+ runBatchRef.current(requestable);
87
+ }
88
+ return promise;
89
+ // eslint-disable-next-line react-hooks/exhaustive-deps
90
+ }, [key, settle]);
91
+ const requestRef = useRef(request);
92
+ requestRef.current = request;
93
+ const confirmRationale = useCallback(() => {
94
+ if (phaseRef.current !== 'rationale') return;
95
+ runBatchRef.current(requestableRef.current);
96
+ }, []);
97
+ const cancelRationale = useCallback(() => {
98
+ if (phaseRef.current !== 'rationale') return;
99
+ if (mountedRef.current) setPhase('idle');
100
+ const pending = pendingRef.current;
101
+ pendingRef.current = null;
102
+ pending?.resolve(statusesRef.current);
103
+ }, []);
104
+ const refresh = useCallback(async () => {
105
+ const entries = await Promise.all(names.map(async name => {
106
+ if (!adapter.isSupported(name)) {
107
+ return [name, 'unavailable'];
108
+ }
109
+ return [name, await adapter.check(name)];
110
+ }));
111
+ const next = {};
112
+ for (const [name, status] of entries) next[name] = status;
113
+ commit(next);
114
+ return next;
115
+ // eslint-disable-next-line react-hooks/exhaustive-deps
116
+ }, [adapter, key, commit]);
117
+ const refreshRef = useRef(refresh);
118
+ refreshRef.current = refresh;
119
+ const openSettings = useCallback(() => adapter.openSettings(), [adapter]);
120
+
121
+ // Initial check on mount / when the set changes.
122
+ const firstRunRef = useRef(true);
123
+ useEffect(() => {
124
+ mountedRef.current = true;
125
+ if (!firstRunRef.current) {
126
+ commit(buildInitial());
127
+ setPhase('idle');
128
+ pendingRef.current = null;
129
+ }
130
+ firstRunRef.current = false;
131
+ refreshRef.current().then(() => {
132
+ if (requestOnMountRef.current) requestRef.current();
133
+ });
134
+ return () => {
135
+ mountedRef.current = false;
136
+ };
137
+ // eslint-disable-next-line react-hooks/exhaustive-deps
138
+ }, [key]);
139
+
140
+ // Re-check on foreground.
141
+ useEffect(() => {
142
+ if (!revalidateOnFocus) return;
143
+ const sub = AppState.addEventListener('change', next => {
144
+ if (next === 'active') refreshRef.current();
145
+ });
146
+ return () => sub.remove();
147
+ }, [revalidateOnFocus]);
148
+ return useMemo(() => {
149
+ const allGranted = names.every(name => statuses[name] === 'granted');
150
+ const anyBlocked = names.some(name => statuses[name] === 'blocked');
151
+ return {
152
+ statuses,
153
+ phase,
154
+ allGranted,
155
+ anyBlocked,
156
+ request,
157
+ confirmRationale,
158
+ cancelRationale,
159
+ openSettings,
160
+ refresh
161
+ };
162
+ // eslint-disable-next-line react-hooks/exhaustive-deps
163
+ }, [key, statuses, phase, request, confirmRationale, cancelRationale, openSettings, refresh]);
164
+ }
165
+ //# sourceMappingURL=usePermissions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useCallback","useContext","useEffect","useMemo","useRef","useState","AppState","PermissionContext","usePermissions","names","options","ctx","rationale","defaults","revalidateOnFocus","requestOnMount","adapter","key","join","buildInitial","map","name","isSupported","statuses","setStatuses","phase","setPhase","statusesRef","current","phaseRef","rationaleRef","requestOnMountRef","pendingRef","requestableRef","mountedRef","commit","next","settle","pending","resolve","runBatch","list","status","request","runBatchRef","promise","Promise","r","requestable","filter","length","requestRef","confirmRationale","cancelRationale","refresh","entries","all","check","refreshRef","openSettings","firstRunRef","then","sub","addEventListener","remove","allGranted","every","anyBlocked","some"],"sourceRoot":"../../../src","sources":["hooks/usePermissions.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+
3
+ import { reactNativePermissionsAdapter } from "./adapters/reactNativePermissions.js";
4
+ /**
5
+ * Imperative helpers for use outside React (services, sagas, utilities). These
6
+ * are the raw check/request/openSettings calls with no rationale UX - for the
7
+ * full flow with pre-prompts, use {@link usePermission} or {@link PermissionGate}.
8
+ */
9
+
10
+ /** Read current status without prompting. */
11
+ export function checkPermission(name, adapter = reactNativePermissionsAdapter) {
12
+ return adapter.check(name);
13
+ }
14
+
15
+ /** Trigger the native OS prompt and resolve with the resulting status. */
16
+ export function requestPermission(name, adapter = reactNativePermissionsAdapter) {
17
+ return adapter.request(name);
18
+ }
19
+
20
+ /** Open the OS settings screen for this app. */
21
+ export function openAppSettings(adapter = reactNativePermissionsAdapter) {
22
+ return adapter.openSettings();
23
+ }
24
+ //# sourceMappingURL=imperative.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["reactNativePermissionsAdapter","checkPermission","name","adapter","check","requestPermission","request","openAppSettings","openSettings"],"sourceRoot":"../../src","sources":["imperative.ts"],"mappings":";;AAAA,SAASA,6BAA6B,QAAQ,sCAAmC;AAOjF;AACA;AACA;AACA;AACA;;AAEA;AACA,OAAO,SAASC,eAAeA,CAC7BC,IAAoB,EACpBC,OAA0B,GAAGH,6BAA6B,EAC/B;EAC3B,OAAOG,OAAO,CAACC,KAAK,CAACF,IAAI,CAAC;AAC5B;;AAEA;AACA,OAAO,SAASG,iBAAiBA,CAC/BH,IAAoB,EACpBC,OAA0B,GAAGH,6BAA6B,EAC/B;EAC3B,OAAOG,OAAO,CAACG,OAAO,CAACJ,IAAI,CAAC;AAC9B;;AAEA;AACA,OAAO,SAASK,eAAeA,CAC7BJ,OAA0B,GAAGH,6BAA6B,EAC3C;EACf,OAAOG,OAAO,CAACK,YAAY,CAAC,CAAC;AAC/B","ignoreList":[]}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ // Hooks - the primary, headless API.
4
+ export { usePermission } from "./hooks/usePermission.js";
5
+ export { usePermissions } from "./hooks/usePermissions.js";
6
+ // Declarative convenience.
7
+ export { PermissionGate } from "./components/PermissionGate.js";
8
+ // Provider - optional shared adapter + default options.
9
+ export { PermissionProvider, PermissionContext } from "./context.js";
10
+ // Imperative helpers for use outside React.
11
+ export { checkPermission, requestPermission, openAppSettings } from "./imperative.js";
12
+
13
+ // Default adapter (override via options.adapter or PermissionProvider).
14
+ export { reactNativePermissionsAdapter } from "./adapters/reactNativePermissions.js";
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["usePermission","usePermissions","PermissionGate","PermissionProvider","PermissionContext","checkPermission","requestPermission","openAppSettings","reactNativePermissionsAdapter"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA;AACA,SAASA,aAAa,QAAQ,0BAAuB;AACrD,SAASC,cAAc,QAAQ,2BAAwB;AAMvD;AACA,SAASC,cAAc,QAAQ,gCAA6B;AAO5D;AACA,SAASC,kBAAkB,EAAEC,iBAAiB,QAAQ,cAAW;AAOjE;AACA,SACEC,eAAe,EACfC,iBAAiB,EACjBC,eAAe,QACV,iBAAc;;AAErB;AACA,SAASC,6BAA6B,QAAQ,sCAAmC","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["types.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,8 @@
1
+ import type { PermissionAdapter } from '../types.js';
2
+ /**
3
+ * Default adapter, backed by `react-native-permissions`. Notifications are a
4
+ * special case in the native library (a dedicated check/request API) and are
5
+ * routed accordingly.
6
+ */
7
+ export declare const reactNativePermissionsAdapter: PermissionAdapter;
8
+ //# sourceMappingURL=reactNativePermissions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactNativePermissions.d.ts","sourceRoot":"","sources":["../../../../src/adapters/reactNativePermissions.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,aAAU,CAAC;AA8DlB;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,EAAE,iBAmC3C,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { PermissionController, PermissionName, PermissionStatus, UsePermissionOptions } from '../types.js';
3
+ export interface RationaleControls {
4
+ confirm: () => void;
5
+ cancel: () => void;
6
+ status: PermissionStatus;
7
+ }
8
+ export interface BlockedControls {
9
+ openSettings: () => Promise<void>;
10
+ status: PermissionStatus;
11
+ }
12
+ export interface PermissionGateProps {
13
+ name: PermissionName;
14
+ /** Forwarded to the underlying `usePermission`. `requestOnMount` defaults to true here. */
15
+ options?: UsePermissionOptions;
16
+ /**
17
+ * Rendered once access is granted (or limited). Pass a function to take full
18
+ * control and render for every state yourself.
19
+ */
20
+ children: ReactNode | ((controller: PermissionController) => ReactNode);
21
+ /** Your pre-prompt UI, shown while `phase === 'rationale'`. */
22
+ rationale?: (controls: RationaleControls) => ReactNode;
23
+ /** Your "go to Settings" UI, shown while the permission is blocked. */
24
+ blocked?: (controls: BlockedControls) => ReactNode;
25
+ /** Shown while not yet granted and no rationale/blocked UI applies. */
26
+ fallback?: ReactNode;
27
+ }
28
+ /**
29
+ * Declarative convenience over {@link usePermission}. Gates its children behind
30
+ * a granted permission and lets you plug in your own rationale / blocked UI.
31
+ * Auto-runs the request flow on mount unless you override `requestOnMount`.
32
+ */
33
+ export declare function PermissionGate({ name, options, children, rationale, blocked, fallback, }: PermissionGateProps): import("react").JSX.Element;
34
+ //# sourceMappingURL=PermissionGate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PermissionGate.d.ts","sourceRoot":"","sources":["../../../../src/components/PermissionGate.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EACV,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,aAAU,CAAC;AAElB,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,cAAc,CAAC;IACrB,2FAA2F;IAC3F,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B;;;OAGG;IACH,QAAQ,EAAE,SAAS,GAAG,CAAC,CAAC,UAAU,EAAE,oBAAoB,KAAK,SAAS,CAAC,CAAC;IACxE,+DAA+D;IAC/D,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,iBAAiB,KAAK,SAAS,CAAC;IACvD,uEAAuE;IACvE,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,SAAS,CAAC;IACnD,uEAAuE;IACvE,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,SAAS,EACT,OAAO,EACP,QAAe,GAChB,EAAE,mBAAmB,+BA+BrB"}
@@ -0,0 +1,22 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { PermissionAdapter, UsePermissionOptions } from './types.js';
3
+ /** Options that can be defaulted for every hook/component under a provider. */
4
+ export type PermissionDefaults = Pick<UsePermissionOptions, 'rationale' | 'revalidateOnFocus' | 'requestOnMount'>;
5
+ export interface PermissionContextValue {
6
+ adapter: PermissionAdapter;
7
+ defaults: PermissionDefaults;
8
+ }
9
+ export declare const PermissionContext: import("react").Context<PermissionContextValue>;
10
+ export interface PermissionProviderProps {
11
+ /** Override the backend for the whole tree. */
12
+ adapter?: PermissionAdapter;
13
+ /** Default options applied to every `usePermission` / `PermissionGate`. */
14
+ defaults?: PermissionDefaults;
15
+ children: ReactNode;
16
+ }
17
+ /**
18
+ * Optional. Sets a shared adapter and default options for the subtree so you
19
+ * don't repeat them at every call site. `usePermission` works without it.
20
+ */
21
+ export declare function PermissionProvider({ adapter, defaults, children, }: PermissionProviderProps): import("react").JSX.Element;
22
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtD,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,YAAS,CAAC;AAEvE,+EAA+E;AAC/E,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACnC,oBAAoB,EACpB,WAAW,GAAG,mBAAmB,GAAG,gBAAgB,CACrD,CAAC;AAEF,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,QAAQ,EAAE,kBAAkB,CAAC;CAC9B;AAED,eAAO,MAAM,iBAAiB,iDAG5B,CAAC;AAEH,MAAM,WAAW,uBAAuB;IACtC,+CAA+C;IAC/C,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,OAAuC,EACvC,QAAa,EACb,QAAQ,GACT,EAAE,uBAAuB,+BAMzB"}
@@ -0,0 +1,47 @@
1
+ import type { FlowPhase, PermissionStatus } from '../types.js';
2
+ /**
3
+ * Pure, framework-free state machine that drives the permission UX flow.
4
+ *
5
+ * It has zero React and zero native dependencies: given the current state and an
6
+ * event, it returns the next state plus a list of side effects for the caller to
7
+ * interpret. This is what makes the whole flow unit-testable without a device.
8
+ */
9
+ export interface MachineState {
10
+ status: PermissionStatus;
11
+ phase: FlowPhase;
12
+ }
13
+ export type MachineEvent = {
14
+ type: 'REQUEST';
15
+ } | {
16
+ type: 'CONFIRM_RATIONALE';
17
+ } | {
18
+ type: 'CANCEL_RATIONALE';
19
+ } | {
20
+ type: 'REQUEST_RESULT';
21
+ status: PermissionStatus;
22
+ } | {
23
+ type: 'CHECK_RESULT';
24
+ status: PermissionStatus;
25
+ } | {
26
+ type: 'REFRESH_RESULT';
27
+ status: PermissionStatus;
28
+ };
29
+ export type MachineEffect =
30
+ /** Fire the adapter's native `request()`. */
31
+ {
32
+ type: 'runRequest';
33
+ }
34
+ /** Resolve the pending `request()` promise with a final status. */
35
+ | {
36
+ type: 'resolve';
37
+ status: PermissionStatus;
38
+ };
39
+ export interface MachineContext {
40
+ rationale: boolean;
41
+ }
42
+ export interface Transition {
43
+ state: MachineState;
44
+ effects: MachineEffect[];
45
+ }
46
+ export declare function reduce(state: MachineState, event: MachineEvent, ctx: MachineContext): Transition;
47
+ //# sourceMappingURL=machine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../../src/core/machine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAU,CAAC;AAE5D;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,gBAAgB,CAAC;IACzB,KAAK,EAAE,SAAS,CAAC;CAClB;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,mBAAmB,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAEzD,MAAM,MAAM,aAAa;AACvB,6CAA6C;AAC3C;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE;AACxB,mEAAmE;GACjE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAElD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAID,wBAAgB,MAAM,CACpB,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE,cAAc,GAClB,UAAU,CAsDZ"}
@@ -0,0 +1,8 @@
1
+ import type { PermissionController, PermissionName, UsePermissionOptions } from '../types.js';
2
+ /**
3
+ * Headless permission-flow controller. Owns the state machine and wires its
4
+ * effects to the native adapter; renders nothing. Bring your own rationale and
5
+ * "blocked" UI and drive it off `phase` / `status`.
6
+ */
7
+ export declare function usePermission(name: PermissionName, options?: UsePermissionOptions): PermissionController;
8
+ //# sourceMappingURL=usePermission.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePermission.d.ts","sourceRoot":"","sources":["../../../../src/hooks/usePermission.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,oBAAoB,EACpB,cAAc,EAEd,oBAAoB,EACrB,MAAM,aAAU,CAAC;AAOlB;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,cAAc,EACpB,OAAO,GAAE,oBAAyB,GACjC,oBAAoB,CA6KtB"}
@@ -0,0 +1,32 @@
1
+ import type { FlowPhase, PermissionName, PermissionStatus, UsePermissionOptions } from '../types.js';
2
+ export type PermissionStatusMap = Partial<Record<PermissionName, PermissionStatus>>;
3
+ export interface PermissionsController {
4
+ /** Current status per requested permission. */
5
+ statuses: PermissionStatusMap;
6
+ /** Shared flow position for the batch. */
7
+ phase: FlowPhase;
8
+ /** Every requested permission is `granted`. */
9
+ allGranted: boolean;
10
+ /** At least one requested permission is `blocked`. */
11
+ anyBlocked: boolean;
12
+ /**
13
+ * Run the flow for every not-yet-granted permission behind a single shared
14
+ * rationale gate. Prompts are shown one after another. Resolves with the
15
+ * final status map.
16
+ */
17
+ request: () => Promise<PermissionStatusMap>;
18
+ /** Proceed from the shared `rationale` phase to the prompts. */
19
+ confirmRationale: () => void;
20
+ /** Abort the shared `rationale` phase. */
21
+ cancelRationale: () => void;
22
+ openSettings: () => Promise<void>;
23
+ refresh: () => Promise<PermissionStatusMap>;
24
+ }
25
+ /**
26
+ * Aggregate variant of {@link usePermission} for permissions acquired together
27
+ * (e.g. camera + microphone for video). One shared rationale gate, one
28
+ * `request()`, one status map. The `names` array is treated as a stable set -
29
+ * pass a constant or memoized array.
30
+ */
31
+ export declare function usePermissions(names: PermissionName[], options?: UsePermissionOptions): PermissionsController;
32
+ //# sourceMappingURL=usePermissions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePermissions.d.ts","sourceRoot":"","sources":["../../../../src/hooks/usePermissions.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,SAAS,EACT,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,aAAU,CAAC;AAElB,MAAM,MAAM,mBAAmB,GAAG,OAAO,CACvC,MAAM,CAAC,cAAc,EAAE,gBAAgB,CAAC,CACzC,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,+CAA+C;IAC/C,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,0CAA0C;IAC1C,KAAK,EAAE,SAAS,CAAC;IACjB,+CAA+C;IAC/C,UAAU,EAAE,OAAO,CAAC;IACpB,sDAAsD;IACtD,UAAU,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC5C,gEAAgE;IAChE,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,0CAA0C;IAC1C,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,OAAO,EAAE,MAAM,OAAO,CAAC,mBAAmB,CAAC,CAAC;CAC7C;AAOD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,GAAE,oBAAyB,GACjC,qBAAqB,CAsLvB"}
@@ -0,0 +1,13 @@
1
+ import type { PermissionAdapter, PermissionName, PermissionStatus } from './types.js';
2
+ /**
3
+ * Imperative helpers for use outside React (services, sagas, utilities). These
4
+ * are the raw check/request/openSettings calls with no rationale UX - for the
5
+ * full flow with pre-prompts, use {@link usePermission} or {@link PermissionGate}.
6
+ */
7
+ /** Read current status without prompting. */
8
+ export declare function checkPermission(name: PermissionName, adapter?: PermissionAdapter): Promise<PermissionStatus>;
9
+ /** Trigger the native OS prompt and resolve with the resulting status. */
10
+ export declare function requestPermission(name: PermissionName, adapter?: PermissionAdapter): Promise<PermissionStatus>;
11
+ /** Open the OS settings screen for this app. */
12
+ export declare function openAppSettings(adapter?: PermissionAdapter): Promise<void>;
13
+ //# sourceMappingURL=imperative.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imperative.d.ts","sourceRoot":"","sources":["../../../src/imperative.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EACjB,MAAM,YAAS,CAAC;AAEjB;;;;GAIG;AAEH,6CAA6C;AAC7C,wBAAgB,eAAe,CAC7B,IAAI,EAAE,cAAc,EACpB,OAAO,GAAE,iBAAiD,GACzD,OAAO,CAAC,gBAAgB,CAAC,CAE3B;AAED,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,cAAc,EACpB,OAAO,GAAE,iBAAiD,GACzD,OAAO,CAAC,gBAAgB,CAAC,CAE3B;AAED,gDAAgD;AAChD,wBAAgB,eAAe,CAC7B,OAAO,GAAE,iBAAiD,GACzD,OAAO,CAAC,IAAI,CAAC,CAEf"}
@@ -0,0 +1,11 @@
1
+ export { usePermission } from './hooks/usePermission.js';
2
+ export { usePermissions } from './hooks/usePermissions.js';
3
+ export type { PermissionsController, PermissionStatusMap, } from './hooks/usePermissions.js';
4
+ export { PermissionGate } from './components/PermissionGate.js';
5
+ export type { PermissionGateProps, RationaleControls, BlockedControls, } from './components/PermissionGate.js';
6
+ export { PermissionProvider, PermissionContext } from './context.js';
7
+ export type { PermissionProviderProps, PermissionContextValue, PermissionDefaults, } from './context.js';
8
+ export { checkPermission, requestPermission, openAppSettings, } from './imperative.js';
9
+ export { reactNativePermissionsAdapter } from './adapters/reactNativePermissions.js';
10
+ export type { PermissionName, PermissionStatus, FlowPhase, PermissionController, PermissionAdapter, UsePermissionOptions, } from './types.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAAuB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAAwB,CAAC;AACxD,YAAY,EACV,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,2BAAwB,CAAC;AAGhC,OAAO,EAAE,cAAc,EAAE,MAAM,gCAA6B,CAAC;AAC7D,YAAY,EACV,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,GAChB,MAAM,gCAA6B,CAAC;AAGrC,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,cAAW,CAAC;AAClE,YAAY,EACV,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,cAAW,CAAC;AAGnB,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,eAAe,GAChB,MAAM,iBAAc,CAAC;AAGtB,OAAO,EAAE,6BAA6B,EAAE,MAAM,sCAAmC,CAAC;AAElF,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,oBAAoB,EACpB,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,YAAS,CAAC"}