rn-system-bar 3.0.3 → 3.1.1

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.
@@ -0,0 +1,19 @@
1
+ import type { NavigationBarBehavior, NavigationBarButtonStyle, NavigationBarStyle, NavigationBarVisibility, Orientation, ScreencastInfo, StatusBarStyle } from "./types";
2
+ export interface SystemBarConfig {
3
+ navigationBarColor?: string;
4
+ navigationBarVisibility?: NavigationBarVisibility;
5
+ navigationBarButtonStyle?: NavigationBarButtonStyle;
6
+ navigationBarStyle?: NavigationBarStyle;
7
+ navigationBarBehavior?: NavigationBarBehavior;
8
+ statusBarColor?: string;
9
+ statusBarStyle?: StatusBarStyle;
10
+ statusBarVisible?: boolean;
11
+ statusBarAnimated?: boolean;
12
+ keepScreenOn?: boolean;
13
+ immersiveMode?: boolean;
14
+ brightness?: number;
15
+ orientation?: Orientation;
16
+ secureScreen?: boolean;
17
+ }
18
+ export declare const useSystemBar: (config: SystemBarConfig) => void;
19
+ export declare const useScreencast: () => ScreencastInfo;
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ // ─────────────────────────────────────────────
3
+ // rn-system-bar · useSystemBar.ts
4
+ // ─────────────────────────────────────────────
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.useScreencast = exports.useSystemBar = void 0;
40
+ const react_1 = require("react");
41
+ const SystemBar = __importStar(require("./SystemBar"));
42
+ const useSystemBar = (config) => {
43
+ const configRef = (0, react_1.useRef)("");
44
+ const configStr = JSON.stringify(config);
45
+ (0, react_1.useEffect)(() => {
46
+ if (configRef.current === configStr)
47
+ return;
48
+ configRef.current = configStr;
49
+ const apply = async () => {
50
+ const p = [];
51
+ if (config.navigationBarColor !== undefined)
52
+ SystemBar.setNavigationBarColor(config.navigationBarColor);
53
+ if (config.navigationBarVisibility !== undefined)
54
+ p.push(SystemBar.setNavigationBarVisibility(config.navigationBarVisibility));
55
+ if (config.navigationBarButtonStyle !== undefined)
56
+ p.push(SystemBar.setNavigationBarButtonStyle(config.navigationBarButtonStyle));
57
+ if (config.navigationBarStyle !== undefined)
58
+ p.push(SystemBar.setNavigationBarStyle(config.navigationBarStyle));
59
+ if (config.navigationBarBehavior !== undefined)
60
+ p.push(SystemBar.setNavigationBarBehavior(config.navigationBarBehavior));
61
+ await Promise.allSettled(p);
62
+ if (config.statusBarColor !== undefined)
63
+ SystemBar.setStatusBarColor(config.statusBarColor, config.statusBarAnimated);
64
+ if (config.statusBarStyle !== undefined)
65
+ SystemBar.setStatusBarStyle(config.statusBarStyle, config.statusBarAnimated);
66
+ if (config.statusBarVisible !== undefined)
67
+ SystemBar.setStatusBarVisibility(config.statusBarVisible, config.statusBarAnimated);
68
+ if (config.keepScreenOn !== undefined)
69
+ SystemBar.keepScreenOn(config.keepScreenOn);
70
+ if (config.immersiveMode !== undefined)
71
+ SystemBar.immersiveMode(config.immersiveMode);
72
+ if (config.brightness !== undefined)
73
+ SystemBar.setBrightness(config.brightness);
74
+ if (config.orientation !== undefined)
75
+ SystemBar.setOrientation(config.orientation);
76
+ if (config.secureScreen !== undefined)
77
+ SystemBar.setSecureScreen(config.secureScreen);
78
+ };
79
+ apply().catch(() => {
80
+ if (__DEV__)
81
+ console.warn("[rn-system-bar] useSystemBar: one or more settings failed.");
82
+ });
83
+ // eslint-disable-next-line react-hooks/exhaustive-deps
84
+ }, [configStr]);
85
+ };
86
+ exports.useSystemBar = useSystemBar;
87
+ // ─────────────────────────────────────────────
88
+ // useScreencast
89
+ // ─────────────────────────────────────────────
90
+ const useScreencast = () => {
91
+ const [info, setInfo] = (0, react_1.useState)({
92
+ isCasting: false,
93
+ displayName: null,
94
+ });
95
+ (0, react_1.useEffect)(() => {
96
+ SystemBar.getScreencastInfo().then(setInfo).catch(() => { });
97
+ const unsub = SystemBar.onScreencastChange(setInfo);
98
+ return () => unsub();
99
+ }, []);
100
+ return info;
101
+ };
102
+ exports.useScreencast = useScreencast;
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "rn-system-bar",
3
- "version": "3.0.3",
3
+ "version": "3.1.1",
4
4
  "description": "Control Android & iOS system bars, brightness, volume, orientation and screen flags from React Native.",
