rn-system-bar 3.2.3 → 3.2.5

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/src/types.ts CHANGED
@@ -14,20 +14,17 @@ export type StatusBarStyle = "light" | "dark";
14
14
 
15
15
  /**
16
16
  * Navigation bar color value.
17
- *
18
- * - Any CSS hex string solid colour e.g. "#1a1a2e", "#000"
19
- * - `"transparent"` fully transparent (FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS +
20
- * transparent color; content draws behind bar)
21
- * - `"translucent"` → semi-transparent (FLAG_TRANSLUCENT_NAVIGATION)
17
+ * - Any hex string → solid colour e.g. "#1a1a2e"
18
+ * - `"transparent"`fully transparent
19
+ * - `"translucent"` semi-transparent
22
20
  */
23
21
  export type NavigationBarColorValue = string | "transparent" | "translucent";
24
22
 
25
23
  /**
26
24
  * Status bar background color value.
27
- *
28
- * - Any CSS hex string solid colour
29
- * - `"transparent"` fully transparent (draws behind content)
30
- * - `"translucent"` → semi-transparent
25
+ * - Any hex string → solid colour
26
+ * - `"transparent"`fully transparent
27
+ * - `"translucent"` semi-transparent
31
28
  */
32
29
  export type StatusBarColorValue = string | "transparent" | "translucent";
33
30
 
@@ -35,19 +32,11 @@ export type StatusBarColorValue = string | "transparent" | "translucent";
35
32
  // Theme
36
33
  // ─────────────────────────────────────────────
37
34
 
38
- /**
39
- * "system" → follow the OS Appearance (dark/light).
40
- * "dark" → force dark.
41
- * "light" → force light.
42
- */
43
35
  export type ThemeMode = "system" | "dark" | "light";
44
36
 
45
37
  export interface ThemeState {
46
- /** Resolved dark-mode flag. Always a concrete boolean. */
47
38
  isDark: boolean;
48
- /** Currently active override ("system" = following OS). */
49
39
  mode: ThemeMode;
50
- /** Set the override mode. Pass "system" to revert to OS. */
51
40
  setMode: (mode: ThemeMode) => void;
52
41
  }
53
42
 
@@ -66,7 +55,7 @@ export type VolumeStream =
66
55
  | "system";
67
56
 
68
57
  // ─────────────────────────────────────────────
69
- // System screencast (external display / HDMI)
58
+ // System screencast (external display / HDMI / AirPlay)
70
59
  // ─────────────────────────────────────────────
71
60
 
