@amazon-devices/react-native-safe-area-context 2.0.1758683737

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 (156) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +315 -0
  3. package/SystemBundles/e3c0cdeab56b8b622d4f0fd5a80812eafe199fa2287d0e3a09c5e573a1035350.bundle +11031 -0
  4. package/SystemBundles/e3c0cdeab56b8b622d4f0fd5a80812eafe199fa2287d0e3a09c5e573a1035350.map +1 -0
  5. package/SystemModules/amzn__react-native-safe-area-context-2.modules.txt +55 -0
  6. package/SystemModules/amzn__react-native-safe-area-context-2.private.modules.txt +91 -0
  7. package/SystemModules/keplerscript-system-bundle-config.json +7 -0
  8. package/THIRD_PARTY_NOTICES.txt +24 -0
  9. package/android/build.gradle +46 -0
  10. package/android/src/main/AndroidManifest.xml +6 -0
  11. package/android/src/main/java/com/th3rdwave/safeareacontext/EdgeInsets.java +22 -0
  12. package/android/src/main/java/com/th3rdwave/safeareacontext/InsetsChangeEvent.java +33 -0
  13. package/android/src/main/java/com/th3rdwave/safeareacontext/Rect.java +22 -0
  14. package/android/src/main/java/com/th3rdwave/safeareacontext/SafeAreaContextPackage.java +31 -0
  15. package/android/src/main/java/com/th3rdwave/safeareacontext/SafeAreaProvider.java +66 -0
  16. package/android/src/main/java/com/th3rdwave/safeareacontext/SafeAreaProviderManager.java +94 -0
  17. package/android/src/main/java/com/th3rdwave/safeareacontext/SafeAreaUtils.java +82 -0
  18. package/android/src/main/java/com/th3rdwave/safeareacontext/SafeAreaView.java +159 -0
  19. package/android/src/main/java/com/th3rdwave/safeareacontext/SafeAreaViewEdges.java +8 -0
  20. package/android/src/main/java/com/th3rdwave/safeareacontext/SafeAreaViewLocalData.java +27 -0
  21. package/android/src/main/java/com/th3rdwave/safeareacontext/SafeAreaViewManager.java +72 -0
  22. package/android/src/main/java/com/th3rdwave/safeareacontext/SafeAreaViewMode.java +6 -0
  23. package/android/src/main/java/com/th3rdwave/safeareacontext/SafeAreaViewShadowNode.java +201 -0
  24. package/android/src/main/java/com/th3rdwave/safeareacontext/SerializationUtils.java +52 -0
  25. package/ios/SafeAreaView/RCTView+SafeAreaCompat.h +16 -0
  26. package/ios/SafeAreaView/RCTView+SafeAreaCompat.m +57 -0
  27. package/ios/SafeAreaView/RNCSafeAreaProvider.h +13 -0
  28. package/ios/SafeAreaView/RNCSafeAreaProvider.m +65 -0
  29. package/ios/SafeAreaView/RNCSafeAreaProviderManager.h +9 -0
  30. package/ios/SafeAreaView/RNCSafeAreaProviderManager.m +61 -0
  31. package/ios/SafeAreaView/RNCSafeAreaShadowView.h +9 -0
  32. package/ios/SafeAreaView/RNCSafeAreaShadowView.m +180 -0
  33. package/ios/SafeAreaView/RNCSafeAreaView.h +21 -0
  34. package/ios/SafeAreaView/RNCSafeAreaView.m +118 -0
  35. package/ios/SafeAreaView/RNCSafeAreaViewEdges.h +9 -0
  36. package/ios/SafeAreaView/RNCSafeAreaViewEdges.m +13 -0
  37. package/ios/SafeAreaView/RNCSafeAreaViewLocalData.h +18 -0
  38. package/ios/SafeAreaView/RNCSafeAreaViewLocalData.m +16 -0
  39. package/ios/SafeAreaView/RNCSafeAreaViewManager.h +9 -0
  40. package/ios/SafeAreaView/RNCSafeAreaViewManager.m +25 -0
  41. package/ios/SafeAreaView/RNCSafeAreaViewMode.h +7 -0
  42. package/ios/SafeAreaView/RNCSafeAreaViewMode.m +11 -0
  43. package/ios/SafeAreaView.xcodeproj/project.pbxproj +338 -0
  44. package/kepler-compatibility.json +8 -0
  45. package/kepler-transformed-package-info.json +3 -0
  46. package/lib/commonjs/CompatNativeSafeAreaProvider.js +44 -0
  47. package/lib/commonjs/CompatNativeSafeAreaProvider.js.map +1 -0
  48. package/lib/commonjs/InitialWindow.js +13 -0
  49. package/lib/commonjs/InitialWindow.js.map +1 -0
  50. package/lib/commonjs/InitialWindow.kepler.js +15 -0
  51. package/lib/commonjs/InitialWindow.kepler.js.map +1 -0
  52. package/lib/commonjs/InitialWindow.native.js +15 -0
  53. package/lib/commonjs/InitialWindow.native.js.map +1 -0
  54. package/lib/commonjs/NativeSafeAreaProvider.js +132 -0
  55. package/lib/commonjs/NativeSafeAreaProvider.js.map +1 -0
  56. package/lib/commonjs/NativeSafeAreaProvider.kepler.js +9 -0
  57. package/lib/commonjs/NativeSafeAreaProvider.kepler.js.map +1 -0
  58. package/lib/commonjs/NativeSafeAreaProvider.macos.js +9 -0
  59. package/lib/commonjs/NativeSafeAreaProvider.macos.js.map +1 -0
  60. package/lib/commonjs/NativeSafeAreaProvider.native.js +9 -0
  61. package/lib/commonjs/NativeSafeAreaProvider.native.js.map +1 -0
  62. package/lib/commonjs/NativeSafeAreaProvider.windows.js +9 -0
  63. package/lib/commonjs/NativeSafeAreaProvider.windows.js.map +1 -0
  64. package/lib/commonjs/SafeArea.types.js +6 -0
  65. package/lib/commonjs/SafeArea.types.js.map +1 -0
  66. package/lib/commonjs/SafeAreaContext.js +113 -0
  67. package/lib/commonjs/SafeAreaContext.js.map +1 -0
  68. package/lib/commonjs/SafeAreaView.js +82 -0
  69. package/lib/commonjs/SafeAreaView.js.map +1 -0
  70. package/lib/commonjs/SafeAreaView.kepler.js +9 -0
  71. package/lib/commonjs/SafeAreaView.kepler.js.map +1 -0
  72. package/lib/commonjs/SafeAreaView.macos.js +9 -0
  73. package/lib/commonjs/SafeAreaView.macos.js.map +1 -0
  74. package/lib/commonjs/SafeAreaView.native.js +9 -0
  75. package/lib/commonjs/SafeAreaView.native.js.map +1 -0
  76. package/lib/commonjs/SafeAreaView.windows.js +9 -0
  77. package/lib/commonjs/SafeAreaView.windows.js.map +1 -0
  78. package/lib/commonjs/index.js +50 -0
  79. package/lib/commonjs/index.js.map +1 -0
  80. package/lib/commonjs/useWindowDimensions.js +32 -0
  81. package/lib/commonjs/useWindowDimensions.js.map +1 -0
  82. package/lib/module/CompatNativeSafeAreaProvider.js +35 -0
  83. package/lib/module/CompatNativeSafeAreaProvider.js.map +1 -0
  84. package/lib/module/InitialWindow.js +7 -0
  85. package/lib/module/InitialWindow.js.map +1 -0
  86. package/lib/module/InitialWindow.kepler.js +9 -0
  87. package/lib/module/InitialWindow.kepler.js.map +1 -0
  88. package/lib/module/InitialWindow.native.js +9 -0
  89. package/lib/module/InitialWindow.native.js.map +1 -0
  90. package/lib/module/NativeSafeAreaProvider.js +124 -0
  91. package/lib/module/NativeSafeAreaProvider.js.map +1 -0
  92. package/lib/module/NativeSafeAreaProvider.kepler.js +3 -0
  93. package/lib/module/NativeSafeAreaProvider.kepler.js.map +1 -0
  94. package/lib/module/NativeSafeAreaProvider.macos.js +3 -0
  95. package/lib/module/NativeSafeAreaProvider.macos.js.map +1 -0
  96. package/lib/module/NativeSafeAreaProvider.native.js +3 -0
  97. package/lib/module/NativeSafeAreaProvider.native.js.map +1 -0
  98. package/lib/module/NativeSafeAreaProvider.windows.js +3 -0
  99. package/lib/module/NativeSafeAreaProvider.windows.js.map +1 -0
  100. package/lib/module/SafeArea.types.js +2 -0
  101. package/lib/module/SafeArea.types.js.map +1 -0
  102. package/lib/module/SafeAreaContext.js +99 -0
  103. package/lib/module/SafeAreaContext.js.map +1 -0
  104. package/lib/module/SafeAreaView.js +74 -0
  105. package/lib/module/SafeAreaView.js.map +1 -0
  106. package/lib/module/SafeAreaView.kepler.js +3 -0
  107. package/lib/module/SafeAreaView.kepler.js.map +1 -0
  108. package/lib/module/SafeAreaView.macos.js +3 -0
  109. package/lib/module/SafeAreaView.macos.js.map +1 -0
  110. package/lib/module/SafeAreaView.native.js +3 -0
  111. package/lib/module/SafeAreaView.native.js.map +1 -0
  112. package/lib/module/SafeAreaView.windows.js +3 -0
  113. package/lib/module/SafeAreaView.windows.js.map +1 -0
  114. package/lib/module/index.js +5 -0
  115. package/lib/module/index.js.map +1 -0
  116. package/lib/module/useWindowDimensions.js +26 -0
  117. package/lib/module/useWindowDimensions.js.map +1 -0
  118. package/lib/typescript/src/CompatNativeSafeAreaProvider.d.ts +2 -0
  119. package/lib/typescript/src/InitialWindow.d.ts +6 -0
  120. package/lib/typescript/src/InitialWindow.kepler.d.ts +6 -0
  121. package/lib/typescript/src/InitialWindow.native.d.ts +6 -0
  122. package/lib/typescript/src/NativeSafeAreaProvider.d.ts +2 -0
  123. package/lib/typescript/src/NativeSafeAreaProvider.kepler.d.ts +2 -0
  124. package/lib/typescript/src/NativeSafeAreaProvider.macos.d.ts +2 -0
  125. package/lib/typescript/src/NativeSafeAreaProvider.native.d.ts +3 -0
  126. package/lib/typescript/src/NativeSafeAreaProvider.windows.d.ts +2 -0
  127. package/lib/typescript/src/SafeArea.types.d.ts +31 -0
  128. package/lib/typescript/src/SafeAreaContext.d.ts +30 -0
  129. package/lib/typescript/src/SafeAreaView.d.ts +2 -0
  130. package/lib/typescript/src/SafeAreaView.kepler.d.ts +2 -0
  131. package/lib/typescript/src/SafeAreaView.macos.d.ts +2 -0
  132. package/lib/typescript/src/SafeAreaView.native.d.ts +2 -0
  133. package/lib/typescript/src/SafeAreaView.windows.d.ts +2 -0
  134. package/lib/typescript/src/index.d.ts +4 -0
  135. package/lib/typescript/src/useWindowDimensions.d.ts +8 -0
  136. package/package.json +1 -0
  137. package/react-native-safe-area-context.podspec +19 -0
  138. package/react-native.config.js +8 -0
  139. package/src/CompatNativeSafeAreaProvider.tsx +29 -0
  140. package/src/InitialWindow.kepler.ts +10 -0
  141. package/src/InitialWindow.native.ts +16 -0
  142. package/src/InitialWindow.ts +8 -0
  143. package/src/NativeSafeAreaProvider.kepler.tsx +3 -0
  144. package/src/NativeSafeAreaProvider.macos.tsx +3 -0
  145. package/src/NativeSafeAreaProvider.native.tsx +6 -0
  146. package/src/NativeSafeAreaProvider.tsx +129 -0
  147. package/src/NativeSafeAreaProvider.windows.tsx +3 -0
  148. package/src/SafeArea.types.ts +43 -0
  149. package/src/SafeAreaContext.tsx +148 -0
  150. package/src/SafeAreaView.kepler.tsx +3 -0
  151. package/src/SafeAreaView.macos.tsx +3 -0
  152. package/src/SafeAreaView.native.tsx +6 -0
  153. package/src/SafeAreaView.tsx +85 -0
  154. package/src/SafeAreaView.windows.tsx +3 -0
  155. package/src/index.tsx +4 -0
  156. package/src/useWindowDimensions.tsx +35 -0