5
- "main": "index.ts",
6
- "react-native": "index.ts",
7
- "types": "src/types.ts",
5
+ "main": "lib/index.js",
6
+ "react-native": "lib/index.js",
7
+ "types": "lib/index.d.ts",
8
8
  "homepage": "https://github.com/your-org/rn-system-bar",
9
9
  "license": "MIT",
10
10
  "author": "Your Name",
@@ -23,6 +23,7 @@
23
23
  "files": [
24
24
  "index.ts",
25
25
  "src/",
26
+ "lib/",
26
27
  "specs/",
27
28
  "android/",
28
29
  "ios/",
@@ -31,5 +32,15 @@
31
32
  "peerDependencies": {
32
33
  "react": ">=18.0.0",
33
34
  "react-native": ">=0.73.0"
35
+ },
36
+ "scripts": {
37
+ "build": "rimraf lib && npx tsc",
38
+ "npm:prepublish": "npm publish --access public",
39
+ "installing": "cd .. && npm install rn-system-bar@latest && cd rn-system-bar"
40
+ },
41
+ "devDependencies": {
42
+ "@types/react": "^19.2.14",
43
+ "@types/react-native": "^0.72.8",
44
+ "typescript": "^5.9.3"
34
45
  }
35
46
  }
package/src/SystemBar.ts CHANGED
@@ -1,9 +1,7 @@
1
1
  // ─────────────────────────────────────────────
2
2
  // rn-system-bar · SystemBar.ts
3
- // v4 — expo-navigation-bar based, zero deprecated APIs
4
3
  // ─────────────────────────────────────────────
5
4
 
6
- import * as NavigationBar from "expo-navigation-bar";
7
5
  import { NativeModules, Platform, StatusBar } from "react-native";
8
6
 