72
61
  export interface ScreencastDisplay {
@@ -75,49 +64,77 @@ export interface ScreencastDisplay {
75
64
  isValid: boolean;
76
65
  }
77
66
 
78
- /** Result of getSystemScreencastInfo() — physical/HDMI/Miracast external display. */
79
67
  export interface SystemScreencastInfo {
80
68
  isCasting: boolean;
81
69
  displayName: string | null;
82
70
  displays: ScreencastDisplay[];
83
71
  }
84
72
 
73
+ /** @deprecated Use SystemScreencastInfo */
74
+ export interface ScreencastInfo extends SystemScreencastInfo {}
75
+
85
76
  // ─────────────────────────────────────────────
86
- // App-only cast (MediaRouter — Chromecast / TV)
77
+ // Network
87
78
  // ─────────────────────────────────────────────
88
79
 
89
- /** Connection state of the in-app cast session. */
90
- export type AppCastState =
91
- | "idle"
92
- | "scanning"
93
- | "connecting"
94
- | "connected"
95
- | "disconnecting";
96
-
97
- /** A discovered castable device (TV, Chromecast, etc.). */
98
- export interface AppCastDevice {
99
- /** Unique route ID from MediaRouter. */
100
- id: string;
101
- /** Human-readable device name e.g. "Living Room TV". */
102
- name: string;
103
- /** Device description / model string (may be null). */
104
- description: string | null;
105
- /** Signal strength 0–100, or null if unavailable. */
106
- signalStrength: number | null;
107
- /** Whether a pairing/PIN step is required. */
108
- requiresPairing: boolean;
80
+ export type NetworkType = "wifi" | "cellular" | "none" | "unknown";
81
+
82
+ export interface NetworkInfo {
83
+ /** Connection medium. */
84
+ type: NetworkType;
85
+ /** True when the device has an active internet connection. */
86
+ isConnected: boolean;
87
+ /** True when airplane mode is on (Android only; always false on iOS). */
88
+ isAirplaneMode: boolean;
89
+ /** Wi-Fi SSID — Android only, requires location permission; null on iOS. */
90
+ ssid: string | null;
91
+ /** Cellular generation e.g. "4g" | "5g" — Android only; null on iOS. */
92
+ cellularGeneration: string | null;
109
93
  }
110
94
 
111
- /** Full snapshot of in-app cast state. */
112
- export interface AppCastInfo {
113
- state: AppCastState;
114
- /** Devices found during the last scan. */
115
- devices: AppCastDevice[];
116
- /** The device currently connected (or connecting). */
117
- connectedDevice: AppCastDevice | null;
118
- /** Error message from the last failed operation. */
119
- error: string | null;
95
+ // ─────────────────────────────────────────────
96
+ // Battery
97
+ // ─────────────────────────────────────────────
98
+
99
+ export type BatteryState = "charging" | "discharging" | "full" | "unknown";
100
+
101
+ export interface BatteryInfo {
102
+ /** Battery level 0–100, or -1 if unknown. */
103
+ level: number;
104
+ state: BatteryState;
105
+ isCharging: boolean;
106
+ /** True when level ≤ 20 and not charging. */
107
+ isLow: boolean;
120
108
  }
121
109
 
122
- /** @deprecated Use SystemScreencastInfo */
123
- export interface ScreencastInfo extends SystemScreencastInfo {}
110
+ // ─────────────────────────────────────────────
111
+ // Haptics
112
+ // ─────────────────────────────────────────────
113
+
114
+ export type HapticPattern =
115
+ | "light"
116
+ | "medium"
117
+ | "heavy"
118
+ | "success"
119
+ | "warning"
120
+ | "error"
121
+ | "selection";
122
+
123
+ // ─────────────────────────────────────────────
124
+ // Font Scale
125
+ // ─────────────────────────────────────────────
126
+
127
+ export interface FontScaleInfo {
128
+ /**
129
+ * System font scale multiplier (1.0 = default).
130
+ * Android: from Configuration.fontScale.
131
+ * iOS: derived from UIContentSizeCategory.
132
+ */
133
+ fontScale: number;
134
+ /**
135
+ * Screen pixel density.
136
+ * Android: DisplayMetrics.density.
137
+ * iOS: UIScreen.main.scale.
138
+ */
139
+ density: number;
140
+ }
@@ -2,15 +2,17 @@
2
2
  // rn-system-bar · useSystemBar.ts
3
3
  // ─────────────────────────────────────────────
4
4
 
5
- import { useCallback, useEffect, useRef, useState } from "react";
5
+ import { useEffect, useState } from "react";
6
6
  import * as SystemBar from "./SystemBar";
7
7
  import type {
8
- AppCastInfo,
8
+ BatteryInfo,
9
+ FontScaleInfo,
9
10
  NavigationBarBehavior,
10
11
  NavigationBarButtonStyle,
11
12
  NavigationBarColorValue,
12
13
  NavigationBarStyle,
13
14
  NavigationBarVisibility,
15
+ NetworkInfo,
14
16
  Orientation,
15
17
  ScreencastInfo,
16
18
  StatusBarColorValue,
@@ -37,7 +39,6 @@ export interface SystemBarConfig {
37
39
  statusBarColor?: StatusBarColorValue;
38
40
  statusBarStyle?: StatusBarStyle;
39
41
  statusBarVisible?: boolean;
40
- statusBarAnimated?: boolean;
41
42
 
42
43
  // Screen
43
44
  keepScreenOn?: boolean;
@@ -61,75 +62,46 @@ export interface SystemBarConfig {
61
62
  // ─────────────────────────────────────────────
62
63
 
63
64
  export const useSystemBar = (config: SystemBarConfig): void => {
64
- const configRef = useRef("");
65
65
  const configStr = JSON.stringify(config);
66
66
 
67
67
  useEffect(() => {
68
- if (configRef.current === configStr) return;
69
- configRef.current = configStr;
70
-
71
- const apply = async () => {
72
- if (config.navigationBarColor !== undefined)
73
- SystemBar.setNavigationBarColor(config.navigationBarColor);
74
- if (config.navigationBarVisibility !== undefined)
75
- SystemBar.setNavigationBarVisibility(config.navigationBarVisibility);
76
- if (config.navigationBarButtonStyle !== undefined)
77
- SystemBar.setNavigationBarButtonStyle(config.navigationBarButtonStyle);
78
- if (config.navigationBarStyle !== undefined)
79
- SystemBar.setNavigationBarStyle(config.navigationBarStyle);
80
- if (config.navigationBarBehavior !== undefined)
81
- SystemBar.setNavigationBarBehavior(config.navigationBarBehavior);
82
- if (config.statusBarColor !== undefined)
83
- SystemBar.setStatusBarColor(config.statusBarColor);
84
- if (config.statusBarStyle !== undefined)
85
- SystemBar.setStatusBarStyle(config.statusBarStyle);
86
- if (config.statusBarVisible !== undefined)
87
- SystemBar.setStatusBarVisibility(config.statusBarVisible);
88
- if (config.keepScreenOn !== undefined)
89
- SystemBar.keepScreenOn(config.keepScreenOn);
90
- if (config.immersiveMode !== undefined)
91
- SystemBar.immersiveMode(config.immersiveMode);
92
- if (config.brightness !== undefined)
93
- SystemBar.setBrightness(config.brightness);
94
- if (config.orientation !== undefined)
95
- SystemBar.setOrientation(config.orientation);
96
- if (config.secureScreen !== undefined)
97
- SystemBar.setSecureScreen(config.secureScreen);
98
- };
99
-
100
- apply().catch(() => {
101
- if (__DEV__)
102
- console.warn(
103
- "[rn-system-bar] useSystemBar: one or more settings failed.",
104
- );
105
- });
68
+ if (config.navigationBarColor !== undefined)
69
+ SystemBar.setNavigationBarColor(config.navigationBarColor);
70
+ if (config.navigationBarVisibility !== undefined)
71
+ SystemBar.setNavigationBarVisibility(config.navigationBarVisibility);
72
+ if (config.navigationBarButtonStyle !== undefined)
73
+ SystemBar.setNavigationBarButtonStyle(config.navigationBarButtonStyle);
74
+ if (config.navigationBarStyle !== undefined)
75
+ SystemBar.setNavigationBarStyle(config.navigationBarStyle);
76
+ if (config.navigationBarBehavior !== undefined)
77
+ SystemBar.setNavigationBarBehavior(config.navigationBarBehavior);
78
+ if (config.statusBarColor !== undefined)
79
+ SystemBar.setStatusBarColor(config.statusBarColor);
80
+ if (config.statusBarStyle !== undefined)
81
+ SystemBar.setStatusBarStyle(config.statusBarStyle);
82
+ if (config.statusBarVisible !== undefined)
83
+ SystemBar.setStatusBarVisibility(config.statusBarVisible);
84
+ if (config.keepScreenOn !== undefined)
85
+ SystemBar.keepScreenOn(config.keepScreenOn);
86
+ if (config.immersiveMode !== undefined)
87
+ SystemBar.immersiveMode(config.immersiveMode);
88
+ if (config.brightness !== undefined)
89
+ SystemBar.setBrightness(config.brightness);
90
+ if (config.orientation !== undefined)
91
+ SystemBar.setOrientation(config.orientation);
92
+ if (config.secureScreen !== undefined)
93
+ SystemBar.setSecureScreen(config.secureScreen);
106
94
  // eslint-disable-next-line react-hooks/exhaustive-deps
107
95
  }, [configStr]);
108
96
  };
109
97
 
110
98
  // ─────────────────────────────────────────────
111
99
  // ThemedSystemBarConfig + useThemeSystemBar
112
- //
113
- // Combines useTheme() + useSystemBar() — nav/status bars
114
- // automatically update whenever the theme changes (OS or manual).
115
- //
116
- // @example
117
- // const { isDark, mode, setMode } = useThemeSystemBar({
118
- // dark: { navigationBarColor: "#000000", statusBarStyle: "light" },
119
- // light: { navigationBarColor: "#ffffff", statusBarStyle: "dark" },
120
- // base: { keepScreenOn: true },
121
- // });
122
100
  // ─────────────────────────────────────────────
123
101
 
124
102
  export interface ThemedSystemBarConfig {
125
- /** Config applied when the resolved theme is DARK. */
126
103
  dark?: SystemBarConfig;
127
- /** Config applied when the resolved theme is LIGHT. */
128
104
  light?: SystemBarConfig;
129
- /**
130
- * Static config merged under both themes.
131
- * Theme-specific (dark/light) values always win.
132
- */
133
105
  base?: SystemBarConfig;
134
106
  }
135
107
 
@@ -157,12 +129,6 @@ export type { ThemeMode, ThemeState };
157
129
 
158
130
  // ─────────────────────────────────────────────
159
131
  // useSystemScreencast
160
- // Tracks OS-level external display state.
161
- // Android: DisplayManager (HDMI / Miracast / Presentation display).
162
- // iOS: UIScreen.screens (AirPlay mirror).
163
- //
164
- // @example
165
- // const { isCasting, displayName, displays } = useSystemScreencast();
166
132
  // ─────────────────────────────────────────────
167
133
 
168
134
  export const useSystemScreencast = (): SystemScreencastInfo => {
@@ -183,9 +149,8 @@ export const useSystemScreencast = (): SystemScreencastInfo => {
183
149
  return info;
184
150
  };
185
151
 
186
- /** @deprecated Renamed to useSystemScreencast() */
187
- // useSystemBar.ts useScreencast
188
- export const useScreencast = () => {
152
+ /** @deprecated Use useSystemScreencast() */
153
+ export const useScreencast = (): ScreencastInfo => {
189
154
  const [info, setInfo] = useState<ScreencastInfo>({
190
155
  isCasting: false,
191
156
  displayName: null,
@@ -193,7 +158,6 @@ export const useScreencast = () => {
193
158
  });
194
159
 
195
160
  useEffect(() => {
196
- // Guard: if method doesn't exist on native module, bail silently
197
161
  SystemBar.getScreencastInfo()
198
162
  .then(setInfo)
199
163
  .catch(() => {
@@ -202,13 +166,10 @@ export const useScreencast = () => {
202
166
  "[rn-system-bar] getSystemScreencastInfo not available. Rebuild native.",
203
167
  );
204
168
  });
205
-
206
169
  let unsub: (() => void) | undefined;
207
170
  try {
208
171
  unsub = SystemBar.onScreencastChange(setInfo);
209
- } catch {
210
- // native listener not available
211
- }
172
+ } catch {}
212
173
  return () => unsub?.();
213
174
  }, []);
214
175
 
@@ -216,79 +177,89 @@ export const useScreencast = () => {
216
177
  };
217
178
 
218
179
  // ─────────────────────────────────────────────
219
- // UseAppCastReturn + useAppCast
220
- //
221
- // In-app device discovery + casting via Android MediaRouter.
222
- // Mirrors ONLY this app's screen — NOT the whole system.
223
- // iOS always returns idle (AirPlay is system-managed, no public API).
224
- //
225
- // Flow:
226
- // 1. Mount the component — calls getAppCastInfo() for initial state
227
- // 2. call scan() → state = "scanning", devices populate
228
- // 3. call connect(device.id) → state = "connecting" → "connected"
229
- // 4. call disconnect() → state = "disconnecting" → "idle"
230
- // 5. Unmount → scan auto-stopped (battery safe)
231
- //
232
- // @example
233
- // const { state, devices, connectedDevice, error,
234
- // scan, stopScan, connect, disconnect } = useAppCast();
235
- //
236
- // <Button title="Find TVs" onPress={scan} />
237
- // {devices.map(d => (
238
- // <Button key={d.id} title={`Cast to ${d.name}`}
239
- // onPress={() => connect(d.id)} />
240
- // ))}
241
- // {connectedDevice && (
242
- // <Button title="Stop casting" onPress={disconnect} />
243
- // )}
180
+ // useNetwork
244
181
  // ─────────────────────────────────────────────
245
182
 
246
- export interface UseAppCastReturn extends AppCastInfo {
247
- /** Start scanning for nearby castable devices (TV, Chromecast, etc.). */
248
- scan: () => void;
249
- /** Stop the device discovery scan. */
250
- stopScan: () => void;
251
- /**
252
- * Connect to a discovered device and begin casting this app's screen.
253
- * @param deviceId The `id` field from `AppCastDevice`.
254
- * @param pairingPin Optional PIN string if `requiresPairing` is true.
255
- */
256
- connect: (deviceId: string, pairingPin?: string) => void;
257
- /** End the active cast session and return to idle. */
258
- disconnect: () => void;
259
- }
260
-
261
- export const useAppCast = (): UseAppCastReturn => {
262
- const [info, setInfo] = useState<AppCastInfo>({
263
- state: "idle",
264
- devices: [],
265
- connectedDevice: null,
266
- error: null,
183
+ /**
184
+ * Subscribe to network state. Fires immediately with the current snapshot,
185
+ * then on every connectivity change.
186
+ *
187
+ * @example
188
+ * const { isConnected, type } = useNetwork();
189
+ */
190
+ export const useNetwork = (): NetworkInfo => {
191
+ const [info, setInfo] = useState<NetworkInfo>({
192
+ type: "unknown",
193
+ isConnected: false,
194
+ isAirplaneMode: false,
195
+ ssid: null,
196
+ cellularGeneration: null,
267
197
  });
268
198
 
269
199
  useEffect(() => {
270
- // Sync initial state
271
- SystemBar.getAppCastInfo()
200
+ SystemBar.getNetworkInfo()
272
201
  .then(setInfo)
273
202
  .catch(() => {});
203
+ const unsub = SystemBar.onNetworkChange(setInfo);
204
+ return () => unsub();
205
+ }, []);
274
206
 
275
- // Subscribe to all cast events (device found/lost, state changes, errors)
276
- const unsub = SystemBar.onAppCastChange(setInfo);
207
+ return info;
208
+ };
209
+
210
+ // ─────────────────────────────────────────────
211
+ // useBattery
212
+ // ─────────────────────────────────────────────
277
213
 
278
- return () => {
279
- unsub();
280
- // Auto-stop scan on unmount avoids background battery drain
281
- SystemBar.stopAppCastScan();
282
- };
214
+ /**
215
+ * Subscribe to battery state. Fires immediately with the current snapshot,
216
+ * then on every level / state change.
217
+ *
218
+ * @example
219
+ * const { level, isCharging, isLow } = useBattery();
220
+ */
221
+ export const useBattery = (): BatteryInfo => {
222
+ const [info, setInfo] = useState<BatteryInfo>({
223
+ level: -1,
224
+ state: "unknown",
225
+ isCharging: false,
226
+ isLow: false,
227
+ });
228
+
229
+ useEffect(() => {
230
+ SystemBar.getBatteryInfo()
231
+ .then(setInfo)
232
+ .catch(() => {});
233
+ const unsub = SystemBar.onBatteryChange(setInfo);
234
+ return () => unsub();
283
235
  }, []);
284
236
 
285
- const scan = useCallback(() => SystemBar.startAppCastScan(), []);
286
- const stopScan = useCallback(() => SystemBar.stopAppCastScan(), []);
287
- const connect = useCallback(
288
- (id: string, pin?: string) => SystemBar.connectAppCast(id, pin),
289
- [],
290
- );
291
- const disconnect = useCallback(() => SystemBar.disconnectAppCast(), []);
237
+ return info;
238
+ };
239
+
240
+ // ─────────────────────────────────────────────
241
+ // useFontScale
242
+ // ─────────────────────────────────────────────
243
+
244
+ /**
245
+ * Subscribe to system font scale changes (accessibility text size).
246
+ *
247
+ * @example
248
+ * const { fontScale, density } = useFontScale();
249
+ */
250
+ export const useFontScale = (): FontScaleInfo => {
251
+ const [info, setInfo] = useState<FontScaleInfo>({
252
+ fontScale: 1,
253
+ density: 1,
254
+ });
255
+
256
+ useEffect(() => {
257
+ SystemBar.getFontScaleInfo()
258
+ .then(setInfo)
259
+ .catch(() => {});
260
+ const unsub = SystemBar.onFontScaleChange(setInfo);
261
+ return () => unsub();
262
+ }, []);
292
263
 
293
- return { ...info, scan, stopScan, connect, disconnect };
264
+ return info;
294
265
  };