@@ -0,0 +1,159 @@
1
+ package com.th3rdwave.safeareacontext;
2
+
3
+ import android.annotation.SuppressLint;
4
+ import android.content.Context;
5
+ import android.content.ContextWrapper;
6
+ import android.util.Log;
7
+ import android.view.View;
8
+ import android.view.ViewParent;
9
+ import android.view.ViewTreeObserver;
10
+
11
+ import com.facebook.react.bridge.ReactContext;
12
+ import com.facebook.react.uimanager.UIManagerModule;
13
+ import com.facebook.react.views.view.ReactViewGroup;
14
+
15
+ import java.util.EnumSet;
16
+ import java.util.concurrent.atomic.AtomicBoolean;
17
+
18
+ import androidx.annotation.Nullable;
19
+
20
+ @SuppressLint("ViewConstructor")
21
+ public class SafeAreaView extends ReactViewGroup implements ViewTreeObserver.OnPreDrawListener {
22
+ private SafeAreaViewMode mMode = SafeAreaViewMode.PADDING;
23
+ private @Nullable EdgeInsets mInsets;
24
+ private @Nullable EnumSet<SafeAreaViewEdges> mEdges;
25
+ private @Nullable View mProviderView;
26
+
27
+ public SafeAreaView(Context context) {
28
+ super(context);
29
+ }
30
+
31
+ /**
32
+ * UIManagerHelper.getReactContext only exists in RN 0.63+ so vendor it here for a while.
33
+ */
34
+ private static ReactContext getReactContext(View view) {
35
+ Context context = view.getContext();
36
+ if (!(context instanceof ReactContext) && context instanceof ContextWrapper) {
37
+ context = ((ContextWrapper) context).getBaseContext();
38
+ }
39
+ return (ReactContext) context;
40
+ }
41
+
42
+ private void updateInsets() {
43
+ if (mInsets != null) {
44
+ EnumSet<SafeAreaViewEdges> edges = mEdges != null
45
+ ? mEdges
46
+ : EnumSet.allOf(SafeAreaViewEdges.class);
47
+
48
+ SafeAreaViewLocalData localData = new SafeAreaViewLocalData(mInsets, mMode, edges);
49
+
50
+ ReactContext reactContext = getReactContext(this);
51
+ UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class);
52
+ if (uiManager != null) {
53
+ uiManager.setViewLocalData(getId(), localData);
54
+ waitForReactLayout();
55
+ }
56
+ }
57
+ }
58
+
59
+ private static final long MAX_WAIT_TIME_NANO = 500000000L; // 500ms
60
+
61
+ private void waitForReactLayout() {
62
+ // Block the main thread until the native module thread is finished with
63
+ // its current tasks. To do this we use the done boolean as a lock and enqueue
64
+ // a task on the native modules thread. When the task runs we can unblock the
65
+ // main thread. This should be safe as long as the native modules thread
66
+ // does not block waiting on the main thread.
67
+ final AtomicBoolean done = new AtomicBoolean(false);
68
+ final long startTime = System.nanoTime();
69
+ long waitTime = 0L;
70
+ getReactContext(this).runOnNativeModulesQueueThread(new Runnable() {
71
+ @Override
72
+ public void run() {
73
+ synchronized (done) {
74
+ if (done.compareAndSet(false, true)) {
75
+ done.notify();
76
+ }
77
+ }
78
+ }
79
+ });
80
+ synchronized (done) {
81
+ while (!done.get() && waitTime < MAX_WAIT_TIME_NANO) {
82
+ try {
83
+ done.wait(MAX_WAIT_TIME_NANO / 1000000L);
84
+ } catch (InterruptedException e) {
85
+ // In case of an interrupt just give up waiting.
86
+ done.set(true);
87
+ }
88
+ waitTime += System.nanoTime() - startTime;
89
+ }
90
+ // Timed out waiting.
91
+ if (waitTime >= MAX_WAIT_TIME_NANO) {
92
+ Log.w("SafeAreaView", "Timed out waiting for layout.");
93
+ }
94
+ }
95
+ }
96
+
97
+ public void setMode(SafeAreaViewMode mode) {
98
+ mMode = mode;
99
+ updateInsets();
100
+ }
101
+
102
+ public void setEdges(EnumSet<SafeAreaViewEdges> edges) {
103
+ mEdges = edges;
104
+ updateInsets();
105
+ }
106
+
107
+ private boolean maybeUpdateInsets() {
108
+ if (mProviderView == null) {
109
+ return false;
110
+ }
111
+ EdgeInsets edgeInsets = SafeAreaUtils.getSafeAreaInsets(mProviderView);
112
+ if (edgeInsets != null && (mInsets == null || !mInsets.equalsToEdgeInsets(edgeInsets))) {
113
+ mInsets = edgeInsets;
114
+ updateInsets();
115
+ return true;
116
+ }
117
+ return false;
118
+ }
119
+
120
+ private View findProvider() {
121
+ ViewParent current = getParent();
122
+ while (current != null) {
123
+ if (current instanceof SafeAreaProvider) {
124
+ return (View) current;
125
+ }
126
+ current = current.getParent();
127
+ }
128
+ return this;
129
+ }
130
+
131
+ @Override
132
+ protected void onAttachedToWindow() {
133
+ super.onAttachedToWindow();
134
+
135
+ mProviderView = findProvider();
136
+
137
+ mProviderView.getViewTreeObserver().addOnPreDrawListener(this);
138
+ maybeUpdateInsets();
139
+ }
140
+
141
+ @Override
142
+ protected void onDetachedFromWindow() {
143
+ super.onDetachedFromWindow();
144
+
145
+ if (mProviderView != null) {
146
+ mProviderView.getViewTreeObserver().removeOnPreDrawListener(this);
147
+ }
148
+ mProviderView = null;
149
+ }
150
+
151
+ @Override
152
+ public boolean onPreDraw() {
153
+ boolean didUpdate = maybeUpdateInsets();
154
+ if (didUpdate) {
155
+ requestLayout();
156
+ }
157
+ return !didUpdate;
158
+ }
159
+ }
@@ -0,0 +1,8 @@
1
+ package com.th3rdwave.safeareacontext;
2
+
3
+ public enum SafeAreaViewEdges {
4
+ TOP,
5
+ RIGHT,
6
+ BOTTOM,
7
+ LEFT
8
+ }
@@ -0,0 +1,27 @@
1
+ package com.th3rdwave.safeareacontext;
2
+
3
+ import java.util.EnumSet;
4
+
5
+ public class SafeAreaViewLocalData {
6
+ private EdgeInsets mInsets;
7
+ private SafeAreaViewMode mMode;
8
+ private EnumSet<SafeAreaViewEdges> mEdges;
9
+
10
+ public SafeAreaViewLocalData(EdgeInsets insets, SafeAreaViewMode mode, EnumSet<SafeAreaViewEdges> edges) {
11
+ mInsets = insets;
12
+ mMode = mode;
13
+ mEdges = edges;
14
+ }
15
+
16
+ public EdgeInsets getInsets() {
17
+ return mInsets;
18
+ }
19
+
20
+ public SafeAreaViewMode getMode() {
21
+ return mMode;
22
+ }
23
+
24
+ public EnumSet<SafeAreaViewEdges> getEdges() {
25
+ return mEdges;
26
+ }
27
+ }
@@ -0,0 +1,72 @@
1
+ package com.th3rdwave.safeareacontext;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import androidx.annotation.Nullable;
5
+
6
+ import com.facebook.react.bridge.ReadableArray;
7
+ import com.facebook.react.uimanager.LayoutShadowNode;
8
+ import com.facebook.react.uimanager.ThemedReactContext;
9
+ import com.facebook.react.uimanager.annotations.ReactProp;
10
+ import com.facebook.react.views.view.ReactViewManager;
11
+
12
+ import java.util.EnumSet;
13
+
14
+ public class SafeAreaViewManager extends ReactViewManager {
15
+ public SafeAreaViewManager() {
16
+ super();
17
+ }
18
+
19
+ @Override
20
+ @NonNull
21
+ public String getName() {
22
+ return "RNCSafeAreaView";
23
+ }
24
+
25
+ @Override
26
+ @NonNull
27
+ public SafeAreaView createViewInstance(@NonNull ThemedReactContext context) {
28
+ return new SafeAreaView(context);
29
+ }
30
+
31
+ @Override
32
+ @NonNull
33
+ public SafeAreaViewShadowNode createShadowNodeInstance() {
34
+ return new SafeAreaViewShadowNode();
35
+ }
36
+
37
+ @Override
38
+ public Class<? extends LayoutShadowNode> getShadowNodeClass() {
39
+ return SafeAreaViewShadowNode.class;
40
+ }
41
+
42
+ @ReactProp(name = "mode")
43
+ public void setMode(SafeAreaView view, @Nullable String mode) {
44
+ if ("padding".equals(mode)) {
45
+ view.setMode(SafeAreaViewMode.PADDING);
46
+ } else if ("margin".equals(mode)) {
47
+ view.setMode(SafeAreaViewMode.MARGIN);
48
+ }
49
+ }
50
+
51
+ @ReactProp(name = "edges")
52
+ public void setEdges(SafeAreaView view, @Nullable ReadableArray propList) {
53
+ EnumSet<SafeAreaViewEdges> edges = EnumSet.noneOf(SafeAreaViewEdges.class);
54
+
55
+ if (propList != null) {
56
+ for (int i = 0; i < propList.size(); i += 1) {
57
+ String edgeName = propList.getString(i);
58
+ if ("top".equals(edgeName)) {
59
+ edges.add(SafeAreaViewEdges.TOP);
60
+ } else if ("right".equals(edgeName)) {
61
+ edges.add(SafeAreaViewEdges.RIGHT);
62
+ } else if ("bottom".equals(edgeName)) {
63
+ edges.add(SafeAreaViewEdges.BOTTOM);
64
+ } else if ("left".equals(edgeName)) {
65
+ edges.add(SafeAreaViewEdges.LEFT);
66
+ }
67
+ }
68
+ }
69
+
70
+ view.setEdges(edges);
71
+ }
72
+ }
@@ -0,0 +1,6 @@
1
+ package com.th3rdwave.safeareacontext;
2
+
3
+ public enum SafeAreaViewMode {
4
+ PADDING,
5
+ MARGIN
6
+ }
@@ -0,0 +1,201 @@
1
+ package com.th3rdwave.safeareacontext;
2
+
3
+ import com.facebook.react.bridge.Dynamic;
4
+ import com.facebook.react.bridge.ReadableType;
5
+ import com.facebook.react.uimanager.LayoutShadowNode;
6
+ import com.facebook.react.uimanager.NativeViewHierarchyOptimizer;
7
+ import com.facebook.react.uimanager.PixelUtil;
8
+ import com.facebook.react.uimanager.Spacing;
9
+ import com.facebook.react.uimanager.ViewProps;
10
+ import com.facebook.react.uimanager.annotations.ReactPropGroup;
11
+
12
+ import java.util.EnumSet;
13
+
14
+ import androidx.annotation.Nullable;
15
+
16
+ public class SafeAreaViewShadowNode extends LayoutShadowNode {
17
+ private @Nullable SafeAreaViewLocalData mLocalData;
18
+
19
+ private float[] mPaddings;
20
+ private float[] mMargins;
21
+ private boolean mNeedsUpdate = false;
22
+
23
+ public SafeAreaViewShadowNode() {
24
+ super();
25
+
26
+ mPaddings = new float[ViewProps.PADDING_MARGIN_SPACING_TYPES.length];
27
+ mMargins = new float[ViewProps.PADDING_MARGIN_SPACING_TYPES.length];
28
+
29
+ for (int i = 0; i < ViewProps.PADDING_MARGIN_SPACING_TYPES.length; i += 1) {
30
+ mPaddings[i] = Float.NaN;
31
+ mMargins[i] = Float.NaN;
32
+ }
33
+ }
34
+
35
+ private void updateInsets() {
36
+ if (mLocalData == null) {
37
+ return;
38
+ }
39
+
40
+ float top = 0;
41
+ float right = 0;
42
+ float bottom = 0;
43
+ float left = 0;
44
+
45
+ float[] meta = mLocalData.getMode() == SafeAreaViewMode.PADDING ? mPaddings : mMargins;
46
+
47
+ float allEdges = meta[Spacing.ALL];
48
+ if (!Float.isNaN(allEdges)) {
49
+ top = allEdges;
50
+ right = allEdges;
51
+ bottom = allEdges;
52
+ left = allEdges;
53
+ }
54
+
55
+ float verticalEdges = meta[Spacing.VERTICAL];
56
+ if (!Float.isNaN(verticalEdges)) {
57
+ top = verticalEdges;
58
+ bottom = verticalEdges;
59
+ }
60
+
61
+ float horizontalEdges = meta[Spacing.HORIZONTAL];
62
+ if (!Float.isNaN(horizontalEdges)) {
63
+ right = horizontalEdges;
64
+ left = horizontalEdges;
65
+ }
66
+
67
+ float topEdge = meta[Spacing.TOP];
68
+ if (!Float.isNaN(topEdge)) {
69
+ top = topEdge;
70
+ }
71
+
72
+ float rightEdge = meta[Spacing.RIGHT];
73
+ if (!Float.isNaN(rightEdge)) {
74
+ right = rightEdge;
75
+ }
76
+
77
+ float bottomEdge = meta[Spacing.BOTTOM];
78
+ if (!Float.isNaN(bottomEdge)) {
79
+ bottom = bottomEdge;
80
+ }
81
+
82
+ float leftEdge = meta[Spacing.LEFT];
83
+ if (!Float.isNaN(leftEdge)) {
84
+ left = leftEdge;
85
+ }
86
+
87
+ top = PixelUtil.toPixelFromDIP(top);
88
+ right = PixelUtil.toPixelFromDIP(right);
89
+ bottom = PixelUtil.toPixelFromDIP(bottom);
90
+ left = PixelUtil.toPixelFromDIP(left);
91
+
92
+ EnumSet<SafeAreaViewEdges> edges = mLocalData.getEdges();
93
+ EdgeInsets insets = mLocalData.getInsets();
94
+ float insetTop = edges.contains(SafeAreaViewEdges.TOP) ? insets.top : 0;
95
+ float insetRight = edges.contains(SafeAreaViewEdges.RIGHT) ? insets.right : 0;
96
+ float insetBottom = edges.contains(SafeAreaViewEdges.BOTTOM) ? insets.bottom : 0;
97
+ float insetLeft = edges.contains(SafeAreaViewEdges.LEFT) ? insets.left : 0;
98
+
99
+ if (mLocalData.getMode() == SafeAreaViewMode.PADDING) {
100
+ super.setPadding(Spacing.TOP, insetTop + top);
101
+ super.setPadding(Spacing.RIGHT, insetRight + right);
102
+ super.setPadding(Spacing.BOTTOM, insetBottom + bottom);
103
+ super.setPadding(Spacing.LEFT, insetLeft + left);
104
+ } else {
105
+ super.setMargin(Spacing.TOP, insetTop + top);
106
+ super.setMargin(Spacing.RIGHT, insetRight + right);
107
+ super.setMargin(Spacing.BOTTOM, insetBottom + bottom);
108
+ super.setMargin(Spacing.LEFT, insetLeft + left);
109
+ }
110
+ }
111
+
112
+ private void resetInsets(SafeAreaViewMode mode) {
113
+ if (mode == SafeAreaViewMode.PADDING) {
114
+ super.setPadding(Spacing.TOP, mPaddings[Spacing.TOP]);
115
+ super.setPadding(Spacing.RIGHT, mPaddings[Spacing.TOP]);
116
+ super.setPadding(Spacing.BOTTOM, mPaddings[Spacing.BOTTOM]);
117
+ super.setPadding(Spacing.LEFT, mPaddings[Spacing.LEFT]);
118
+ } else {
119
+ super.setMargin(Spacing.TOP, mMargins[Spacing.TOP]);
120
+ super.setMargin(Spacing.RIGHT, mMargins[Spacing.TOP]);
121
+ super.setMargin(Spacing.BOTTOM, mMargins[Spacing.BOTTOM]);
122
+ super.setMargin(Spacing.LEFT, mMargins[Spacing.LEFT]);
123
+ }
124
+ }
125
+
126
+ // The signature for onBeforeLayout is different in RN 0.59.
127
+ // Remove when we drop support for this version and add back @Override and super call to
128
+ // onBeforeLayout(NativeViewHierarchyOptimizer).
129
+ public void onBeforeLayout() {
130
+ if (mNeedsUpdate) {
131
+ mNeedsUpdate = false;
132
+ updateInsets();
133
+ }
134
+ }
135
+
136
+ public void onBeforeLayout(NativeViewHierarchyOptimizer nativeViewHierarchyOptimizer) {
137
+ if (mNeedsUpdate) {
138
+ mNeedsUpdate = false;
139
+ updateInsets();
140
+ }
141
+ }
142
+
143
+ @Override
144
+ public void setLocalData(Object data) {
145
+ if (!(data instanceof SafeAreaViewLocalData)) {
146
+ return;
147
+ }
148
+
149
+ SafeAreaViewLocalData localData = (SafeAreaViewLocalData) data;
150
+
151
+ if (mLocalData != null && mLocalData.getMode() != localData.getMode()) {
152
+ resetInsets(mLocalData.getMode());
153
+ }
154
+
155
+ mLocalData = localData;
156
+
157
+ mNeedsUpdate = false;
158
+ updateInsets();
159
+ }
160
+
161
+ // Names needs to reflect exact order in LayoutShadowNode.java
162
+ @Override
163
+ @ReactPropGroup(
164
+ names = {
165
+ ViewProps.PADDING,
166
+ ViewProps.PADDING_VERTICAL,
167
+ ViewProps.PADDING_HORIZONTAL,
168
+ ViewProps.PADDING_START,
169
+ ViewProps.PADDING_END,
170
+ ViewProps.PADDING_TOP,
171
+ ViewProps.PADDING_BOTTOM,
172
+ ViewProps.PADDING_LEFT,
173
+ ViewProps.PADDING_RIGHT,
174
+ })
175
+ public void setPaddings(int index, Dynamic padding) {
176
+ int spacingType = ViewProps.PADDING_MARGIN_SPACING_TYPES[index];
177
+ mPaddings[spacingType] = padding.getType() == ReadableType.Number ? (float) padding.asDouble() : Float.NaN;
178
+ super.setPaddings(index, padding);
179
+ mNeedsUpdate = true;
180
+ }
181
+
182
+ @Override
183
+ @ReactPropGroup(
184
+ names = {
185
+ ViewProps.MARGIN,
186
+ ViewProps.MARGIN_VERTICAL,
187
+ ViewProps.MARGIN_HORIZONTAL,
188
+ ViewProps.MARGIN_START,
189
+ ViewProps.MARGIN_END,
190
+ ViewProps.MARGIN_TOP,
191
+ ViewProps.MARGIN_BOTTOM,
192
+ ViewProps.MARGIN_LEFT,
193
+ ViewProps.MARGIN_RIGHT,
194
+ })
195
+ public void setMargins(int index, Dynamic margin) {
196
+ int spacingType = ViewProps.PADDING_MARGIN_SPACING_TYPES[index];
197
+ mMargins[spacingType] = margin.getType() == ReadableType.Number ? (float) margin.asDouble() : Float.NaN;
198
+ super.setMargins(index, margin);
199
+ mNeedsUpdate = true;
200
+ }
201
+ }
@@ -0,0 +1,52 @@
1
+ package com.th3rdwave.safeareacontext;
2
+
3
+ import com.facebook.react.bridge.Arguments;
4
+ import com.facebook.react.bridge.WritableMap;
5
+ import com.facebook.react.common.MapBuilder;
6
+ import com.facebook.react.uimanager.PixelUtil;
7
+
8
+ import java.util.Map;
9
+
10
+ /* package */ class SerializationUtils {
11
+ static WritableMap edgeInsetsToJsMap(EdgeInsets insets) {
12
+ WritableMap insetsMap = Arguments.createMap();
13
+ insetsMap.putDouble("top", PixelUtil.toDIPFromPixel(insets.top));
14
+ insetsMap.putDouble("right", PixelUtil.toDIPFromPixel(insets.right));
15
+ insetsMap.putDouble("bottom", PixelUtil.toDIPFromPixel(insets.bottom));
16
+ insetsMap.putDouble("left", PixelUtil.toDIPFromPixel(insets.left));
17
+ return insetsMap;
18
+ }
19
+
20
+ static Map<String, Float> edgeInsetsToJavaMap(EdgeInsets insets) {
21
+ return MapBuilder.of(
22
+ "top",
23
+ PixelUtil.toDIPFromPixel(insets.top),
24
+ "right",
25
+ PixelUtil.toDIPFromPixel(insets.right),
26
+ "bottom",
27
+ PixelUtil.toDIPFromPixel(insets.bottom),
28
+ "left",
29
+ PixelUtil.toDIPFromPixel(insets.left));
30
+ }
31
+
32
+ static WritableMap rectToJsMap(Rect rect) {
33
+ WritableMap rectMap = Arguments.createMap();
34
+ rectMap.putDouble("x", PixelUtil.toDIPFromPixel(rect.x));
35
+ rectMap.putDouble("y", PixelUtil.toDIPFromPixel(rect.y));
36
+ rectMap.putDouble("width", PixelUtil.toDIPFromPixel(rect.width));
37
+ rectMap.putDouble("height", PixelUtil.toDIPFromPixel(rect.height));
38
+ return rectMap;
39
+ }
40
+
41
+ static Map<String, Float> rectToJavaMap(Rect rect) {
42
+ return MapBuilder.of(
43
+ "x",
44
+ PixelUtil.toDIPFromPixel(rect.x),
45
+ "y",
46
+ PixelUtil.toDIPFromPixel(rect.y),
47
+ "width",
48
+ PixelUtil.toDIPFromPixel(rect.width),
49
+ "height",
50
+ PixelUtil.toDIPFromPixel(rect.height));
51
+ }
52
+ }
@@ -0,0 +1,16 @@
1
+ #import <UIKit/UIKit.h>
2
+ #import <React/RCTDefines.h>
3
+ #import <React/RCTView.h>
4
+
5
+ RCT_EXTERN BOOL UIEdgeInsetsEqualToEdgeInsetsWithThreshold(UIEdgeInsets insets1, UIEdgeInsets insets2, CGFloat threshold);
6
+
7
+ NS_ASSUME_NONNULL_BEGIN
8
+
9
+ @interface UIView(SafeAreaCompat)
10
+
11
+ - (BOOL)nativeSafeAreaSupport;
12
+ - (UIEdgeInsets)safeAreaInsetsOrEmulate;
13
+
14
+ @end
15
+
16
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,57 @@
1
+ #import "RCTView+SafeAreaCompat.h"
2
+
3
+ #import <React/RCTUIManager.h>
4
+
5
+ BOOL UIEdgeInsetsEqualToEdgeInsetsWithThreshold(UIEdgeInsets insets1, UIEdgeInsets insets2, CGFloat threshold)
6
+ {
7
+ return ABS(insets1.left - insets2.left) <= threshold &&
8
+ ABS(insets1.right - insets2.right) <= threshold &&
9
+ ABS(insets1.top - insets2.top) <= threshold &&
10
+ ABS(insets1.bottom - insets2.bottom) <= threshold;
11
+ }
12
+
13
+ @implementation UIView(SafeAreaCompat)
14
+
15
+ - (BOOL)nativeSafeAreaSupport
16
+ {
17
+ return [self respondsToSelector:@selector(safeAreaInsets)];
18
+ }
19
+
20
+ - (UIEdgeInsets)safeAreaInsetsOrEmulate
21
+ {
22
+ #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
23
+ if (self.nativeSafeAreaSupport) {
24
+ if (@available(iOS 11.0, *)) {
25
+ return self.safeAreaInsets;
26
+ }
27
+ }
28
+ #endif
29
+ return self.emulatedSafeAreaInsets;
30
+ }
31
+
32
+ - (UIEdgeInsets)emulatedSafeAreaInsets
33
+ {
34
+ UIViewController* vc = self.reactViewController;
35
+
36
+ if (!vc) {
37
+ return UIEdgeInsetsZero;
38
+ }
39
+
40
+ CGFloat topLayoutOffset = vc.topLayoutGuide.length;
41
+ CGFloat bottomLayoutOffset = vc.bottomLayoutGuide.length;
42
+ CGRect safeArea = vc.view.bounds;
43
+ safeArea.origin.y += topLayoutOffset;
44
+ safeArea.size.height -= topLayoutOffset + bottomLayoutOffset;
45
+ CGRect localSafeArea = [vc.view convertRect:safeArea toView:self];
46
+ UIEdgeInsets safeAreaInsets = UIEdgeInsetsMake(0, 0, 0, 0);
47
+ if (CGRectGetMinY(localSafeArea) > CGRectGetMinY(self.bounds)) {
48
+ safeAreaInsets.top = CGRectGetMinY(localSafeArea) - CGRectGetMinY(self.bounds);
49
+ }
50
+ if (CGRectGetMaxY(localSafeArea) < CGRectGetMaxY(self.bounds)) {
51
+ safeAreaInsets.bottom = CGRectGetMaxY(self.bounds) - CGRectGetMaxY(localSafeArea);
52
+ }
53
+
54
+ return safeAreaInsets;
55
+ }
56
+
57
+ @end
@@ -0,0 +1,13 @@
1
+ #import <UIKit/UIKit.h>
2
+
3
+ #import <React/RCTView.h>
4
+
5
+ NS_ASSUME_NONNULL_BEGIN
6
+
7
+ @interface RNCSafeAreaProvider : RCTView
8
+
9
+ @property (nonatomic, copy) RCTBubblingEventBlock onInsetsChange;
10
+
11
+ @end
12
+
13
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,65 @@
1
+ #import "RNCSafeAreaProvider.h"
2
+
3
+ #import <React/RCTBridge.h>
4
+ #import <React/RCTUIManager.h>
5
+ #import "RCTView+SafeAreaCompat.h"
6
+
7
+ @implementation RNCSafeAreaProvider
8
+ {
9
+ UIEdgeInsets _currentSafeAreaInsets;
10
+ CGRect _currentFrame;
11
+ BOOL _initialInsetsSent;
12
+ }
13
+
14
+ - (void)safeAreaInsetsDidChange
15
+ {
16
+ [self invalidateSafeAreaInsets];
17
+ }
18
+
19
+ - (void)invalidateSafeAreaInsets
20
+ {
21
+ // This gets called before the view size is set by react-native so
22
+ // make sure to wait so we don't set wrong insets to JS.
23
+ if (CGSizeEqualToSize(self.frame.size, CGSizeZero)) {
24
+ return;
25
+ }
26
+
27
+ UIEdgeInsets safeAreaInsets = [self safeAreaInsetsOrEmulate];
28
+ CGRect frame = [self convertRect:self.bounds toView:nil];
29
+
30
+ if (
31
+ _initialInsetsSent &&
32
+ UIEdgeInsetsEqualToEdgeInsetsWithThreshold(safeAreaInsets, _currentSafeAreaInsets, 1.0 / RCTScreenScale()) &&
33
+ CGRectEqualToRect(frame, _currentFrame)
34
+ ) {
35
+ return;
36
+ }
37
+
38
+ _initialInsetsSent = YES;
39
+ _currentSafeAreaInsets = safeAreaInsets;
40
+ _currentFrame = frame;
41
+
42
+ self.onInsetsChange(@{
43
+ @"insets": @{
44
+ @"top": @(safeAreaInsets.top),
45
+ @"right": @(safeAreaInsets.right),
46
+ @"bottom": @(safeAreaInsets.bottom),
47
+ @"left": @(safeAreaInsets.left),
48
+ },
49
+ @"frame": @{
50
+ @"x": @(frame.origin.x),
51
+ @"y": @(frame.origin.y),
52
+ @"width": @(frame.size.width),
53
+ @"height": @(frame.size.height),
54
+ },
55
+ });
56
+ }
57
+
58
+ - (void)layoutSubviews
59
+ {
60
+ [super layoutSubviews];
61
+
62
+ [self invalidateSafeAreaInsets];
63
+ }
64
+
65
+ @end
@@ -0,0 +1,9 @@
1
+ #import <React/RCTViewManager.h>
2
+
3
+ NS_ASSUME_NONNULL_BEGIN
4
+
5
+ @interface RNCSafeAreaProviderManager : RCTViewManager
6
+
7
+ @end
8
+
9
+ NS_ASSUME_NONNULL_END