9
7
  import type {
@@ -12,222 +10,171 @@ import type {
12
10
  NavigationBarStyle,
13
11
  NavigationBarVisibility,
14
12
  Orientation,
13
+ ScreencastInfo,
15
14
  StatusBarStyle,
16
15
  VolumeStream,
17
16
  } from "./types";
18
17
 
19
- const { SystemBar: SystemBarNative } = NativeModules;
18
+ const NavBar = (() => {
19
+ try { return require("expo-navigation-bar"); }
20
+ catch { return null; }
21
+ })();
22
+
23
+ const { SystemBar: Native } = NativeModules;
20
24
 
21
25
  const isAndroid = Platform.OS === "android";
22
26
 
23
27
  const androidOnly = (name: string): boolean => {
24
28
  if (!isAndroid) {
25
- if (__DEV__) {
26
- console.warn(
27
- `[rn-system-bar] ${name}() is Android-only and is a no-op on iOS.`,
28
- );
29
- }
29
+ if (__DEV__) console.warn(`[rn-system-bar] ${name}() is Android-only, no-op on iOS.`);
30
30
  return false;
31
31
  }
32
32
  return true;
33
33
  };
34
34
 
35
35
  const checkNative = () => {
36
- if (!SystemBarNative) {
37
- throw new Error(
38
- "[rn-system-bar] Native module not found. Rebuild your Android/iOS project.",
39
- );
40
- }
36
+ if (!Native) throw new Error("[rn-system-bar] Native module not found. Rebuild your project.");
41
37
  };
42
38
 
43
39
  // ═══════════════════════════════════════════════
44
- // NAVIGATION BAR — expo-navigation-bar (Android only)
45
- // Uses WindowInsetsController internally on API 30+.
46
- // Zero deprecated APIs.
40
+ // NAVIGATION BAR (Android-only)
41
+ // Color native Window API (edge-to-edge safe)
42
+ // Others expo-navigation-bar (work in edge-to-edge)
47
43
  // ═══════════════════════════════════════════════
48
44
 
49
- /**
50
- * Set navigation bar background color.
51
- * @param color Hex string e.g. "#000000"
52
- * @platform android
53
- */
54
- export const setNavigationBarColor = (color: string): Promise<void> => {
55
- if (!androidOnly("setNavigationBarColor")) return Promise.resolve();
56
- return NavigationBar.setBackgroundColorAsync(color);
57
- };
58
-
59
- /**
60
- * Show or hide the navigation bar.
61
- * @platform android
62
- */
63
- export const setNavigationBarVisibility = (
64
- mode: NavigationBarVisibility,
65
- ): Promise<void> => {
45
+ export const setNavigationBarColor = (color: string): void => {
46
+ if (!androidOnly("setNavigationBarColor")) return;
47
+ checkNative();
48
+ Native.setNavigationBarColor(color);
49
+ };
50
+
51
+ export const setNavigationBarVisibility = (mode: NavigationBarVisibility): Promise<void> => {
66
52
  if (!androidOnly("setNavigationBarVisibility")) return Promise.resolve();
67
- return NavigationBar.setVisibilityAsync(mode);
53
+ return NavBar?.setVisibilityAsync(mode) ?? Promise.resolve();
68
54
  };
69
55
 
70
- /**
71
- * Set navigation bar icon/button style.
72
- * @param style "light" = white icons | "dark" = black icons
73
- * @platform android
74
- */
75
- export const setNavigationBarButtonStyle = (
76
- style: NavigationBarButtonStyle,
77
- ): Promise<void> => {
56
+ export const setNavigationBarButtonStyle = (style: NavigationBarButtonStyle): Promise<void> => {
78
57
  if (!androidOnly("setNavigationBarButtonStyle")) return Promise.resolve();
79
- return NavigationBar.setButtonStyleAsync(style);
58
+ return NavBar?.setButtonStyleAsync(style) ?? Promise.resolve();
80
59
  };
81
60
 
82
- /**
83
- * Set navigation bar visual style.
84
- * @platform android
85
- */
86
- export const setNavigationBarStyle = (
87
- style: NavigationBarStyle,
88
- ): Promise<void> => {
61
+ export const setNavigationBarStyle = (style: NavigationBarStyle): Promise<void> => {
89
62
  if (!androidOnly("setNavigationBarStyle")) return Promise.resolve();
90
- const buttonStyle: NavigationBarButtonStyle =
91
- style === "dark" || style === "auto" ? "dark" : "light";
92
- return NavigationBar.setButtonStyleAsync(buttonStyle);
93
- };
94
-
95
- /**
96
- * Set navigation bar gesture behavior.
97
- * @platform android
98
- */
99
- export const setNavigationBarBehavior = (
100
- behavior: NavigationBarBehavior,
101
- ): Promise<void> => {
63
+ const btn: NavigationBarButtonStyle = style === "dark" || style === "auto" ? "dark" : "light";
64
+ return NavBar?.setButtonStyleAsync(btn) ?? Promise.resolve();
65
+ };
66
+
67
+ export const setNavigationBarBehavior = (behavior: NavigationBarBehavior): Promise<void> => {
102
68
  if (!androidOnly("setNavigationBarBehavior")) return Promise.resolve();
103
- return NavigationBar.setBehaviorAsync(behavior);
69
+ return NavBar?.setBehaviorAsync(behavior) ?? Promise.resolve();
104
70
  };
105
71
 
106
72
  // ═══════════════════════════════════════════════
107
73
  // STATUS BAR
108
- // React Native StatusBar — cross-platform, no deprecated APIs.
109
74
  // ═══════════════════════════════════════════════
110
75
 
111
- /**
112
- * Set status bar background color.
113
- * @platform android
114
- */
115
76
  export const setStatusBarColor = (color: string, animated = false): void => {
116
77
  if (!androidOnly("setStatusBarColor")) return;
117
78
  StatusBar.setBackgroundColor(color, animated);
118
79
  };
119
80
 
120
- /**
121
- * Set status bar icon style.
122
- * "light" = white icons | "dark" = dark icons
123
- */
124
- export const setStatusBarStyle = (
125
- style: StatusBarStyle,
126
- animated = false,
127
- ): void => {
128
- StatusBar.setBarStyle(
129
- style === "light" ? "light-content" : "dark-content",
130
- animated,
131
- );
132
- };
133
-
134
- /**
135
- * Show or hide the status bar.
136
- */
137
- export const setStatusBarVisibility = (
138
- visible: boolean,
139
- animated = false,
140
- ): void => {
81
+ export const setStatusBarStyle = (style: StatusBarStyle, animated = false): void => {
82
+ StatusBar.setBarStyle(style === "light" ? "light-content" : "dark-content", animated);
83
+ };
84
+
85
+ export const setStatusBarVisibility = (visible: boolean, animated = false): void => {
141
86
  StatusBar.setHidden(!visible, animated ? "slide" : "none");
142
87
  };
143
88
 
144
89
  // ═══════════════════════════════════════════════
145
- // BRIGHTNESS — native module
90
+ // BRIGHTNESS
91
+ //
92
+ // setBrightness → updates BOTH window brightness (instant)
93
+ // AND system brightness (persisted).
94
+ // On first call: opens WRITE_SETTINGS if not granted.
95
+ //
96
+ // getBrightness → reads SYSTEM brightness so slider always
97
+ // matches the device brightness bar.
146
98
  // ═══════════════════════════════════════════════
147
99
 
148
- /**
149
- * Set screen brightness (0.0 – 1.0).
150
- */
151
100
  export const setBrightness = (level: number): void => {
152
101
  checkNative();
153
- SystemBarNative.setBrightness(Math.max(0, Math.min(1, level)));
102
+ Native.setBrightness(Math.max(0.01, Math.min(1, level)));
154
103
  };
155
104
 
156
- /**
157
- * Get current screen brightness.
158
- * @returns Promise<number> 0.0 – 1.0
159
- */
160
105
  export const getBrightness = (): Promise<number> => {
161
106
  checkNative();
162
- return SystemBarNative.getBrightness();
107
+ return Native.getBrightness();
163
108
  };
164
109
 
165
110
  // ═══════════════════════════════════════════════
166
- // VOLUME — native module
111
+ // VOLUME
167
112
  // ═══════════════════════════════════════════════
168
113
 
169
- /**
170
- * Set volume level (0.0 – 1.0).
171
- * @param stream "music" | "ring" | "notification" | "alarm" | "system"
172
- */
173
- export const setVolume = (
174
- level: number,
175
- stream: VolumeStream = "music",
176
- ): void => {
114
+ export const setVolume = (level: number, stream: VolumeStream = "music"): void => {
177
115
  checkNative();
178
- SystemBarNative.setVolume(Math.max(0, Math.min(1, level)), stream);
116
+ Native.setVolume(Math.max(0, Math.min(1, level)), stream);
179
117
  };
180
118
 
181
- /**
182
- * Get current volume level (0.0 – 1.0).
183
- */
184
119
  export const getVolume = (stream: VolumeStream = "music"): Promise<number> => {
185
120
  checkNative();
186
- return SystemBarNative.getVolume(stream);
121
+ return Native.getVolume(stream);
187
122
  };
188
123
 
189
- /**
190
- * Show or hide the system volume popup.
191
- * @platform android
192
- */
193
124
  export const setVolumeHUDVisible = (visible: boolean): void => {
194
125
  if (!androidOnly("setVolumeHUDVisible")) return;
195
126
  checkNative();
196
- SystemBarNative.setVolumeHUDVisible(visible);
127
+ Native.setVolumeHUDVisible(visible);
197
128
  };
198
129
 
199
130
  // ═══════════════════════════════════════════════
200
- // SCREEN — native module
131
+ // SCREEN
201
132
  // ═══════════════════════════════════════════════
202
133
 
203
- /**
204
- * Prevent the screen from going to sleep.
205
- */
206
134
  export const keepScreenOn = (enable: boolean): void => {
207
135
  checkNative();
208
- SystemBarNative.keepScreenOn(enable);
136
+ Native.keepScreenOn(enable);
209
137
  };
210
138
 
211
- /**
212
- * Enable immersive fullscreen (hides status + nav bar).
213
- * Uses WindowInsetsController on API 30+.
214
- * @platform android
215
- */
216
139
  export const immersiveMode = (enable: boolean): void => {
217
140
  if (!androidOnly("immersiveMode")) return;
218
141
  checkNative();
219
- SystemBarNative.immersiveMode(enable);
142
+ Native.immersiveMode(enable);
143
+ };
144
+
145
+ export const setSecureScreen = (enable: boolean): void => {
146
+ if (!androidOnly("setSecureScreen")) return;
147
+ checkNative();
148
+ Native.setSecureScreen(enable);
220
149
  };
221
150
 
222
151
  // ═══════════════════════════════════════════════
223
- // ORIENTATION — native module
152
+ // ORIENTATION
224
153
  // ═══════════════════════════════════════════════
225
154
 
226
- /**
227
- * Lock or unlock screen orientation.
228
- * "portrait" | "landscape" | "landscape-left" | "landscape-right" | "auto"
229
- */
230
155
  export const setOrientation = (mode: Orientation): void => {
231
156
  checkNative();
232
- SystemBarNative.setOrientation(mode);
157
+ Native.setOrientation(mode);
158
+ };
159
+
160
+ // ═══════════════════════════════════════════════
161
+ // SCREENCAST
162
+ // ═══════════════════════════════════════════════
163
+
164
+ export const getScreencastInfo = (): Promise<ScreencastInfo> => {
165
+ checkNative();
166
+ return Native.getScreencastInfo();
167
+ };
168
+
169
+ export const onScreencastChange = (
170
+ callback: (info: ScreencastInfo) => void
171
+ ): (() => void) => {
172
+ checkNative();
173
+ const { DeviceEventEmitter } = require("react-native");
174
+ Native.startScreencastListener();
175
+ const sub = DeviceEventEmitter.addListener("SystemBar_ScreencastChange", callback);
176
+ return () => {
177
+ sub.remove();
178
+ Native.stopScreencastListener();
179
+ };
233
180
  };
package/src/types.ts CHANGED
@@ -3,27 +3,14 @@
3
3
  // ─────────────────────────────────────────────
4
4
 
5
5
  export type NavigationBarBehavior =
6
- | "overlay-swipe" // Swipe from edge reveals bar briefly (overlay)
7
- | "inset-swipe" // Swipe insets content when bar appears
8
- | "inset-touch"; // Touch insets content when bar appears
6
+ | "overlay-swipe"
7
+ | "inset-swipe"
8
+ | "inset-touch";
9
9
 
10
- export type NavigationBarButtonStyle =
11
- | "light" // White / light-coloured icons
12
- | "dark"; // Black / dark-coloured icons
13
-
14
- export type NavigationBarStyle =
15
- | "auto" // System decides
16
- | "inverted" // Inverted from system
17
- | "light" // Light background nav bar
18
- | "dark"; // Dark background nav bar
19
-
20
- export type NavigationBarVisibility =
21
- | "visible"
22
- | "hidden";
23
-
24
- export type StatusBarStyle =
25
- | "light" // Light icons (for dark backgrounds)
26
- | "dark"; // Dark icons (for light backgrounds)
10
+ export type NavigationBarButtonStyle = "light" | "dark";
11
+ export type NavigationBarStyle = "auto" | "inverted" | "light" | "dark";
12
+ export type NavigationBarVisibility = "visible" | "hidden";
13
+ export type StatusBarStyle = "light" | "dark";
27
14
 
28
15
  export type Orientation =
29
16
  | "portrait"
@@ -39,32 +26,7 @@ export type VolumeStream =
39
26
  | "alarm"
40
27
  | "system";
41
28
 
42
- export interface SystemBarAPI {
43
- // Navigation Bar
44
- setNavigationBarColor(color: string): void;
45
- setNavigationBarVisibility(mode: NavigationBarVisibility): void;
46
- setNavigationBarButtonStyle(style: NavigationBarButtonStyle): void;
47
- setNavigationBarStyle(style: NavigationBarStyle): void;
48
- setNavigationBarBehavior(behavior: NavigationBarBehavior): void;
49
-
50
- // Status Bar
51
- setStatusBarColor(color: string): void;
52
- setStatusBarStyle(style: StatusBarStyle): void;
53
- setStatusBarVisibility(visible: boolean): void;
54
-
55
- // Brightness
56
- setBrightness(level: number): void;
57
- getBrightness(): Promise<number>;
58
-
59
- // Volume
60
- setVolume(level: number, stream?: VolumeStream): void;
61
- getVolume(stream?: VolumeStream): Promise<number>;
62
- setVolumeHUDVisible(visible: boolean): void;
63
-
64
- // Screen
65
- keepScreenOn(enable: boolean): void;
66
- immersiveMode(enable: boolean): void;
67
-
68
- // Orientation
69
- setOrientation(mode: Orientation): void;
29
+ export interface ScreencastInfo {
30
+ isCasting: boolean;
31
+ displayName: string | null;
70
32
  }
@@ -0,0 +1,90 @@
1
+ // ─────────────────────────────────────────────
2
+ // rn-system-bar · useSystemBar.ts
3
+ // ─────────────────────────────────────────────
4
+
5
+ import { useEffect, useRef, useState } from "react";
6
+ import type {
7
+ NavigationBarBehavior,
8
+ NavigationBarButtonStyle,
9
+ NavigationBarStyle,
10
+ NavigationBarVisibility,
11
+ Orientation,
12
+ ScreencastInfo,
13
+ StatusBarStyle,
14
+ } from "./types";
15
+ import * as SystemBar from "./SystemBar";
16
+
17
+ // ─────────────────────────────────────────────
18
+ // useSystemBar — apply system bar config safely
19
+ // All async calls run inside useEffect — no Suspense crash
20
+ // ─────────────────────────────────────────────
21
+ export interface SystemBarConfig {
22
+ navigationBarColor?: string;
23
+ navigationBarVisibility?: NavigationBarVisibility;
24
+ navigationBarButtonStyle?: NavigationBarButtonStyle;
25
+ navigationBarStyle?: NavigationBarStyle;
26
+ navigationBarBehavior?: NavigationBarBehavior;
27
+ statusBarColor?: string;
28
+ statusBarStyle?: StatusBarStyle;
29
+ statusBarVisible?: boolean;
30
+ statusBarAnimated?: boolean;
31
+ keepScreenOn?: boolean;
32
+ immersiveMode?: boolean;
33
+ brightness?: number;
34
+ orientation?: Orientation;
35
+ secureScreen?: boolean;
36
+ }
37
+
38
+ export const useSystemBar = (config: SystemBarConfig) => {
39
+ const configRef = useRef("");
40
+ const configStr = JSON.stringify(config);
41
+
42
+ useEffect(() => {
43
+ if (configRef.current === configStr) return;
44
+ configRef.current = configStr;
45
+
46
+ const apply = async () => {
47
+ const p: Promise<void>[] = [];
48
+
49
+ if (config.navigationBarColor !== undefined) SystemBar.setNavigationBarColor(config.navigationBarColor);
50
+ if (config.navigationBarVisibility !== undefined) p.push(SystemBar.setNavigationBarVisibility(config.navigationBarVisibility));
51
+ if (config.navigationBarButtonStyle !== undefined) p.push(SystemBar.setNavigationBarButtonStyle(config.navigationBarButtonStyle));
52
+ if (config.navigationBarStyle !== undefined) p.push(SystemBar.setNavigationBarStyle(config.navigationBarStyle));
53
+ if (config.navigationBarBehavior !== undefined) p.push(SystemBar.setNavigationBarBehavior(config.navigationBarBehavior));
54
+
55
+ await Promise.allSettled(p);
56
+
57
+ if (config.statusBarColor !== undefined) SystemBar.setStatusBarColor(config.statusBarColor, config.statusBarAnimated);
58
+ if (config.statusBarStyle !== undefined) SystemBar.setStatusBarStyle(config.statusBarStyle, config.statusBarAnimated);
59
+ if (config.statusBarVisible !== undefined) SystemBar.setStatusBarVisibility(config.statusBarVisible, config.statusBarAnimated);
60
+ if (config.keepScreenOn !== undefined) SystemBar.keepScreenOn(config.keepScreenOn);
61
+ if (config.immersiveMode !== undefined) SystemBar.immersiveMode(config.immersiveMode);
62
+ if (config.brightness !== undefined) SystemBar.setBrightness(config.brightness);
63
+ if (config.orientation !== undefined) SystemBar.setOrientation(config.orientation);
64
+ if (config.secureScreen !== undefined) SystemBar.setSecureScreen(config.secureScreen);
65
+ };
66
+
67
+ apply().catch(() => {
68
+ if (__DEV__) console.warn("[rn-system-bar] useSystemBar: one or more settings failed.");
69
+ });
70
+ // eslint-disable-next-line react-hooks/exhaustive-deps
71
+ }, [configStr]);
72
+ };
73
+
74
+ // ─────────────────────────────────────────────
75
+ // useScreencast
76
+ // ─────────────────────────────────────────────
77
+ export const useScreencast = () => {
78
+ const [info, setInfo] = useState<ScreencastInfo>({
79
+ isCasting: false,
80
+ displayName: null,
81
+ });
82
+
83
+ useEffect(() => {
84
+ SystemBar.getScreencastInfo().then(setInfo).catch(() => {});
85
+ const unsub = SystemBar.onScreencastChange(setInfo);
86
+ return () => unsub();
87
+ }, []);
88
+
89
+ return info;
90
+ };