@shoutem/ui 9.0.5 → 9.0.7

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.
@@ -4,22 +4,37 @@ import { initialWindowMetrics } from 'react-native-safe-area-context';
4
4
 
5
5
  export const NAVIGATION_HEADER_HEIGHT = 64;
6
6
 
7
+ // Fallback inset values used when initialWindowMetrics is null (race condition
8
+ // in large apps where JS evaluates before the safe-area native module inits).
9
+ // Bottom: 34pt — consistent across all notched iPhones since iPhone X (2017).
10
+ // Top: 59pt — matches Dynamic Island devices (iPhone 14+).
11
+ // Slightly too large for older notched devices (44–48pt), but using the
12
+ // largest one prevents content from being hidden under the notch/Dynamic Island.
13
+ const DEFAULT_IOS_TOP_INSET = 59;
14
+ const DEFAULT_IOS_BOTTOM_INSET = 34;
15
+
7
16
  export const isNotchedAndroid =
8
17
  Platform.OS === 'android' && DeviceInfo.hasNotch();
9
18
 
10
19
  export const NAVIGATION_BAR_HEIGHT = Platform.select({
11
- ios: NAVIGATION_HEADER_HEIGHT + initialWindowMetrics?.insets?.top,
20
+ ios:
21
+ NAVIGATION_HEADER_HEIGHT +
22
+ (initialWindowMetrics?.insets?.top ?? DEFAULT_IOS_TOP_INSET),
12
23
  android: isNotchedAndroid
13
24
  ? NAVIGATION_HEADER_HEIGHT + StatusBar.currentHeight
14
25
  : NAVIGATION_HEADER_HEIGHT,
15
26
  default: NAVIGATION_HEADER_HEIGHT,
16
27
  });
17
28
 
29
+ // Bottom inset from the native safe-area module (home indicator on iOS,
30
+ // system nav bar on Android with edge-to-edge). Falls back to 34pt on iOS
31
+ // (race condition guard) or 0 on Android (no inset when edge-to-edge is off).
18
32
  export const HOME_INDICATOR_PADDING =
19
- Platform.OS === 'ios' ? initialWindowMetrics?.insets?.bottom : 0;
33
+ initialWindowMetrics?.insets?.bottom ??
34
+ (Platform.OS === 'ios' ? DEFAULT_IOS_BOTTOM_INSET : 0);
20
35
 
21
36
  export const NOTCH_AREA_HEIGHT = Platform.select({
22
- ios: initialWindowMetrics?.insets?.top,
37
+ ios: initialWindowMetrics?.insets?.top ?? DEFAULT_IOS_TOP_INSET,
23
38
  android: isNotchedAndroid ? StatusBar.currentHeight : 0,
24
39
  default: 0,
25
40
  });
@@ -30,3 +45,56 @@ export const Device = {
30
45
  NOTCH_AREA_HEIGHT,
31
46
  NAVIGATION_HEADER_HEIGHT,
32
47
  };
48
+
49
+ // Lazy getters — resolve initialWindowMetrics on first render,
50
+ // when the native module is guaranteed to be ready.
51
+ let _topInset;
52
+ let _bottomInset;
53
+
54
+ const getTopInset = () => {
55
+ if (_topInset === undefined) {
56
+ // eslint-disable-next-line global-require
57
+ const metrics = require('react-native-safe-area-context')
58
+ .initialWindowMetrics;
59
+ _topInset = metrics?.insets?.top ?? DEFAULT_IOS_TOP_INSET;
60
+ }
61
+
62
+ return _topInset;
63
+ };
64
+
65
+ const getBottomInset = () => {
66
+ if (_bottomInset === undefined) {
67
+ // eslint-disable-next-line global-require
68
+ const metrics = require('react-native-safe-area-context')
69
+ .initialWindowMetrics;
70
+
71
+ // Use actual bottom inset if available. Fallback: 34pt on iOS (safe
72
+ // default for all notched iPhones), 0 on Android (no inset pre-RN 0.77).
73
+ _bottomInset =
74
+ metrics?.insets?.bottom ??
75
+ (Platform.OS === 'ios' ? DEFAULT_IOS_BOTTOM_INSET : 0);
76
+ }
77
+
78
+ return _bottomInset;
79
+ };
80
+
81
+ export const getNavigationBarHeight = () =>
82
+ Platform.select({
83
+ ios: NAVIGATION_HEADER_HEIGHT + getTopInset(),
84
+ android: isNotchedAndroid
85
+ ? NAVIGATION_HEADER_HEIGHT + StatusBar.currentHeight
86
+ : NAVIGATION_HEADER_HEIGHT,
87
+ default: NAVIGATION_HEADER_HEIGHT,
88
+ });
89
+
90
+ // Returns bottom safe area inset on both platforms. On iOS this is the home
91
+ // indicator area (34pt). On Android this is the system navigation bar height
92
+ // when edge-to-edge is enabled (RN 0.76+), or 0 on older RN versions.
93
+ export const getHomeIndicatorPadding = () => getBottomInset();
94
+
95
+ export const getNotchAreaHeight = () =>
96
+ Platform.select({
97
+ ios: getTopInset(),
98
+ android: isNotchedAndroid ? StatusBar.currentHeight : 0,
99
+ default: 0,
100
+ });
package/helpers/index.js CHANGED
@@ -1,5 +1,8 @@
1
1
  export {
2
2
  Device,
3
+ getHomeIndicatorPadding,
4
+ getNavigationBarHeight,
5
+ getNotchAreaHeight,
3
6
  HOME_INDICATOR_PADDING,
4
7
  isNotchedAndroid,
5
8
  NAVIGATION_BAR_HEIGHT,
package/index.js CHANGED
@@ -78,7 +78,14 @@ export { YearRangePicker } from './components/YearRangePicker';
78
78
  export * from './hooks';
79
79
 
80
80
  // Helpers
81
- export { calculateKeyboardOffset, Device, Keyboard } from './helpers';
81
+ export {
82
+ calculateKeyboardOffset,
83
+ Device,
84
+ getHomeIndicatorPadding,
85
+ getNavigationBarHeight,
86
+ getNotchAreaHeight,
87
+ Keyboard,
88
+ } from './helpers';
82
89
 
83
90
  // HTML
84
91
  export { Html } from './html';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shoutem/ui",
3
- "version": "9.0.5",
3
+ "version": "9.0.7",
4
4
  "description": "Styleable set of components for React Native applications",
5
5
  "scripts": {
6
6
  "lint": "eslint .",
@@ -1,8 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(npm whoami:*)",
5
- "Bash(npm config:*)"
6
- ]
7
- }
8
- }