This commit is contained in:
Yamozha
2021-04-02 02:24:13 +03:00
parent c23950b545
commit 7256d79e2c
31493 changed files with 3036630 additions and 0 deletions

21
node_modules/react-native-safe-area-context/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Th3rd Wave
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

310
node_modules/react-native-safe-area-context/README.md generated vendored Normal file
View File

@ -0,0 +1,310 @@
# react-native-safe-area-context
[![npm](https://img.shields.io/npm/v/react-native-safe-area-context)](https://www.npmjs.com/package/react-native-safe-area-context) ![Supports Android, iOS, web, macOS and Windows](https://img.shields.io/badge/platforms-android%20%7C%20ios%20%7C%20web%20%7C%20macos%20%7C%20windows-lightgrey.svg) ![MIT License](https://img.shields.io/npm/l/react-native-safe-area-context.svg)
[![JavaScript tests](https://github.com/th3rdwave/react-native-safe-area-context/workflows/JavaScript%20tests/badge.svg)](https://github.com/th3rdwave/react-native-safe-area-context/actions?query=workflow%3AJavaScript%20tests) [![iOS build](https://github.com/th3rdwave/react-native-safe-area-context/workflows/iOS%20build/badge.svg)](https://github.com/th3rdwave/react-native-safe-area-context/actions?query=workflow%3AiOS%20build) [![Android build](https://github.com/th3rdwave/react-native-safe-area-context/workflows/Android%20build/badge.svg)](https://github.com/th3rdwave/react-native-safe-area-context/actions?query=workflow%3AAndroid%20build)
A flexible way to handle safe area, also works on Android and Web!
## Getting started
```
npm install react-native-safe-area-context
```
You then need to link the native parts of the library for the platforms you are using.
#### Linking in React Native >= 0.60
Linking the package is not required anymore with [Autolinking](https://github.com/react-native-community/cli/blob/master/docs/autolinking.md).
- **iOS Platform:**
`$ npx pod-install`
#### Linking in React Native < 0.60
The easiest way to link the library is using the CLI tool by running this command from the root of your project:
```
react-native link react-native-safe-area-context
```
If you can't or don't want to use the CLI tool, you can also manually link the library using the instructions below (click on the arrow to show them):
<details>
<summary>Manually link the library on iOS</summary>
Either follow the [instructions in the React Native documentation](https://facebook.github.io/react-native/docs/linking-libraries-ios#manual-linking) to manually link the framework or link using [Cocoapods](https://cocoapods.org) by adding this to your `Podfile`:
```ruby
pod 'react-native-safe-area-context', :path => '../node_modules/react-native-safe-area-context'
```
</details>
<details>
<summary>Manually link the library on Android</summary>
Make the following changes:
#### `android/settings.gradle`
```groovy
include ':react-native-safe-area-context'
project(':react-native-safe-area-context').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-safe-area-context/android')
```
#### `android/app/build.gradle`
```groovy
dependencies {
...
implementation project(':react-native-safe-area-context')
}
```
#### `android/app/src/main/.../MainApplication.java`
On top, where imports are:
```java
import com.th3rdwave.safeareacontext.SafeAreaContextPackage;
```
Add the `SafeAreaContextPackage` class to your list of exported packages.
```java
@Override
protected List<ReactPackage> getPackages() {
return Arrays.asList(
new MainReactPackage(),
...
new SafeAreaContextPackage()
);
}
```
</details>
## Usage
This library has 2 important concepts, if you are familiar with React Context this is very similar.
### Providers
The [SafeAreaProvider](#safeareaprovider) component is a `View` from where insets provided by [Consumers](#consumers) are relative to. This means that if this view overlaps with any system elements (status bar, notches, etc.) these values will be provided to descendent consumers. Usually you will have one provider at the top of your app.
### Consumers
Consumers are components and hooks that allow using inset values provided by the nearest parent [Provider](#providers). Values are always relative to a provider and not to these components.
- [SafeAreaView](#safeareaview) is the preferred way to consume insets. This is a regular `View` with insets applied as extra padding or margin. It offers better performance by applying insets natively and avoids flickers that can happen with the other JS based consumers.
- [useSafeAreaInsets](#usesafeareainsets) offers more flexibility, but can cause some layout flicker in certain cases. Use this if you need more control over how insets are applied.
## API
### SafeAreaProvider
You should add `SafeAreaProvider` in your app root component. You may need to add it in other places like the root of modals and routes when using `react-native-screen`.
Note that providers should not be inside a `View` that is animated with `Animated` or inside a `ScrollView` since it can cause very frequent updates.
#### Example
```js
import { SafeAreaProvider } from 'react-native-safe-area-context';
function App() {
return <SafeAreaProvider>...</SafeAreaProvider>;
}
```
#### Props
Accepts all [View](https://reactnative.dev/docs/view#props) props. Has a default style of `{flex: 1}`.
##### `initialMetrics`
Optional, defaults to `null`.
Can be used to provide the initial value for frame and insets, this allows rendering immediatly. See [optimization](#optimization) for more information on how to use this prop.
### SafeAreaView
`SafeAreaView` is a regular `View` component with the safe area insets applied as padding or margin.
Padding or margin styles are added to the insets, for example `style={{paddingTop: 10}}` on a `SafeAreaView` that has insets of 20 will result in a top padding of 30.
#### Example
```js
import { SafeAreaView } from 'react-native-safe-area-context';
function SomeComponent() {
return (
<SafeAreaView style={{ flex: 1, backgroundColor: 'red' }}>
<View style={{ flex: 1, backgroundColor: 'blue' }} />
</SafeAreaView>
);
}
```
#### Props
Accepts all [View](https://reactnative.dev/docs/view#props) props.
##### `edges`
Optional, array of `top`, `right`, `bottom`, and `left`. Defaults to all.
Sets the edges to apply the safe area insets to.
For example if you don't want insets to apply to the top edge because the view does not touch the top of the screen you can use:
```js
<SafeAreaView edges={['right', 'bottom', 'left']} />
```
##### `mode`
Optional, `padding` (default) or `margin`.
Apply the safe area to either the padding or the margin.
This can be useful for example to create a safe area aware separator component:
```js
<SafeAreaView mode="margin" style={{ height: 1, backgroundColor: '#eee' }} />
```
### useSafeAreaInsets
Returns the safe area insets of the nearest provider. This allows manipulating the inset values from JavaScript. Note that insets are not updated synchronously so it might cause a slight delay for example when rotating the screen.
Object with `{ top: number, right: number, bottom: number, left: number }`.
```js
import { useSafeAreaInsets } from 'react-native-safe-area-context';
function HookComponent() {
const insets = useSafeAreaInsets();
return <View style={{ paddingBottom: Math.max(insets.bottom, 16) }} />;
}
```
### useSafeAreaFrame
Returns the frame of the nearest provider. This can be used as an alternative to the `Dimensions` module.
Object with `{ x: number, y: number, width: number, height: number }`
### `SafeAreaInsetsContext`
React Context with the value of the safe area insets.
Can be used with class components:
```js
import { SafeAreaInsetsContext } from 'react-native-safe-area-context';
class ClassComponent extends React.Component {
render() {
return (
<SafeAreaInsetsContext.Consumer>
{(insets) => <View style={{ paddingTop: insets.top }} />}
</SafeAreaInsetsContext.Consumer>
);
}
}
```
### `withSafeAreaInsets`
Higher order component that provides safe area insets as the `insets` prop.
### `SafeAreaFrameContext`
React Context with the value of the safe area frame.
### `initialWindowMetrics`
Insets and frame of the window on initial render. This can be used with the `initialMetrics` from `SafeAreaProvider`. See [optimization](#optimization) for more information.
Object with:
```ts
{
frame: { x: number, y: number, width: number, height: number },
insets: { top: number, left: number, right: number, bottom: number },
}
```
## Deprecated apis
### useSafeArea
Use `useSafeAreaInsets` intead.
### SafeAreaConsumer
Use `SafeAreaInsetsContext.Consumer` instead.
### SafeAreaContext
Use `SafeAreaInsetsContext` instead.
### initialWindowSafeAreaInsets
Use `initialWindowMetrics` instead.
## Web SSR
If you are doing server side rendering on the web you can use `initialMetrics` to inject insets and frame value based on the device the user has, or simply pass zero values. Since insets measurement is async it will break rendering your page content otherwise.
## Optimization
If you can, use `SafeAreaView`. It's implemented natively so when rotating the device, there is no delay from the asynchronous bridge.
To speed up the initial render, you can import `initialWindowMetrics` from this package and set as the `initialMetrics` prop on the provider as described in Web SSR. You cannot do this if your provider remounts, or you are using `react-native-navigation`.
```js
import {
SafeAreaProvider,
initialWindowMetrics,
} from 'react-native-safe-area-context';
function App() {
return (
<SafeAreaProvider initialMetrics={initialWindowMetrics}>
...
</SafeAreaProvider>
);
}
```
## Testing
When testing components nested under `SafeAreaProvider`, ensure to pass `initialMetrics` to
provide mock data for frame and insets and ensure the provider renders its children.
```js
export function TestSafeAreaProvider({ children }) {
return (
<SafeAreaProvider
initialMetrics={{
frame: { x: 0, y: 0, width: 0, height: 0 },
insets: { top: 0, left: 0, right: 0, bottom: 0 },
}}
>
{children}
</SafeAreaProvider>
);
}
```
## Contributing
See the [Contributing Guide](CONTRIBUTING.md)

View File

@ -0,0 +1,46 @@
def getExtOrDefault(name, defaultValue) {
return rootProject.ext.has(name) ? rootProject.ext.get(name) : defaultValue
}
buildscript {
// The Android Gradle plugin is only required when opening the android folder stand-alone.
// This avoids unnecessary downloads and potential conflicts when the library is included as a
// module dependency in an application project.
if (project == rootProject) {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
}
}
}
apply plugin: 'com.android.library'
android {
compileSdkVersion getExtOrDefault('compileSdkVersion', 28)
defaultConfig {
minSdkVersion getExtOrDefault('minSdkVersion', 16)
targetSdkVersion getExtOrDefault('targetSdkVersion', 28)
}
lintOptions{
abortOnError false
}
}
repositories {
google()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
jcenter()
}
dependencies {
//noinspection GradleDynamicVersion
implementation 'com.facebook.react:react-native:+'
}

View File

@ -0,0 +1,6 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.th3rdwave.safeareacontext">
</manifest>

View File

@ -0,0 +1,22 @@
package com.th3rdwave.safeareacontext;
/* package */ class EdgeInsets {
float top;
float right;
float bottom;
float left;
EdgeInsets(float top, float right, float bottom, float left) {
this.top = top;
this.right = right;
this.bottom = bottom;
this.left = left;
}
boolean equalsToEdgeInsets(EdgeInsets other) {
if (this == other) {
return true;
}
return this.top == other.top && this.right == other.right && this.bottom == other.bottom && this.left == other.left;
}
}

View File

@ -0,0 +1,33 @@
package com.th3rdwave.safeareacontext;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;
/* package */ class InsetsChangeEvent extends Event<InsetsChangeEvent> {
static final String EVENT_NAME = "topInsetsChange";
private EdgeInsets mInsets;
private Rect mFrame;
InsetsChangeEvent(int viewTag, EdgeInsets insets, Rect frame) {
super(viewTag);
mInsets = insets;
mFrame = frame;
}
@Override
public String getEventName() {
return EVENT_NAME;
}
@Override
public void dispatch(RCTEventEmitter rctEventEmitter) {
WritableMap event = Arguments.createMap();
event.putMap("insets", SerializationUtils.edgeInsetsToJsMap(mInsets));
event.putMap("frame", SerializationUtils.rectToJsMap(mFrame));
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), event);
}
}

View File

@ -0,0 +1,22 @@
package com.th3rdwave.safeareacontext;
/* package */ class Rect {
float x;
float y;
float width;
float height;
Rect(float x, float y, float width, float height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
boolean equalsToRect(Rect other) {
if (this == other) {
return true;
}
return this.x == other.x && this.y == other.y && this.width == other.width && this.height == other.height;
}
}

View File

@ -0,0 +1,31 @@
package com.th3rdwave.safeareacontext;
import androidx.annotation.NonNull;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class SafeAreaContextPackage implements ReactPackage {
@NonNull
@Override
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@NonNull
@Override
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(
new SafeAreaProviderManager(reactContext),
new SafeAreaViewManager()
);
}
}

View File

@ -0,0 +1,66 @@
package com.th3rdwave.safeareacontext;
import android.annotation.SuppressLint;
import android.content.Context;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.views.view.ReactViewGroup;
import androidx.annotation.Nullable;
@SuppressLint("ViewConstructor")
public class SafeAreaProvider extends ReactViewGroup implements ViewTreeObserver.OnPreDrawListener {
public interface OnInsetsChangeListener {
void onInsetsChange(SafeAreaProvider view, EdgeInsets insets, Rect frame);
}
private @Nullable OnInsetsChangeListener mInsetsChangeListener;
private @Nullable EdgeInsets mLastInsets;
private @Nullable Rect mLastFrame;
public SafeAreaProvider(Context context) {
super(context);
}
private void maybeUpdateInsets() {
EdgeInsets edgeInsets = SafeAreaUtils.getSafeAreaInsets(this);
Rect frame = SafeAreaUtils.getFrame((ViewGroup) getRootView(), this);
if (edgeInsets != null && frame != null &&
(mLastInsets == null ||
mLastFrame == null ||
!mLastInsets.equalsToEdgeInsets(edgeInsets) ||
!mLastFrame.equalsToRect(frame))) {
Assertions.assertNotNull(mInsetsChangeListener).onInsetsChange(this, edgeInsets, frame);
mLastInsets = edgeInsets;
mLastFrame = frame;
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getViewTreeObserver().addOnPreDrawListener(this);
maybeUpdateInsets();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
getViewTreeObserver().removeOnPreDrawListener(this);
}
@Override
public boolean onPreDraw() {
maybeUpdateInsets();
return true;
}
public void setOnInsetsChangeListener(OnInsetsChangeListener listener) {
mInsetsChangeListener = listener;
}
}

View File

@ -0,0 +1,91 @@
package com.th3rdwave.safeareacontext;
import android.app.Activity;
import android.view.View;
import android.view.ViewGroup;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.events.EventDispatcher;
import java.util.Map;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class SafeAreaProviderManager extends ViewGroupManager<SafeAreaProvider> {
private final ReactApplicationContext mContext;
public SafeAreaProviderManager(ReactApplicationContext context) {
super();
mContext = context;
}
@Override
@NonNull
public String getName() {
return "RNCSafeAreaProvider";
}
@Override
@NonNull
public SafeAreaProvider createViewInstance(@NonNull ThemedReactContext context) {
return new SafeAreaProvider(context);
}
@Override
protected void addEventEmitters(@NonNull ThemedReactContext reactContext, @NonNull final SafeAreaProvider view) {
final EventDispatcher dispatcher =
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
view.setOnInsetsChangeListener(new SafeAreaProvider.OnInsetsChangeListener() {
@Override
public void onInsetsChange(SafeAreaProvider view, EdgeInsets insets, Rect frame) {
dispatcher.dispatchEvent(new InsetsChangeEvent(view.getId(), insets, frame));
}
});
}
@Override
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
return MapBuilder.<String, Object>builder()
.put(InsetsChangeEvent.EVENT_NAME, MapBuilder.of("registrationName", "onInsetsChange"))
.build();
}
private @Nullable Map<String, Object> getInitialWindowMetrics() {
Activity activity = mContext.getCurrentActivity();
if (activity == null) {
return null;
}
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
if (decorView == null) {
return null;
}
View contentView = decorView.findViewById(android.R.id.content);
EdgeInsets insets = SafeAreaUtils.getSafeAreaInsets(decorView);
Rect frame = SafeAreaUtils.getFrame(decorView, contentView);
if (insets == null || frame == null) {
return null;
}
return MapBuilder.<String, Object>of(
"insets",
SerializationUtils.edgeInsetsToJavaMap(insets),
"frame",
SerializationUtils.rectToJavaMap(frame));
}
@Nullable
@Override
public Map<String, Object> getExportedViewConstants() {
return MapBuilder.<String, Object>of(
"initialWindowMetrics",
getInitialWindowMetrics());
}
}

View File

@ -0,0 +1,82 @@
package com.th3rdwave.safeareacontext;
import android.graphics.Rect;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import androidx.annotation.Nullable;
/* package */ class SafeAreaUtils {
private static @Nullable EdgeInsets getRootWindowInsetsCompat(View rootView) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
WindowInsets insets = rootView.getRootWindowInsets();
if (insets == null) {
return null;
}
return new EdgeInsets(
insets.getSystemWindowInsetTop(),
insets.getSystemWindowInsetRight(),
// System insets are more reliable to account for notches but the
// system inset for bottom includes the soft keyboard which we don't
// want to be consistent with iOS. Using the min value makes sure we
// never get the keyboard offset while still working with devices that
// hide the navigation bar.
Math.min(insets.getSystemWindowInsetBottom(), insets.getStableInsetBottom()),
insets.getSystemWindowInsetLeft());
} else {
Rect visibleRect = new Rect();
rootView.getWindowVisibleDisplayFrame(visibleRect);
return new EdgeInsets(
visibleRect.top,
rootView.getWidth() - visibleRect.right,
rootView.getHeight() - visibleRect.bottom,
visibleRect.left);
}
}
static @Nullable EdgeInsets getSafeAreaInsets(View view) {
// The view has not been layout yet.
if (view.getHeight() == 0) {
return null;
}
View rootView = view.getRootView();
EdgeInsets windowInsets = getRootWindowInsetsCompat(rootView);
if (windowInsets == null) {
return null;
}
// Calculate the part of the view that overlaps with window insets.
float windowWidth = rootView.getWidth();
float windowHeight = rootView.getHeight();
Rect visibleRect = new Rect();
view.getGlobalVisibleRect(visibleRect);
windowInsets.top = Math.max(windowInsets.top - visibleRect.top, 0);
windowInsets.left = Math.max(windowInsets.left - visibleRect.left, 0);
windowInsets.bottom = Math.max(visibleRect.top + view.getHeight() + windowInsets.bottom - windowHeight, 0);
windowInsets.right = Math.max(visibleRect.left + view.getWidth() + windowInsets.right - windowWidth, 0);
return windowInsets;
}
static @Nullable com.th3rdwave.safeareacontext.Rect getFrame(ViewGroup rootView, View view) {
// This can happen while the view gets unmounted.
if (view.getParent() == null) {
return null;
}
Rect offset = new Rect();
view.getDrawingRect(offset);
try {
rootView.offsetDescendantRectToMyCoords(view, offset);
} catch (IllegalArgumentException ex) {
// This can throw if the view is not a descendant of rootView. This should not
// happen but avoid potential crashes.
ex.printStackTrace();
return null;
}
return new com.th3rdwave.safeareacontext.Rect(offset.left, offset.top, view.getWidth(), view.getHeight());
}
}

View File

@ -0,0 +1,159 @@
package com.th3rdwave.safeareacontext;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.ContextWrapper;
import android.util.Log;
import android.view.View;
import android.view.ViewParent;
import android.view.ViewTreeObserver;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.views.view.ReactViewGroup;
import java.util.EnumSet;
import java.util.concurrent.atomic.AtomicBoolean;
import androidx.annotation.Nullable;
@SuppressLint("ViewConstructor")
public class SafeAreaView extends ReactViewGroup implements ViewTreeObserver.OnPreDrawListener {
private SafeAreaViewMode mMode = SafeAreaViewMode.PADDING;
private @Nullable EdgeInsets mInsets;
private @Nullable EnumSet<SafeAreaViewEdges> mEdges;
private @Nullable View mProviderView;
public SafeAreaView(Context context) {
super(context);
}
/**
* UIManagerHelper.getReactContext only exists in RN 0.63+ so vendor it here for a while.
*/
private static ReactContext getReactContext(View view) {
Context context = view.getContext();
if (!(context instanceof ReactContext) && context instanceof ContextWrapper) {
context = ((ContextWrapper) context).getBaseContext();
}
return (ReactContext) context;
}
private void updateInsets() {
if (mInsets != null) {
EnumSet<SafeAreaViewEdges> edges = mEdges != null
? mEdges
: EnumSet.allOf(SafeAreaViewEdges.class);
SafeAreaViewLocalData localData = new SafeAreaViewLocalData(mInsets, mMode, edges);
ReactContext reactContext = getReactContext(this);
UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class);
if (uiManager != null) {
uiManager.setViewLocalData(getId(), localData);
waitForReactLayout();
}
}
}
private static final long MAX_WAIT_TIME_NANO = 500000000L; // 500ms
private void waitForReactLayout() {
// Block the main thread until the native module thread is finished with
// its current tasks. To do this we use the done boolean as a lock and enqueue
// a task on the native modules thread. When the task runs we can unblock the
// main thread. This should be safe as long as the native modules thread
// does not block waiting on the main thread.
final AtomicBoolean done = new AtomicBoolean(false);
final long startTime = System.nanoTime();
long waitTime = 0L;
getReactContext(this).runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
synchronized (done) {
if (done.compareAndSet(false, true)) {
done.notify();
}
}
}
});
synchronized (done) {
while (!done.get() && waitTime < MAX_WAIT_TIME_NANO) {
try {
done.wait(MAX_WAIT_TIME_NANO / 1000000L);
} catch (InterruptedException e) {
// In case of an interrupt just give up waiting.
done.set(true);
}
waitTime += System.nanoTime() - startTime;
}
// Timed out waiting.
if (waitTime >= MAX_WAIT_TIME_NANO) {
Log.w("SafeAreaView", "Timed out waiting for layout.");
}
}
}
public void setMode(SafeAreaViewMode mode) {
mMode = mode;
updateInsets();
}
public void setEdges(EnumSet<SafeAreaViewEdges> edges) {
mEdges = edges;
updateInsets();
}
private boolean maybeUpdateInsets() {
if (mProviderView == null) {
return false;
}
EdgeInsets edgeInsets = SafeAreaUtils.getSafeAreaInsets(mProviderView);
if (edgeInsets != null && (mInsets == null || !mInsets.equalsToEdgeInsets(edgeInsets))) {
mInsets = edgeInsets;
updateInsets();
return true;
}
return false;
}
private View findProvider() {
ViewParent current = getParent();
while (current != null) {
if (current instanceof SafeAreaProvider) {
return (View) current;
}
current = current.getParent();
}
return this;
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mProviderView = findProvider();
mProviderView.getViewTreeObserver().addOnPreDrawListener(this);
maybeUpdateInsets();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mProviderView != null) {
mProviderView.getViewTreeObserver().removeOnPreDrawListener(this);
}
mProviderView = null;
}
@Override
public boolean onPreDraw() {
boolean didUpdate = maybeUpdateInsets();
if (didUpdate) {
requestLayout();
}
return !didUpdate;
}
}

View File

@ -0,0 +1,8 @@
package com.th3rdwave.safeareacontext;
public enum SafeAreaViewEdges {
TOP,
RIGHT,
BOTTOM,
LEFT
}

View File

@ -0,0 +1,27 @@
package com.th3rdwave.safeareacontext;
import java.util.EnumSet;
public class SafeAreaViewLocalData {
private EdgeInsets mInsets;
private SafeAreaViewMode mMode;
private EnumSet<SafeAreaViewEdges> mEdges;
public SafeAreaViewLocalData(EdgeInsets insets, SafeAreaViewMode mode, EnumSet<SafeAreaViewEdges> edges) {
mInsets = insets;
mMode = mode;
mEdges = edges;
}
public EdgeInsets getInsets() {
return mInsets;
}
public SafeAreaViewMode getMode() {
return mMode;
}
public EnumSet<SafeAreaViewEdges> getEdges() {
return mEdges;
}
}

View File

@ -0,0 +1,72 @@
package com.th3rdwave.safeareacontext;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.uimanager.LayoutShadowNode;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.views.view.ReactViewManager;
import java.util.EnumSet;
public class SafeAreaViewManager extends ReactViewManager {
public SafeAreaViewManager() {
super();
}
@Override
@NonNull
public String getName() {
return "RNCSafeAreaView";
}
@Override
@NonNull
public SafeAreaView createViewInstance(@NonNull ThemedReactContext context) {
return new SafeAreaView(context);
}
@Override
@NonNull
public SafeAreaViewShadowNode createShadowNodeInstance() {
return new SafeAreaViewShadowNode();
}
@Override
public Class<? extends LayoutShadowNode> getShadowNodeClass() {
return SafeAreaViewShadowNode.class;
}
@ReactProp(name = "mode")
public void setMode(SafeAreaView view, @Nullable String mode) {
if ("padding".equals(mode)) {
view.setMode(SafeAreaViewMode.PADDING);
} else if ("margin".equals(mode)) {
view.setMode(SafeAreaViewMode.MARGIN);
}
}
@ReactProp(name = "edges")
public void setEdges(SafeAreaView view, @Nullable ReadableArray propList) {
EnumSet<SafeAreaViewEdges> edges = EnumSet.noneOf(SafeAreaViewEdges.class);
if (propList != null) {
for (int i = 0; i < propList.size(); i += 1) {
String edgeName = propList.getString(i);
if ("top".equals(edgeName)) {
edges.add(SafeAreaViewEdges.TOP);
} else if ("right".equals(edgeName)) {
edges.add(SafeAreaViewEdges.RIGHT);
} else if ("bottom".equals(edgeName)) {
edges.add(SafeAreaViewEdges.BOTTOM);
} else if ("left".equals(edgeName)) {
edges.add(SafeAreaViewEdges.LEFT);
}
}
}
view.setEdges(edges);
}
}

View File

@ -0,0 +1,6 @@
package com.th3rdwave.safeareacontext;
public enum SafeAreaViewMode {
PADDING,
MARGIN
}

View File

@ -0,0 +1,201 @@
package com.th3rdwave.safeareacontext;
import com.facebook.react.bridge.Dynamic;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.uimanager.LayoutShadowNode;
import com.facebook.react.uimanager.NativeViewHierarchyOptimizer;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.Spacing;
import com.facebook.react.uimanager.ViewProps;
import com.facebook.react.uimanager.annotations.ReactPropGroup;
import java.util.EnumSet;
import androidx.annotation.Nullable;
public class SafeAreaViewShadowNode extends LayoutShadowNode {
private @Nullable SafeAreaViewLocalData mLocalData;
private float[] mPaddings;
private float[] mMargins;
private boolean mNeedsUpdate = false;
public SafeAreaViewShadowNode() {
super();
mPaddings = new float[ViewProps.PADDING_MARGIN_SPACING_TYPES.length];
mMargins = new float[ViewProps.PADDING_MARGIN_SPACING_TYPES.length];
for (int i = 0; i < ViewProps.PADDING_MARGIN_SPACING_TYPES.length; i += 1) {
mPaddings[i] = Float.NaN;
mMargins[i] = Float.NaN;
}
}
private void updateInsets() {
if (mLocalData == null) {
return;
}
float top = 0;
float right = 0;
float bottom = 0;
float left = 0;
float[] meta = mLocalData.getMode() == SafeAreaViewMode.PADDING ? mPaddings : mMargins;
float allEdges = meta[Spacing.ALL];
if (!Float.isNaN(allEdges)) {
top = allEdges;
right = allEdges;
bottom = allEdges;
left = allEdges;
}
float verticalEdges = meta[Spacing.VERTICAL];
if (!Float.isNaN(verticalEdges)) {
top = verticalEdges;
bottom = verticalEdges;
}
float horizontalEdges = meta[Spacing.HORIZONTAL];
if (!Float.isNaN(horizontalEdges)) {
right = horizontalEdges;
left = horizontalEdges;
}
float topEdge = meta[Spacing.TOP];
if (!Float.isNaN(topEdge)) {
top = topEdge;
}
float rightEdge = meta[Spacing.RIGHT];
if (!Float.isNaN(rightEdge)) {
right = rightEdge;
}
float bottomEdge = meta[Spacing.BOTTOM];
if (!Float.isNaN(bottomEdge)) {
bottom = bottomEdge;
}
float leftEdge = meta[Spacing.LEFT];
if (!Float.isNaN(leftEdge)) {
left = leftEdge;
}
top = PixelUtil.toPixelFromDIP(top);
right = PixelUtil.toPixelFromDIP(right);
bottom = PixelUtil.toPixelFromDIP(bottom);
left = PixelUtil.toPixelFromDIP(left);
EnumSet<SafeAreaViewEdges> edges = mLocalData.getEdges();
EdgeInsets insets = mLocalData.getInsets();
float insetTop = edges.contains(SafeAreaViewEdges.TOP) ? insets.top : 0;
float insetRight = edges.contains(SafeAreaViewEdges.RIGHT) ? insets.right : 0;
float insetBottom = edges.contains(SafeAreaViewEdges.BOTTOM) ? insets.bottom : 0;
float insetLeft = edges.contains(SafeAreaViewEdges.LEFT) ? insets.left : 0;
if (mLocalData.getMode() == SafeAreaViewMode.PADDING) {
super.setPadding(Spacing.TOP, insetTop + top);
super.setPadding(Spacing.RIGHT, insetRight + right);
super.setPadding(Spacing.BOTTOM, insetBottom + bottom);
super.setPadding(Spacing.LEFT, insetLeft + left);
} else {
super.setMargin(Spacing.TOP, insetTop + top);
super.setMargin(Spacing.RIGHT, insetRight + right);
super.setMargin(Spacing.BOTTOM, insetBottom + bottom);
super.setMargin(Spacing.LEFT, insetLeft + left);
}
}
private void resetInsets(SafeAreaViewMode mode) {
if (mode == SafeAreaViewMode.PADDING) {
super.setPadding(Spacing.TOP, mPaddings[Spacing.TOP]);
super.setPadding(Spacing.RIGHT, mPaddings[Spacing.TOP]);
super.setPadding(Spacing.BOTTOM, mPaddings[Spacing.BOTTOM]);
super.setPadding(Spacing.LEFT, mPaddings[Spacing.LEFT]);
} else {
super.setMargin(Spacing.TOP, mMargins[Spacing.TOP]);
super.setMargin(Spacing.RIGHT, mMargins[Spacing.TOP]);
super.setMargin(Spacing.BOTTOM, mMargins[Spacing.BOTTOM]);
super.setMargin(Spacing.LEFT, mMargins[Spacing.LEFT]);
}
}
// The signature for onBeforeLayout is different in RN 0.59.
// Remove when we drop support for this version and add back @Override and super call to
// onBeforeLayout(NativeViewHierarchyOptimizer).
public void onBeforeLayout() {
if (mNeedsUpdate) {
mNeedsUpdate = false;
updateInsets();
}
}
public void onBeforeLayout(NativeViewHierarchyOptimizer nativeViewHierarchyOptimizer) {
if (mNeedsUpdate) {
mNeedsUpdate = false;
updateInsets();
}
}
@Override
public void setLocalData(Object data) {
if (!(data instanceof SafeAreaViewLocalData)) {
return;
}
SafeAreaViewLocalData localData = (SafeAreaViewLocalData) data;
if (mLocalData != null && mLocalData.getMode() != localData.getMode()) {
resetInsets(mLocalData.getMode());
}
mLocalData = localData;
mNeedsUpdate = false;
updateInsets();
}
// Names needs to reflect exact order in LayoutShadowNode.java
@Override
@ReactPropGroup(
names = {
ViewProps.PADDING,
ViewProps.PADDING_VERTICAL,
ViewProps.PADDING_HORIZONTAL,
ViewProps.PADDING_START,
ViewProps.PADDING_END,
ViewProps.PADDING_TOP,
ViewProps.PADDING_BOTTOM,
ViewProps.PADDING_LEFT,
ViewProps.PADDING_RIGHT,
})
public void setPaddings(int index, Dynamic padding) {
int spacingType = ViewProps.PADDING_MARGIN_SPACING_TYPES[index];
mPaddings[spacingType] = padding.getType() == ReadableType.Number ? (float) padding.asDouble() : Float.NaN;
super.setPaddings(index, padding);
mNeedsUpdate = true;
}
@Override
@ReactPropGroup(
names = {
ViewProps.MARGIN,
ViewProps.MARGIN_VERTICAL,
ViewProps.MARGIN_HORIZONTAL,
ViewProps.MARGIN_START,
ViewProps.MARGIN_END,
ViewProps.MARGIN_TOP,
ViewProps.MARGIN_BOTTOM,
ViewProps.MARGIN_LEFT,
ViewProps.MARGIN_RIGHT,
})
public void setMargins(int index, Dynamic margin) {
int spacingType = ViewProps.PADDING_MARGIN_SPACING_TYPES[index];
mMargins[spacingType] = margin.getType() == ReadableType.Number ? (float) margin.asDouble() : Float.NaN;
super.setMargins(index, margin);
mNeedsUpdate = true;
}
}

View File

@ -0,0 +1,52 @@
package com.th3rdwave.safeareacontext;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.PixelUtil;
import java.util.Map;
/* package */ class SerializationUtils {
static WritableMap edgeInsetsToJsMap(EdgeInsets insets) {
WritableMap insetsMap = Arguments.createMap();
insetsMap.putDouble("top", PixelUtil.toDIPFromPixel(insets.top));
insetsMap.putDouble("right", PixelUtil.toDIPFromPixel(insets.right));
insetsMap.putDouble("bottom", PixelUtil.toDIPFromPixel(insets.bottom));
insetsMap.putDouble("left", PixelUtil.toDIPFromPixel(insets.left));
return insetsMap;
}
static Map<String, Float> edgeInsetsToJavaMap(EdgeInsets insets) {
return MapBuilder.of(
"top",
PixelUtil.toDIPFromPixel(insets.top),
"right",
PixelUtil.toDIPFromPixel(insets.right),
"bottom",
PixelUtil.toDIPFromPixel(insets.bottom),
"left",
PixelUtil.toDIPFromPixel(insets.left));
}
static WritableMap rectToJsMap(Rect rect) {
WritableMap rectMap = Arguments.createMap();
rectMap.putDouble("x", PixelUtil.toDIPFromPixel(rect.x));
rectMap.putDouble("y", PixelUtil.toDIPFromPixel(rect.y));
rectMap.putDouble("width", PixelUtil.toDIPFromPixel(rect.width));
rectMap.putDouble("height", PixelUtil.toDIPFromPixel(rect.height));
return rectMap;
}
static Map<String, Float> rectToJavaMap(Rect rect) {
return MapBuilder.of(
"x",
PixelUtil.toDIPFromPixel(rect.x),
"y",
PixelUtil.toDIPFromPixel(rect.y),
"width",
PixelUtil.toDIPFromPixel(rect.width),
"height",
PixelUtil.toDIPFromPixel(rect.height));
}
}

View File

@ -0,0 +1,296 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
19AC186D23048EBB0093B581 /* RNCSafeAreaView.m in Sources */ = {isa = PBXBuildFile; fileRef = 19AC186C23048EBB0093B581 /* RNCSafeAreaView.m */; };
2EF2DACC23198DA400BBA425 /* RNCSafeAreaViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EF2DACB23198DA400BBA425 /* RNCSafeAreaViewManager.m */; };
C923EDBC220C2C1A00D3100F /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C923EDBB220C2C1A00D3100F /* SystemConfiguration.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
58B511D91A9E6C8500147676 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
134814201AA4EA6300B7C361 /* libRNCSafeAreaContext.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNCSafeAreaContext.a; sourceTree = BUILT_PRODUCTS_DIR; };
19AC186B23048EBB0093B581 /* RNCSafeAreaView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNCSafeAreaView.h; path = SafeAreaView/RNCSafeAreaView.h; sourceTree = "<group>"; };
19AC186C23048EBB0093B581 /* RNCSafeAreaView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNCSafeAreaView.m; path = SafeAreaView/RNCSafeAreaView.m; sourceTree = "<group>"; };
2EF2DACA23198DA300BBA425 /* RNCSafeAreaViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNCSafeAreaViewManager.h; path = SafeAreaView/RNCSafeAreaViewManager.h; sourceTree = "<group>"; };
2EF2DACB23198DA400BBA425 /* RNCSafeAreaViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNCSafeAreaViewManager.m; path = SafeAreaView/RNCSafeAreaViewManager.m; sourceTree = "<group>"; };
C923EDBB220C2C1A00D3100F /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
58B511D81A9E6C8500147676 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C923EDBC220C2C1A00D3100F /* SystemConfiguration.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
134814211AA4EA7D00B7C361 /* Products */ = {
isa = PBXGroup;
children = (
134814201AA4EA6300B7C361 /* libRNCSafeAreaContext.a */,
);
name = Products;
sourceTree = "<group>";
};
58B511D21A9E6C8500147676 = {
isa = PBXGroup;
children = (
2EF2DACA23198DA300BBA425 /* RNCSafeAreaViewManager.h */,
2EF2DACB23198DA400BBA425 /* RNCSafeAreaViewManager.m */,
19AC186B23048EBB0093B581 /* RNCSafeAreaView.h */,
19AC186C23048EBB0093B581 /* RNCSafeAreaView.m */,
134814211AA4EA7D00B7C361 /* Products */,
C923EDBA220C2C1A00D3100F /* Frameworks */,
);
sourceTree = "<group>";
};
C923EDBA220C2C1A00D3100F /* Frameworks */ = {
isa = PBXGroup;
children = (
C923EDBB220C2C1A00D3100F /* SystemConfiguration.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
58B511DA1A9E6C8500147676 /* RNCSafeAreaContext */ = {
isa = PBXNativeTarget;
buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNCSafeAreaContext" */;
buildPhases = (
58B511D71A9E6C8500147676 /* Sources */,
58B511D81A9E6C8500147676 /* Frameworks */,
58B511D91A9E6C8500147676 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = RNCSafeAreaContext;
productName = RCTDataManager;
productReference = 134814201AA4EA6300B7C361 /* libRNCSafeAreaContext.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
58B511D31A9E6C8500147676 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1030;
ORGANIZATIONNAME = Facebook;
TargetAttributes = {
58B511DA1A9E6C8500147676 = {
CreatedOnToolsVersion = 6.1.1;
};
};
};
buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "SafeAreaView" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 58B511D21A9E6C8500147676;
productRefGroup = 58B511D21A9E6C8500147676;
projectDirPath = "";
projectRoot = "";
targets = (
58B511DA1A9E6C8500147676 /* RNCSafeAreaContext */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
58B511D71A9E6C8500147676 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2EF2DACC23198DA400BBA425 /* RNCSafeAreaViewManager.m in Sources */,
19AC186D23048EBB0093B581 /* RNCSafeAreaView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
58B511ED1A9E6C8500147676 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
58B511EE1A9E6C8500147676 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
58B511F01A9E6C8500147676 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../../React/**",
"$(SRCROOT)/../../react-native/React/**",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RNCSafeAreaContext;
SKIP_INSTALL = YES;
};
name = Debug;
};
58B511F11A9E6C8500147676 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../../React/**",
"$(SRCROOT)/../../react-native/React/**",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RNCSafeAreaContext;
SKIP_INSTALL = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "SafeAreaView" */ = {
isa = XCConfigurationList;
buildConfigurations = (
58B511ED1A9E6C8500147676 /* Debug */,
58B511EE1A9E6C8500147676 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNCSafeAreaContext" */ = {
isa = XCConfigurationList;
buildConfigurations = (
58B511F01A9E6C8500147676 /* Debug */,
58B511F11A9E6C8500147676 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 58B511D31A9E6C8500147676 /* Project object */;
}

View File

@ -0,0 +1,16 @@
#import <UIKit/UIKit.h>
#import <React/RCTDefines.h>
#import <React/RCTView.h>
RCT_EXTERN BOOL UIEdgeInsetsEqualToEdgeInsetsWithThreshold(UIEdgeInsets insets1, UIEdgeInsets insets2, CGFloat threshold);
NS_ASSUME_NONNULL_BEGIN
@interface UIView(SafeAreaCompat)
- (BOOL)nativeSafeAreaSupport;
- (UIEdgeInsets)safeAreaInsetsOrEmulate;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,57 @@
#import "RCTView+SafeAreaCompat.h"
#import <React/RCTUIManager.h>
BOOL UIEdgeInsetsEqualToEdgeInsetsWithThreshold(UIEdgeInsets insets1, UIEdgeInsets insets2, CGFloat threshold)
{
return ABS(insets1.left - insets2.left) <= threshold &&
ABS(insets1.right - insets2.right) <= threshold &&
ABS(insets1.top - insets2.top) <= threshold &&
ABS(insets1.bottom - insets2.bottom) <= threshold;
}
@implementation UIView(SafeAreaCompat)
- (BOOL)nativeSafeAreaSupport
{
return [self respondsToSelector:@selector(safeAreaInsets)];
}
- (UIEdgeInsets)safeAreaInsetsOrEmulate
{
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
if (self.nativeSafeAreaSupport) {
if (@available(iOS 11.0, *)) {
return self.safeAreaInsets;
}
}
#endif
return self.emulatedSafeAreaInsets;
}
- (UIEdgeInsets)emulatedSafeAreaInsets
{
UIViewController* vc = self.reactViewController;
if (!vc) {
return UIEdgeInsetsZero;
}
CGFloat topLayoutOffset = vc.topLayoutGuide.length;
CGFloat bottomLayoutOffset = vc.bottomLayoutGuide.length;
CGRect safeArea = vc.view.bounds;
safeArea.origin.y += topLayoutOffset;
safeArea.size.height -= topLayoutOffset + bottomLayoutOffset;
CGRect localSafeArea = [vc.view convertRect:safeArea toView:self];
UIEdgeInsets safeAreaInsets = UIEdgeInsetsMake(0, 0, 0, 0);
if (CGRectGetMinY(localSafeArea) > CGRectGetMinY(self.bounds)) {
safeAreaInsets.top = CGRectGetMinY(localSafeArea) - CGRectGetMinY(self.bounds);
}
if (CGRectGetMaxY(localSafeArea) < CGRectGetMaxY(self.bounds)) {
safeAreaInsets.bottom = CGRectGetMaxY(self.bounds) - CGRectGetMaxY(localSafeArea);
}
return safeAreaInsets;
}
@end

View File

@ -0,0 +1,13 @@
#import <UIKit/UIKit.h>
#import <React/RCTView.h>
NS_ASSUME_NONNULL_BEGIN
@interface RNCSafeAreaProvider : RCTView
@property (nonatomic, copy) RCTBubblingEventBlock onInsetsChange;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,65 @@
#import "RNCSafeAreaProvider.h"
#import <React/RCTBridge.h>
#import <React/RCTUIManager.h>
#import "RCTView+SafeAreaCompat.h"
@implementation RNCSafeAreaProvider
{
UIEdgeInsets _currentSafeAreaInsets;
CGRect _currentFrame;
BOOL _initialInsetsSent;
}
- (void)safeAreaInsetsDidChange
{
[self invalidateSafeAreaInsets];
}
- (void)invalidateSafeAreaInsets
{
// This gets called before the view size is set by react-native so
// make sure to wait so we don't set wrong insets to JS.
if (CGSizeEqualToSize(self.frame.size, CGSizeZero)) {
return;
}
UIEdgeInsets safeAreaInsets = [self safeAreaInsetsOrEmulate];
CGRect frame = [self convertRect:self.bounds toView:nil];
if (
_initialInsetsSent &&
UIEdgeInsetsEqualToEdgeInsetsWithThreshold(safeAreaInsets, _currentSafeAreaInsets, 1.0 / RCTScreenScale()) &&
CGRectEqualToRect(frame, _currentFrame)
) {
return;
}
_initialInsetsSent = YES;
_currentSafeAreaInsets = safeAreaInsets;
_currentFrame = frame;
self.onInsetsChange(@{
@"insets": @{
@"top": @(safeAreaInsets.top),
@"right": @(safeAreaInsets.right),
@"bottom": @(safeAreaInsets.bottom),
@"left": @(safeAreaInsets.left),
},
@"frame": @{
@"x": @(frame.origin.x),
@"y": @(frame.origin.y),
@"width": @(frame.size.width),
@"height": @(frame.size.height),
},
});
}
- (void)layoutSubviews
{
[super layoutSubviews];
[self invalidateSafeAreaInsets];
}
@end

View File

@ -0,0 +1,9 @@
#import <React/RCTViewManager.h>
NS_ASSUME_NONNULL_BEGIN
@interface RNCSafeAreaProviderManager : RCTViewManager
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,47 @@
#import "RNCSafeAreaProviderManager.h"
#import "RNCSafeAreaProvider.h"
@implementation RNCSafeAreaProviderManager
RCT_EXPORT_MODULE(RNCSafeAreaProvider)
RCT_EXPORT_VIEW_PROPERTY(onInsetsChange, RCTDirectEventBlock)
+ (BOOL)requiresMainQueueSetup
{
return YES;
}
- (UIView *)view
{
return [RNCSafeAreaProvider new];
}
- (NSDictionary *)constantsToExport
{
if (@available(iOS 11.0, *)) {
UIWindow* window = [[UIApplication sharedApplication] keyWindow];
UIEdgeInsets safeAreaInsets = window.safeAreaInsets;
return @{
@"initialWindowMetrics": @{
@"insets": @{
@"top": @(safeAreaInsets.top),
@"right": @(safeAreaInsets.right),
@"bottom": @(safeAreaInsets.bottom),
@"left": @(safeAreaInsets.left),
},
@"frame": @{
@"x": @(window.frame.origin.x),
@"y": @(window.frame.origin.y),
@"width": @(window.frame.size.width),
@"height": @(window.frame.size.height),
},
}
};
} else {
return @{ @"initialWindowMetrics": [NSNull null] };
}
}
@end

View File

@ -0,0 +1,9 @@
#import <React/RCTShadowView.h>
NS_ASSUME_NONNULL_BEGIN
@interface RNCSafeAreaShadowView : RCTShadowView
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,180 @@
#import "RNCSafeAreaShadowView.h"
#import <React/RCTAssert.h>
#include <math.h>
#import "RNCSafeAreaViewLocalData.h"
#import "RNCSafeAreaViewMode.h"
#import "RNCSafeAreaViewEdges.h"
// From RCTShadowView.m
typedef NS_ENUM(unsigned int, meta_prop_t) {
META_PROP_LEFT,
META_PROP_TOP,
META_PROP_RIGHT,
META_PROP_BOTTOM,
META_PROP_HORIZONTAL,
META_PROP_VERTICAL,
META_PROP_ALL,
META_PROP_COUNT,
};
@implementation RNCSafeAreaShadowView {
RNCSafeAreaViewLocalData *_localData;
bool _needsUpdate;
YGValue _paddingMetaProps[META_PROP_COUNT];
YGValue _marginMetaProps[META_PROP_COUNT];
}
- (instancetype)init
{
self = [super init];
if (self) {
_needsUpdate = false;
for (unsigned int ii = 0; ii < META_PROP_COUNT; ii++) {
_paddingMetaProps[ii] = YGValueUndefined;
_marginMetaProps[ii] = YGValueUndefined;
}
}
return self;
}
- (void)extractEdges:(YGValue[])_metaProps top:(CGFloat *)top right:(CGFloat *)right bottom:(CGFloat *)bottom left:(CGFloat *)left
{
if (_metaProps[META_PROP_ALL].unit == YGUnitPoint) {
*top = _metaProps[META_PROP_ALL].value;
*right = _metaProps[META_PROP_ALL].value;
*bottom = _metaProps[META_PROP_ALL].value;
*left = _metaProps[META_PROP_ALL].value;
}
if (_metaProps[META_PROP_HORIZONTAL].unit == YGUnitPoint) {
*right = _metaProps[META_PROP_HORIZONTAL].value;
*left = _metaProps[META_PROP_HORIZONTAL].value;
}
if (_metaProps[META_PROP_VERTICAL].unit == YGUnitPoint) {
*top = _metaProps[META_PROP_VERTICAL].value;
*bottom = _metaProps[META_PROP_VERTICAL].value;
}
if (_metaProps[META_PROP_TOP].unit == YGUnitPoint) {
*top = _metaProps[META_PROP_TOP].value;
}
if (_metaProps[META_PROP_RIGHT].unit == YGUnitPoint) {
*right = _metaProps[META_PROP_RIGHT].value;
}
if (_metaProps[META_PROP_BOTTOM].unit == YGUnitPoint) {
*bottom = _metaProps[META_PROP_BOTTOM].value;
}
if (_metaProps[META_PROP_LEFT].unit == YGUnitPoint) {
*left = _metaProps[META_PROP_LEFT].value;
}
}
- (void)resetInsetsForMode:(RNCSafeAreaViewMode)mode {
if (mode == RNCSafeAreaViewModePadding) {
super.paddingTop = _paddingMetaProps[META_PROP_TOP];
super.paddingRight = _paddingMetaProps[META_PROP_RIGHT];
super.paddingBottom = _paddingMetaProps[META_PROP_BOTTOM];
super.paddingLeft = _paddingMetaProps[META_PROP_LEFT];
} else if (mode == RNCSafeAreaViewModeMargin) {
super.marginTop = _marginMetaProps[META_PROP_TOP];
super.marginRight = _marginMetaProps[META_PROP_RIGHT];
super.marginBottom = _marginMetaProps[META_PROP_BOTTOM];
super.marginLeft = _marginMetaProps[META_PROP_LEFT];
}
}
- (void)updateInsets
{
if (_localData == nil) {
return;
}
UIEdgeInsets insets = _localData.insets;
RNCSafeAreaViewMode mode = _localData.mode;
RNCSafeAreaViewEdges edges = _localData.edges;
CGFloat top = 0;
CGFloat right = 0;
CGFloat bottom = 0;
CGFloat left = 0;
CGFloat insetTop = (edges & RNCSafeAreaViewEdgesTop) ? insets.top : 0;
CGFloat insetRight = (edges & RNCSafeAreaViewEdgesRight) ? insets.right : 0;
CGFloat insetBottom = (edges & RNCSafeAreaViewEdgesBottom) ? insets.bottom : 0;
CGFloat insetLeft = (edges & RNCSafeAreaViewEdgesLeft) ? insets.left : 0;
if (mode == RNCSafeAreaViewModePadding) {
[self extractEdges:_paddingMetaProps top:&top right:&right bottom:&bottom left:&left];
super.paddingTop = (YGValue){insetTop + top, YGUnitPoint};
super.paddingRight = (YGValue){insetRight + right, YGUnitPoint};
super.paddingBottom = (YGValue){insetBottom + bottom, YGUnitPoint};
super.paddingLeft = (YGValue){insetLeft + left, YGUnitPoint};
} else if (mode == RNCSafeAreaViewModeMargin) {
[self extractEdges:_marginMetaProps top:&top right:&right bottom:&bottom left:&left];
super.marginTop = (YGValue){insetTop + top, YGUnitPoint};
super.marginRight = (YGValue){insetRight + right, YGUnitPoint};
super.marginBottom = (YGValue){insetBottom + bottom, YGUnitPoint};
super.marginLeft = (YGValue){insetLeft + left, YGUnitPoint};
}
}
- (void)didSetProps:(NSArray<NSString *> *)changedProps
{
if (_needsUpdate) {
_needsUpdate = false;
[self updateInsets];
}
[super didSetProps:changedProps];
}
- (void)setLocalData:(RNCSafeAreaViewLocalData *)localData
{
RCTAssert(
[localData isKindOfClass:[RNCSafeAreaViewLocalData class]],
@"Local data object for `RCTRNCSafeAreaShadowView` must be `RCTRNCSafeAreaViewLocalData` instance."
);
if (_localData != nil && _localData.mode != localData.mode) {
[self resetInsetsForMode:_localData.mode];
}
_localData = localData;
_needsUpdate = false;
[self updateInsets];
if (_localData.mode == RNCSafeAreaViewModePadding) {
[super didSetProps:@[@"paddingTop", @"paddingRight", @"paddingBottom", @"paddingLeft"]];
} else {
[super didSetProps:@[@"marginTop", @"marginRight", @"marginBottom", @"marginLeft"]];
}
}
#define SHADOW_VIEW_MARGIN_PADDING_PROP(edge, metaProp) \
- (void)setPadding##edge:(YGValue)value \
{ \
[super setPadding##edge:value]; \
_needsUpdate = true; \
_paddingMetaProps[META_PROP_##metaProp] = value; \
} \
- (void)setMargin##edge:(YGValue)value \
{ \
[super setMargin##edge:value]; \
_needsUpdate = true; \
_marginMetaProps[META_PROP_##metaProp] = value; \
}
SHADOW_VIEW_MARGIN_PADDING_PROP(, ALL);
SHADOW_VIEW_MARGIN_PADDING_PROP(Vertical, VERTICAL);
SHADOW_VIEW_MARGIN_PADDING_PROP(Horizontal, HORIZONTAL);
SHADOW_VIEW_MARGIN_PADDING_PROP(Top, TOP);
SHADOW_VIEW_MARGIN_PADDING_PROP(Right, RIGHT);
SHADOW_VIEW_MARGIN_PADDING_PROP(Bottom, BOTTOM);
SHADOW_VIEW_MARGIN_PADDING_PROP(Left, LEFT);
@end

View File

@ -0,0 +1,21 @@
#import <UIKit/UIKit.h>
#import <React/RCTView.h>
#import <React/RCTBridge.h>
#import "RNCSafeAreaViewMode.h"
#import "RNCSafeAreaViewEdges.h"
NS_ASSUME_NONNULL_BEGIN
@class RNCSafeAreaView;
@interface RNCSafeAreaView: RCTView
- (instancetype)initWithBridge:(RCTBridge *)bridge;
@property (nonatomic, assign) RNCSafeAreaViewMode mode;
@property (nonatomic, assign) RNCSafeAreaViewEdges edges;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,118 @@
#import "RNCSafeAreaView.h"
#import <React/RCTBridge.h>
#import <React/RCTUIManager.h>
#import "RNCSafeAreaViewLocalData.h"
#import "RNCSafeAreaViewMode.h"
#import "RNCSafeAreaViewEdges.h"
#import "RCTView+SafeAreaCompat.h"
#import "RNCSafeAreaProvider.h"
@implementation RNCSafeAreaView {
__weak RCTBridge *_bridge;
UIEdgeInsets _currentSafeAreaInsets;
RNCSafeAreaViewMode _mode;
RNCSafeAreaViewEdges _edges;
__weak UIView * _Nullable _providerView;
}
- (instancetype)initWithBridge:(RCTBridge *)bridge
{
if (self = [super initWithFrame:CGRectZero]) {
_bridge = bridge;
// Defaults
_mode = RNCSafeAreaViewModePadding;
_edges = RNCSafeAreaViewEdgesAll;
}
return self;
}
RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)decoder)
RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)
- (NSString *)description
{
NSString *superDescription = [super description];
// Cutting the last `>` character.
if (superDescription.length > 0 && [superDescription characterAtIndex:superDescription.length - 1] == '>') {
superDescription = [superDescription substringToIndex:superDescription.length - 1];
}
return [NSString stringWithFormat:@"%@; RNCSafeAreaInsets = %@; appliedRNCSafeAreaInsets = %@>",
superDescription,
NSStringFromUIEdgeInsets([_providerView safeAreaInsetsOrEmulate]),
NSStringFromUIEdgeInsets(_currentSafeAreaInsets)];
}
- (void)safeAreaInsetsDidChange
{
[super safeAreaInsetsDidChange];
[self invalidateSafeAreaInsets];
}
- (void)layoutSubviews
{
[super layoutSubviews];
if (!self.nativeSafeAreaSupport) {
[self invalidateSafeAreaInsets];
}
}
- (void)didMoveToWindow
{
_providerView = [self findNearestProvider];
[self invalidateSafeAreaInsets];
}
- (void)invalidateSafeAreaInsets
{
if (_providerView == nil) {
return;
}
UIEdgeInsets safeAreaInsets = [_providerView safeAreaInsetsOrEmulate];
if (UIEdgeInsetsEqualToEdgeInsetsWithThreshold(safeAreaInsets, _currentSafeAreaInsets, 1.0 / RCTScreenScale())) {
return;
}
_currentSafeAreaInsets = safeAreaInsets;
[self updateLocalData];
}
- (UIView *)findNearestProvider
{
UIView *current = self.reactSuperview;
while (current != nil) {
if ([current isKindOfClass:RNCSafeAreaProvider.class] ) {
return current;
}
current = current.reactSuperview;
}
return self;
}
- (void)updateLocalData
{
RNCSafeAreaViewLocalData *localData = [[RNCSafeAreaViewLocalData alloc] initWithInsets:_currentSafeAreaInsets
mode:_mode
edges:_edges];
[_bridge.uiManager setLocalData:localData forView:self];
}
- (void)setMode:(RNCSafeAreaViewMode)mode
{
_mode = mode;
[self updateLocalData];
}
- (void)setEdges:(RNCSafeAreaViewEdges)edges
{
_edges = edges;
[self updateLocalData];
}
@end

View File

@ -0,0 +1,9 @@
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, RNCSafeAreaViewEdges) {
RNCSafeAreaViewEdgesTop = 0b1000,
RNCSafeAreaViewEdgesRight = 0b0100,
RNCSafeAreaViewEdgesBottom = 0b0010,
RNCSafeAreaViewEdgesLeft = 0b0001,
RNCSafeAreaViewEdgesAll = 0b1111,
};

View File

@ -0,0 +1,13 @@
#import <React/RCTConvert.h>
#import "RNCSafeAreaViewEdges.h"
@implementation RCTConvert (RNCSafeAreaView)
RCT_MULTI_ENUM_CONVERTER(RNCSafeAreaViewEdges, (@{
@"top": @(RNCSafeAreaViewEdgesTop),
@"right": @(RNCSafeAreaViewEdgesRight),
@"bottom": @(RNCSafeAreaViewEdgesBottom),
@"left": @(RNCSafeAreaViewEdgesLeft),
}), RNCSafeAreaViewEdgesAll, integerValue);
@end

View File

@ -0,0 +1,18 @@
#import <UIKit/UIKit.h>
#import "RNCSafeAreaViewMode.h"
#import "RNCSafeAreaViewEdges.h"
NS_ASSUME_NONNULL_BEGIN
@interface RNCSafeAreaViewLocalData : NSObject
- (instancetype)initWithInsets:(UIEdgeInsets)insets mode:(RNCSafeAreaViewMode)mode edges:(RNCSafeAreaViewEdges)edges;
@property (atomic, readonly) UIEdgeInsets insets;
@property (atomic, readonly) RNCSafeAreaViewMode mode;
@property (atomic, readonly) RNCSafeAreaViewEdges edges;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,16 @@
#import "RNCSafeAreaViewLocalData.h"
@implementation RNCSafeAreaViewLocalData
- (instancetype)initWithInsets:(UIEdgeInsets)insets mode:(RNCSafeAreaViewMode)mode edges:(RNCSafeAreaViewEdges)edges
{
if (self = [super init]) {
_insets = insets;
_mode = mode;
_edges = edges;
}
return self;
}
@end

View File

@ -0,0 +1,9 @@
#import <React/RCTViewManager.h>
NS_ASSUME_NONNULL_BEGIN
@interface RNCSafeAreaViewManager : RCTViewManager
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,25 @@
#import "RNCSafeAreaViewManager.h"
#import "RNCSafeAreaShadowView.h"
#import "RNCSafeAreaView.h"
#import "RNCSafeAreaViewMode.h"
#import "RNCSafeAreaViewEdges.h"
@implementation RNCSafeAreaViewManager
RCT_EXPORT_MODULE(RNCSafeAreaView)
- (UIView *)view
{
return [[RNCSafeAreaView alloc] initWithBridge:self.bridge];
}
- (RNCSafeAreaShadowView *)shadowView
{
return [RNCSafeAreaShadowView new];
}
RCT_EXPORT_VIEW_PROPERTY(mode, RNCSafeAreaViewMode)
RCT_EXPORT_VIEW_PROPERTY(edges, RNCSafeAreaViewEdges)
@end

View File

@ -0,0 +1,7 @@
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, RNCSafeAreaViewMode) {
RNCSafeAreaViewModePadding,
RNCSafeAreaViewModeMargin,
RNCSafeAreaViewModeBorder,
};

View File

@ -0,0 +1,11 @@
#import <React/RCTConvert.h>
#import "RNCSafeAreaViewMode.h"
@implementation RCTConvert (RNCSafeAreaView)
RCT_MULTI_ENUM_CONVERTER(RNCSafeAreaViewMode, (@{
@"padding": @(RNCSafeAreaViewModePadding),
@"margin": @(RNCSafeAreaViewModeMargin),
}), RNCSafeAreaViewModePadding, integerValue);
@end

View File

@ -0,0 +1,51 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.CompatNativeSafeAreaProvider = CompatNativeSafeAreaProvider;
var React = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
var _useWindowDimensions = _interopRequireDefault(require("./useWindowDimensions"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function CompatNativeSafeAreaProvider({
children,
style,
onInsetsChange
}) {
const window = (0, _useWindowDimensions.default)();
React.useEffect(() => {
const insets = {
top: 0,
bottom: 0,
left: 0,
right: 0
};
const frame = {
x: 0,
y: 0,
width: window.width,
height: window.height
}; // @ts-ignore: missing properties
onInsetsChange({
nativeEvent: {
insets,
frame
}
});
}, [onInsetsChange, window.height, window.width]);
return /*#__PURE__*/React.createElement(_reactNative.View, {
style: style
}, children);
}
//# sourceMappingURL=CompatNativeSafeAreaProvider.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["CompatNativeSafeAreaProvider.tsx"],"names":["CompatNativeSafeAreaProvider","children","style","onInsetsChange","window","React","useEffect","insets","top","bottom","left","right","frame","x","y","width","height","nativeEvent"],"mappings":";;;;;;;AAAA;;AACA;;AAEA;;;;;;;;AAEO,SAASA,4BAAT,CAAsC;AAC3CC,EAAAA,QAD2C;AAE3CC,EAAAA,KAF2C;AAG3CC,EAAAA;AAH2C,CAAtC,EAIyB;AAC9B,QAAMC,MAAM,GAAG,mCAAf;AACAC,EAAAA,KAAK,CAACC,SAAN,CAAgB,MAAM;AACpB,UAAMC,MAAM,GAAG;AACbC,MAAAA,GAAG,EAAE,CADQ;AAEbC,MAAAA,MAAM,EAAE,CAFK;AAGbC,MAAAA,IAAI,EAAE,CAHO;AAIbC,MAAAA,KAAK,EAAE;AAJM,KAAf;AAMA,UAAMC,KAAK,GAAG;AACZC,MAAAA,CAAC,EAAE,CADS;AAEZC,MAAAA,CAAC,EAAE,CAFS;AAGZC,MAAAA,KAAK,EAAEX,MAAM,CAACW,KAHF;AAIZC,MAAAA,MAAM,EAAEZ,MAAM,CAACY;AAJH,KAAd,CAPoB,CAapB;;AACAb,IAAAA,cAAc,CAAC;AAAEc,MAAAA,WAAW,EAAE;AAAEV,QAAAA,MAAF;AAAUK,QAAAA;AAAV;AAAf,KAAD,CAAd;AACD,GAfD,EAeG,CAACT,cAAD,EAAiBC,MAAM,CAACY,MAAxB,EAAgCZ,MAAM,CAACW,KAAvC,CAfH;AAgBA,sBAAO,oBAAC,iBAAD;AAAM,IAAA,KAAK,EAAEb;AAAb,KAAqBD,QAArB,CAAP;AACD","sourcesContent":["import * as React from 'react';\nimport { View } from 'react-native';\nimport { NativeSafeAreaProviderProps } from './SafeArea.types';\nimport useWindowDimensions from './useWindowDimensions';\n\nexport function CompatNativeSafeAreaProvider({\n children,\n style,\n onInsetsChange,\n}: NativeSafeAreaProviderProps) {\n const window = useWindowDimensions();\n React.useEffect(() => {\n const insets = {\n top: 0,\n bottom: 0,\n left: 0,\n right: 0,\n };\n const frame = {\n x: 0,\n y: 0,\n width: window.width,\n height: window.height,\n };\n // @ts-ignore: missing properties\n onInsetsChange({ nativeEvent: { insets, frame } });\n }, [onInsetsChange, window.height, window.width]);\n return <View style={style}>{children}</View>;\n}\n"]}

View File

@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.initialWindowSafeAreaInsets = exports.initialWindowMetrics = void 0;
const initialWindowMetrics = null;
/**
* @deprecated
*/
exports.initialWindowMetrics = initialWindowMetrics;
const initialWindowSafeAreaInsets = null;
exports.initialWindowSafeAreaInsets = initialWindowSafeAreaInsets;
//# sourceMappingURL=InitialWindow.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["InitialWindow.ts"],"names":["initialWindowMetrics","initialWindowSafeAreaInsets"],"mappings":";;;;;;AAEO,MAAMA,oBAAoC,GAAG,IAA7C;AAEP;;;;;AAGO,MAAMC,2BAA8C,GAAG,IAAvD","sourcesContent":["import { EdgeInsets, Metrics } from './SafeArea.types';\n\nexport const initialWindowMetrics: Metrics | null = null;\n\n/**\n * @deprecated\n */\nexport const initialWindowSafeAreaInsets: EdgeInsets | null = null;\n"]}

View File

@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.initialWindowSafeAreaInsets = exports.initialWindowMetrics = void 0;
var _reactNative = require("react-native");
const RNCSafeAreaProviderConfig = _reactNative.UIManager.getViewManagerConfig('RNCSafeAreaProvider');
const initialWindowMetrics = RNCSafeAreaProviderConfig != null && RNCSafeAreaProviderConfig.Constants != null ? RNCSafeAreaProviderConfig.Constants.initialWindowMetrics : null;
/**
* @deprecated
*/
exports.initialWindowMetrics = initialWindowMetrics;
const initialWindowSafeAreaInsets = initialWindowMetrics === null || initialWindowMetrics === void 0 ? void 0 : initialWindowMetrics.insets;
exports.initialWindowSafeAreaInsets = initialWindowSafeAreaInsets;
//# sourceMappingURL=InitialWindow.native.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["InitialWindow.native.ts"],"names":["RNCSafeAreaProviderConfig","UIManager","getViewManagerConfig","initialWindowMetrics","Constants","initialWindowSafeAreaInsets","insets"],"mappings":";;;;;;;AAAA;;AAGA,MAAMA,yBAAyB,GAAGC,uBAAUC,oBAAV,CAChC,qBADgC,CAAlC;;AAIO,MAAMC,oBAAoB,GAAIH,yBAAyB,IAAI,IAA7B,IACrCA,yBAAyB,CAACI,SAA1B,IAAuC,IADF,GAEjCJ,yBAAyB,CAACI,SAA1B,CAAoCD,oBAFH,GAGjC,IAHG;AAKP;;;;;AAGO,MAAME,2BAA2B,GAAGF,oBAAH,aAAGA,oBAAH,uBAAGA,oBAAoB,CAAEG,MAA1D","sourcesContent":["import { UIManager } from 'react-native';\nimport { Metrics } from './SafeArea.types';\n\nconst RNCSafeAreaProviderConfig = UIManager.getViewManagerConfig(\n 'RNCSafeAreaProvider',\n) as any;\n\nexport const initialWindowMetrics = (RNCSafeAreaProviderConfig != null &&\nRNCSafeAreaProviderConfig.Constants != null\n ? RNCSafeAreaProviderConfig.Constants.initialWindowMetrics\n : null) as Metrics | null;\n\n/**\n * @deprecated\n */\nexport const initialWindowSafeAreaInsets = initialWindowMetrics?.insets;\n"]}

View File

@ -0,0 +1,152 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = NativeSafeAreaView;
var React = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
/**
* TODO:
* Currently insets and frame are based on the window and are not
* relative to the provider view. This is inconsistent with iOS and Android.
* However in most cases if the provider view covers the screen this is not
* an issue.
*/
const CSSTransitions = {
WebkitTransition: 'webkitTransitionEnd',
Transition: 'transitionEnd',
MozTransition: 'transitionend',
MSTransition: 'msTransitionEnd',
OTransition: 'oTransitionEnd'
};
function NativeSafeAreaView({
children,
style,
onInsetsChange
}) {
React.useEffect(() => {
// Skip for SSR.
if (typeof document === 'undefined') {
return;
}
const element = createContextElement();
document.body.appendChild(element);
const onEnd = () => {
const {
paddingTop,
paddingBottom,
paddingLeft,
paddingRight
} = window.getComputedStyle(element);
const insets = {
top: paddingTop ? parseInt(paddingTop, 10) : 0,
bottom: paddingBottom ? parseInt(paddingBottom, 10) : 0,
left: paddingLeft ? parseInt(paddingLeft, 10) : 0,
right: paddingRight ? parseInt(paddingRight, 10) : 0
};
const frame = {
x: 0,
y: 0,
width: document.documentElement.offsetWidth,
height: document.documentElement.offsetHeight
}; // @ts-ignore: missing properties
onInsetsChange({
nativeEvent: {
insets,
frame
}
});
};
element.addEventListener(getSupportedTransitionEvent(), onEnd);
onEnd();
return () => {
document.body.removeChild(element);
element.removeEventListener(getSupportedTransitionEvent(), onEnd);
};
}, [onInsetsChange]);
return /*#__PURE__*/React.createElement(_reactNative.View, {
style: style
}, children);
}
let _supportedTransitionEvent = null;
function getSupportedTransitionEvent() {
if (_supportedTransitionEvent !== null) {
return _supportedTransitionEvent;
}
const element = document.createElement('invalidtype');
_supportedTransitionEvent = CSSTransitions.Transition;
for (const key in CSSTransitions) {
if (element.style[key] !== undefined) {
_supportedTransitionEvent = CSSTransitions[key];
break;
}
}
return _supportedTransitionEvent;
}
let _supportedEnv = null;
function getSupportedEnv() {
if (_supportedEnv !== null) {
return _supportedEnv;
}
const {
CSS
} = window;
if (CSS && CSS.supports && CSS.supports('top: constant(safe-area-inset-top)')) {
_supportedEnv = 'constant';
} else {
_supportedEnv = 'env';
}
return _supportedEnv;
}
function getInset(side) {
return "".concat(getSupportedEnv(), "(safe-area-inset-").concat(side, ")");
}
function createContextElement() {
const element = document.createElement('div');
const {
style
} = element;
style.position = 'fixed';
style.left = '0';
style.top = '0';
style.width = '0';
style.height = '0';
style.zIndex = '-1';
style.overflow = 'hidden';
style.visibility = 'hidden'; // Bacon: Anything faster than this and the callback will be invoked too early with the wrong insets
style.transitionDuration = '0.05s';
style.transitionProperty = 'padding';
style.transitionDelay = '0s';
style.paddingTop = getInset('top');
style.paddingBottom = getInset('bottom');
style.paddingLeft = getInset('left');
style.paddingRight = getInset('right');
return element;
}
//# sourceMappingURL=NativeSafeAreaProvider.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _CompatNativeSafeAreaProvider = require("./CompatNativeSafeAreaProvider");
var _default = _CompatNativeSafeAreaProvider.CompatNativeSafeAreaProvider;
exports.default = _default;
//# sourceMappingURL=NativeSafeAreaProvider.macos.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["NativeSafeAreaProvider.macos.tsx"],"names":["CompatNativeSafeAreaProvider"],"mappings":";;;;;;;AAAA;;eAEeA,0D","sourcesContent":["import { CompatNativeSafeAreaProvider } from './CompatNativeSafeAreaProvider';\n\nexport default CompatNativeSafeAreaProvider;\n"]}

View File

@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _reactNative = require("react-native");
var _default = (0, _reactNative.requireNativeComponent)('RNCSafeAreaProvider');
exports.default = _default;
//# sourceMappingURL=NativeSafeAreaProvider.native.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["NativeSafeAreaProvider.native.tsx"],"names":[],"mappings":";;;;;;;AAAA;;eAGe,yCACb,qBADa,C","sourcesContent":["import { requireNativeComponent } from 'react-native';\nimport { NativeSafeAreaProviderProps } from './SafeArea.types';\n\nexport default requireNativeComponent<NativeSafeAreaProviderProps>(\n 'RNCSafeAreaProvider',\n);\n"]}

View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _CompatNativeSafeAreaProvider = require("./CompatNativeSafeAreaProvider");
var _default = _CompatNativeSafeAreaProvider.CompatNativeSafeAreaProvider;
exports.default = _default;
//# sourceMappingURL=NativeSafeAreaProvider.windows.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["NativeSafeAreaProvider.windows.tsx"],"names":["CompatNativeSafeAreaProvider"],"mappings":";;;;;;;AAAA;;eAEeA,0D","sourcesContent":["import { CompatNativeSafeAreaProvider } from './CompatNativeSafeAreaProvider';\n\nexport default CompatNativeSafeAreaProvider;\n"]}

View File

@ -0,0 +1,2 @@
"use strict";
//# sourceMappingURL=SafeArea.types.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":[],"names":[],"mappings":"","sourcesContent":[]}

View File

@ -0,0 +1,138 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SafeAreaProvider = SafeAreaProvider;
exports.useSafeAreaInsets = useSafeAreaInsets;
exports.useSafeAreaFrame = useSafeAreaFrame;
exports.withSafeAreaInsets = withSafeAreaInsets;
exports.useSafeArea = useSafeArea;
exports.SafeAreaContext = exports.SafeAreaConsumer = exports.SafeAreaFrameContext = exports.SafeAreaInsetsContext = void 0;
var React = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
var _NativeSafeAreaProvider = _interopRequireDefault(require("./NativeSafeAreaProvider"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
const SafeAreaInsetsContext = React.createContext(null);
exports.SafeAreaInsetsContext = SafeAreaInsetsContext;
const SafeAreaFrameContext = React.createContext(null);
exports.SafeAreaFrameContext = SafeAreaFrameContext;
function SafeAreaProvider({
children,
initialMetrics,
initialSafeAreaInsets,
style
}) {
var _ref, _ref2, _initialMetrics$inset, _ref3, _initialMetrics$frame;
const parentInsets = useParentSafeAreaInsets();
const parentFrame = useParentSafeAreaFrame();
const [insets, setInsets] = React.useState((_ref = (_ref2 = (_initialMetrics$inset = initialMetrics === null || initialMetrics === void 0 ? void 0 : initialMetrics.insets) !== null && _initialMetrics$inset !== void 0 ? _initialMetrics$inset : initialSafeAreaInsets) !== null && _ref2 !== void 0 ? _ref2 : parentInsets) !== null && _ref !== void 0 ? _ref : null);
const [frame, setFrame] = React.useState((_ref3 = (_initialMetrics$frame = initialMetrics === null || initialMetrics === void 0 ? void 0 : initialMetrics.frame) !== null && _initialMetrics$frame !== void 0 ? _initialMetrics$frame : parentFrame) !== null && _ref3 !== void 0 ? _ref3 : {
// Backwards compat so we render anyway if we don't have frame.
x: 0,
y: 0,
width: _reactNative.Dimensions.get('window').width,
height: _reactNative.Dimensions.get('window').height
});
const onInsetsChange = React.useCallback(event => {
const {
nativeEvent: {
frame: nextFrame,
insets: nextInsets
}
} = event;
if ( // Backwards compat with old native code that won't send frame.
nextFrame && (nextFrame.height !== frame.height || nextFrame.width !== frame.width || nextFrame.x !== frame.x || nextFrame.y !== frame.y)) {
setFrame(nextFrame);
}
if (!insets || nextInsets.bottom !== insets.bottom || nextInsets.left !== insets.left || nextInsets.right !== insets.right || nextInsets.top !== insets.top) {
setInsets(nextInsets);
}
}, [frame, insets]);
return /*#__PURE__*/React.createElement(_NativeSafeAreaProvider.default, {
style: [styles.fill, style],
onInsetsChange: onInsetsChange
}, insets != null ? /*#__PURE__*/React.createElement(SafeAreaFrameContext.Provider, {
value: frame
}, /*#__PURE__*/React.createElement(SafeAreaInsetsContext.Provider, {
value: insets
}, children)) : null);
}
const styles = _reactNative.StyleSheet.create({
fill: {
flex: 1
}
});
function useParentSafeAreaInsets() {
return React.useContext(SafeAreaInsetsContext);
}
function useParentSafeAreaFrame() {
return React.useContext(SafeAreaFrameContext);
}
function useSafeAreaInsets() {
const safeArea = React.useContext(SafeAreaInsetsContext);
if (safeArea == null) {
throw new Error('No safe area insets value available. Make sure you are rendering `<SafeAreaProvider>` at the top of your app.');
}
return safeArea;
}
function useSafeAreaFrame() {
const frame = React.useContext(SafeAreaFrameContext);
if (frame == null) {
throw new Error('No safe area frame value available. Make sure you are rendering `<SafeAreaProvider>` at the top of your app.');
}
return frame;
}
function withSafeAreaInsets(WrappedComponent) {
return /*#__PURE__*/React.forwardRef((props, ref) => /*#__PURE__*/React.createElement(SafeAreaConsumer, null, insets => /*#__PURE__*/React.createElement(WrappedComponent, _extends({}, props, {
insets: insets,
ref: ref
}))));
}
/**
* @deprecated
*/
function useSafeArea() {
return useSafeAreaInsets();
}
/**
* @deprecated
*/
const SafeAreaConsumer = SafeAreaInsetsContext.Consumer;
/**
* @deprecated
*/
exports.SafeAreaConsumer = SafeAreaConsumer;
const SafeAreaContext = SafeAreaInsetsContext;
exports.SafeAreaContext = SafeAreaContext;
//# sourceMappingURL=SafeAreaContext.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,97 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SafeAreaView = SafeAreaView;
var React = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
var _SafeAreaContext = require("./SafeAreaContext");
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
// prettier-ignore
const TOP = 0b1000,
RIGHT = 0b0100,
BOTTOM = 0b0010,
LEFT = 0b0001,
ALL = 0b1111;
/* eslint-disable no-bitwise */
const edgeBitmaskMap = {
top: TOP,
right: RIGHT,
bottom: BOTTOM,
left: LEFT
};
function SafeAreaView(_ref) {
let {
style = {},
mode,
edges
} = _ref,
rest = _objectWithoutProperties(_ref, ["style", "mode", "edges"]);
const insets = (0, _SafeAreaContext.useSafeAreaInsets)();
const edgeBitmask = edges != null ? edges.reduce((accum, edge) => accum | edgeBitmaskMap[edge], 0) : ALL;
const appliedStyle = React.useMemo(() => {
const insetTop = edgeBitmask & TOP ? insets.top : 0;
const insetRight = edgeBitmask & RIGHT ? insets.right : 0;
const insetBottom = edgeBitmask & BOTTOM ? insets.bottom : 0;
const insetLeft = edgeBitmask & LEFT ? insets.left : 0;
const flatStyle = _reactNative.StyleSheet.flatten(style);
if (mode === 'margin') {
const {
margin = 0,
marginVertical = margin,
marginHorizontal = margin,
marginTop = marginVertical,
marginRight = marginHorizontal,
marginBottom = marginVertical,
marginLeft = marginHorizontal
} = flatStyle;
const marginStyle = {
marginTop: marginTop + insetTop,
marginRight: marginRight + insetRight,
marginBottom: marginBottom + insetBottom,
marginLeft: marginLeft + insetLeft
};
return [style, marginStyle];
} else {
const {
padding = 0,
paddingVertical = padding,
paddingHorizontal = padding,
paddingTop = paddingVertical,
paddingRight = paddingHorizontal,
paddingBottom = paddingVertical,
paddingLeft = paddingHorizontal
} = flatStyle;
const paddingStyle = {
paddingTop: paddingTop + insetTop,
paddingRight: paddingRight + insetRight,
paddingBottom: paddingBottom + insetBottom,
paddingLeft: paddingLeft + insetLeft
};
return [style, paddingStyle];
}
}, [style, insets, mode, edgeBitmask]);
return /*#__PURE__*/React.createElement(_reactNative.View, _extends({
style: appliedStyle
}, rest));
}
//# sourceMappingURL=SafeAreaView.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SafeAreaView = void 0;
var _reactNative = require("react-native");
const SafeAreaView = _reactNative.View;
exports.SafeAreaView = SafeAreaView;
//# sourceMappingURL=SafeAreaView.macos.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["SafeAreaView.macos.tsx"],"names":["SafeAreaView","View"],"mappings":";;;;;;;AAAA;;AAEO,MAAMA,YAAY,GAAGC,iBAArB","sourcesContent":["import { View } from 'react-native';\n\nexport const SafeAreaView = View;\n"]}

View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SafeAreaView = void 0;
var _reactNative = require("react-native");
const SafeAreaView = (0, _reactNative.requireNativeComponent)('RNCSafeAreaView');
exports.SafeAreaView = SafeAreaView;
//# sourceMappingURL=SafeAreaView.native.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["SafeAreaView.native.tsx"],"names":["SafeAreaView"],"mappings":";;;;;;;AAAA;;AAGO,MAAMA,YAAY,GAAG,yCAC1B,iBAD0B,CAArB","sourcesContent":["import { requireNativeComponent } from 'react-native';\nimport { NativeSafeAreaViewProps } from './SafeArea.types';\n\nexport const SafeAreaView = requireNativeComponent<NativeSafeAreaViewProps>(\n 'RNCSafeAreaView',\n);\n"]}

View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SafeAreaView = void 0;
var _reactNative = require("react-native");
const SafeAreaView = _reactNative.View;
exports.SafeAreaView = SafeAreaView;
//# sourceMappingURL=SafeAreaView.windows.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["SafeAreaView.windows.tsx"],"names":["SafeAreaView","View"],"mappings":";;;;;;;AAAA;;AAEO,MAAMA,YAAY,GAAGC,iBAArB","sourcesContent":["import { View } from 'react-native';\n\nexport const SafeAreaView = View;\n"]}

View File

@ -0,0 +1,54 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _SafeAreaContext = require("./SafeAreaContext");
Object.keys(_SafeAreaContext).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function get() {
return _SafeAreaContext[key];
}
});
});
var _SafeAreaView = require("./SafeAreaView");
Object.keys(_SafeAreaView).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function get() {
return _SafeAreaView[key];
}
});
});
var _InitialWindow = require("./InitialWindow");
Object.keys(_InitialWindow).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function get() {
return _InitialWindow[key];
}
});
});
var _SafeArea = require("./SafeArea.types");
Object.keys(_SafeArea).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function get() {
return _SafeArea[key];
}
});
});
//# sourceMappingURL=index.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["index.tsx"],"names":[],"mappings":";;;;;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AACA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AACA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AACA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA","sourcesContent":["export * from './SafeAreaContext';\nexport * from './SafeAreaView';\nexport * from './InitialWindow';\nexport * from './SafeArea.types';\n"]}

View File

@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = useWindowDimensions;
var _reactNative = require("react-native");
var _react = require("react");
// Copied from https://github.com/facebook/react-native/blob/8d57691a/Libraries/Utilities/useWindowDimensions.js
// for compatibility with React Native < 0.61.
function useWindowDimensions() {
const [dimensions, setDimensions] = (0, _react.useState)(() => _reactNative.Dimensions.get('window'));
(0, _react.useEffect)(() => {
function handleChange({
window
}) {
if (dimensions.width !== window.width || dimensions.height !== window.height || dimensions.scale !== window.scale || dimensions.fontScale !== window.fontScale) {
setDimensions(window);
}
}
_reactNative.Dimensions.addEventListener('change', handleChange); // We might have missed an update between calling `get` in render and
// `addEventListener` in this handler, so we set it here. If there was
// no change, React will filter out this update as a no-op.
handleChange({
window: _reactNative.Dimensions.get('window')
});
return () => {
_reactNative.Dimensions.removeEventListener('change', handleChange);
};
}, [dimensions]);
return dimensions;
}
//# sourceMappingURL=useWindowDimensions.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["useWindowDimensions.tsx"],"names":["useWindowDimensions","dimensions","setDimensions","Dimensions","get","handleChange","window","width","height","scale","fontScale","addEventListener","removeEventListener"],"mappings":";;;;;;;AAAA;;AACA;;AASA;AACA;AACe,SAASA,mBAAT,GAA+C;AAC5D,QAAM,CAACC,UAAD,EAAaC,aAAb,IAA8B,qBAAS,MAAMC,wBAAWC,GAAX,CAAe,QAAf,CAAf,CAApC;AACA,wBAAU,MAAM;AACd,aAASC,YAAT,CAAsB;AAAEC,MAAAA;AAAF,KAAtB,EAA8D;AAC5D,UACEL,UAAU,CAACM,KAAX,KAAqBD,MAAM,CAACC,KAA5B,IACAN,UAAU,CAACO,MAAX,KAAsBF,MAAM,CAACE,MAD7B,IAEAP,UAAU,CAACQ,KAAX,KAAqBH,MAAM,CAACG,KAF5B,IAGAR,UAAU,CAACS,SAAX,KAAyBJ,MAAM,CAACI,SAJlC,EAKE;AACAR,QAAAA,aAAa,CAACI,MAAD,CAAb;AACD;AACF;;AACDH,4BAAWQ,gBAAX,CAA4B,QAA5B,EAAsCN,YAAtC,EAXc,CAYd;AACA;AACA;;;AACAA,IAAAA,YAAY,CAAC;AAAEC,MAAAA,MAAM,EAAEH,wBAAWC,GAAX,CAAe,QAAf;AAAV,KAAD,CAAZ;AACA,WAAO,MAAM;AACXD,8BAAWS,mBAAX,CAA+B,QAA/B,EAAyCP,YAAzC;AACD,KAFD;AAGD,GAnBD,EAmBG,CAACJ,UAAD,CAnBH;AAoBA,SAAOA,UAAP;AACD","sourcesContent":["import { Dimensions } from 'react-native';\nimport { useEffect, useState } from 'react';\n\ntype DisplayMetrics = {\n width: number;\n height: number;\n scale: number;\n fontScale: number;\n};\n\n// Copied from https://github.com/facebook/react-native/blob/8d57691a/Libraries/Utilities/useWindowDimensions.js\n// for compatibility with React Native < 0.61.\nexport default function useWindowDimensions(): DisplayMetrics {\n const [dimensions, setDimensions] = useState(() => Dimensions.get('window'));\n useEffect(() => {\n function handleChange({ window }: { window: DisplayMetrics }) {\n if (\n dimensions.width !== window.width ||\n dimensions.height !== window.height ||\n dimensions.scale !== window.scale ||\n dimensions.fontScale !== window.fontScale\n ) {\n setDimensions(window);\n }\n }\n Dimensions.addEventListener('change', handleChange);\n // We might have missed an update between calling `get` in render and\n // `addEventListener` in this handler, so we set it here. If there was\n // no change, React will filter out this update as a no-op.\n handleChange({ window: Dimensions.get('window') });\n return () => {\n Dimensions.removeEventListener('change', handleChange);\n };\n }, [dimensions]);\n return dimensions;\n}\n"]}

View File

@ -0,0 +1,35 @@
import * as React from 'react';
import { View } from 'react-native';
import useWindowDimensions from './useWindowDimensions';
export function CompatNativeSafeAreaProvider({
children,
style,
onInsetsChange
}) {
const window = useWindowDimensions();
React.useEffect(() => {
const insets = {
top: 0,
bottom: 0,
left: 0,
right: 0
};
const frame = {
x: 0,
y: 0,
width: window.width,
height: window.height
}; // @ts-ignore: missing properties
onInsetsChange({
nativeEvent: {
insets,
frame
}
});
}, [onInsetsChange, window.height, window.width]);
return /*#__PURE__*/React.createElement(View, {
style: style
}, children);
}
//# sourceMappingURL=CompatNativeSafeAreaProvider.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["CompatNativeSafeAreaProvider.tsx"],"names":["React","View","useWindowDimensions","CompatNativeSafeAreaProvider","children","style","onInsetsChange","window","useEffect","insets","top","bottom","left","right","frame","x","y","width","height","nativeEvent"],"mappings":"AAAA,OAAO,KAAKA,KAAZ,MAAuB,OAAvB;AACA,SAASC,IAAT,QAAqB,cAArB;AAEA,OAAOC,mBAAP,MAAgC,uBAAhC;AAEA,OAAO,SAASC,4BAAT,CAAsC;AAC3CC,EAAAA,QAD2C;AAE3CC,EAAAA,KAF2C;AAG3CC,EAAAA;AAH2C,CAAtC,EAIyB;AAC9B,QAAMC,MAAM,GAAGL,mBAAmB,EAAlC;AACAF,EAAAA,KAAK,CAACQ,SAAN,CAAgB,MAAM;AACpB,UAAMC,MAAM,GAAG;AACbC,MAAAA,GAAG,EAAE,CADQ;AAEbC,MAAAA,MAAM,EAAE,CAFK;AAGbC,MAAAA,IAAI,EAAE,CAHO;AAIbC,MAAAA,KAAK,EAAE;AAJM,KAAf;AAMA,UAAMC,KAAK,GAAG;AACZC,MAAAA,CAAC,EAAE,CADS;AAEZC,MAAAA,CAAC,EAAE,CAFS;AAGZC,MAAAA,KAAK,EAAEV,MAAM,CAACU,KAHF;AAIZC,MAAAA,MAAM,EAAEX,MAAM,CAACW;AAJH,KAAd,CAPoB,CAapB;;AACAZ,IAAAA,cAAc,CAAC;AAAEa,MAAAA,WAAW,EAAE;AAAEV,QAAAA,MAAF;AAAUK,QAAAA;AAAV;AAAf,KAAD,CAAd;AACD,GAfD,EAeG,CAACR,cAAD,EAAiBC,MAAM,CAACW,MAAxB,EAAgCX,MAAM,CAACU,KAAvC,CAfH;AAgBA,sBAAO,oBAAC,IAAD;AAAM,IAAA,KAAK,EAAEZ;AAAb,KAAqBD,QAArB,CAAP;AACD","sourcesContent":["import * as React from 'react';\nimport { View } from 'react-native';\nimport { NativeSafeAreaProviderProps } from './SafeArea.types';\nimport useWindowDimensions from './useWindowDimensions';\n\nexport function CompatNativeSafeAreaProvider({\n children,\n style,\n onInsetsChange,\n}: NativeSafeAreaProviderProps) {\n const window = useWindowDimensions();\n React.useEffect(() => {\n const insets = {\n top: 0,\n bottom: 0,\n left: 0,\n right: 0,\n };\n const frame = {\n x: 0,\n y: 0,\n width: window.width,\n height: window.height,\n };\n // @ts-ignore: missing properties\n onInsetsChange({ nativeEvent: { insets, frame } });\n }, [onInsetsChange, window.height, window.width]);\n return <View style={style}>{children}</View>;\n}\n"]}

View File

@ -0,0 +1,7 @@
export const initialWindowMetrics = null;
/**
* @deprecated
*/
export const initialWindowSafeAreaInsets = null;
//# sourceMappingURL=InitialWindow.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["InitialWindow.ts"],"names":["initialWindowMetrics","initialWindowSafeAreaInsets"],"mappings":"AAEA,OAAO,MAAMA,oBAAoC,GAAG,IAA7C;AAEP;;;;AAGA,OAAO,MAAMC,2BAA8C,GAAG,IAAvD","sourcesContent":["import { EdgeInsets, Metrics } from './SafeArea.types';\n\nexport const initialWindowMetrics: Metrics | null = null;\n\n/**\n * @deprecated\n */\nexport const initialWindowSafeAreaInsets: EdgeInsets | null = null;\n"]}

View File

@ -0,0 +1,9 @@
import { UIManager } from 'react-native';
const RNCSafeAreaProviderConfig = UIManager.getViewManagerConfig('RNCSafeAreaProvider');
export const initialWindowMetrics = RNCSafeAreaProviderConfig != null && RNCSafeAreaProviderConfig.Constants != null ? RNCSafeAreaProviderConfig.Constants.initialWindowMetrics : null;
/**
* @deprecated
*/
export const initialWindowSafeAreaInsets = initialWindowMetrics === null || initialWindowMetrics === void 0 ? void 0 : initialWindowMetrics.insets;
//# sourceMappingURL=InitialWindow.native.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["InitialWindow.native.ts"],"names":["UIManager","RNCSafeAreaProviderConfig","getViewManagerConfig","initialWindowMetrics","Constants","initialWindowSafeAreaInsets","insets"],"mappings":"AAAA,SAASA,SAAT,QAA0B,cAA1B;AAGA,MAAMC,yBAAyB,GAAGD,SAAS,CAACE,oBAAV,CAChC,qBADgC,CAAlC;AAIA,OAAO,MAAMC,oBAAoB,GAAIF,yBAAyB,IAAI,IAA7B,IACrCA,yBAAyB,CAACG,SAA1B,IAAuC,IADF,GAEjCH,yBAAyB,CAACG,SAA1B,CAAoCD,oBAFH,GAGjC,IAHG;AAKP;;;;AAGA,OAAO,MAAME,2BAA2B,GAAGF,oBAAH,aAAGA,oBAAH,uBAAGA,oBAAoB,CAAEG,MAA1D","sourcesContent":["import { UIManager } from 'react-native';\nimport { Metrics } from './SafeArea.types';\n\nconst RNCSafeAreaProviderConfig = UIManager.getViewManagerConfig(\n 'RNCSafeAreaProvider',\n) as any;\n\nexport const initialWindowMetrics = (RNCSafeAreaProviderConfig != null &&\nRNCSafeAreaProviderConfig.Constants != null\n ? RNCSafeAreaProviderConfig.Constants.initialWindowMetrics\n : null) as Metrics | null;\n\n/**\n * @deprecated\n */\nexport const initialWindowSafeAreaInsets = initialWindowMetrics?.insets;\n"]}

View File

@ -0,0 +1,138 @@
import * as React from 'react';
import { View } from 'react-native';
/**
* TODO:
* Currently insets and frame are based on the window and are not
* relative to the provider view. This is inconsistent with iOS and Android.
* However in most cases if the provider view covers the screen this is not
* an issue.
*/
const CSSTransitions = {
WebkitTransition: 'webkitTransitionEnd',
Transition: 'transitionEnd',
MozTransition: 'transitionend',
MSTransition: 'msTransitionEnd',
OTransition: 'oTransitionEnd'
};
export default function NativeSafeAreaView({
children,
style,
onInsetsChange
}) {
React.useEffect(() => {
// Skip for SSR.
if (typeof document === 'undefined') {
return;
}
const element = createContextElement();
document.body.appendChild(element);
const onEnd = () => {
const {
paddingTop,
paddingBottom,
paddingLeft,
paddingRight
} = window.getComputedStyle(element);
const insets = {
top: paddingTop ? parseInt(paddingTop, 10) : 0,
bottom: paddingBottom ? parseInt(paddingBottom, 10) : 0,
left: paddingLeft ? parseInt(paddingLeft, 10) : 0,
right: paddingRight ? parseInt(paddingRight, 10) : 0
};
const frame = {
x: 0,
y: 0,
width: document.documentElement.offsetWidth,
height: document.documentElement.offsetHeight
}; // @ts-ignore: missing properties
onInsetsChange({
nativeEvent: {
insets,
frame
}
});
};
element.addEventListener(getSupportedTransitionEvent(), onEnd);
onEnd();
return () => {
document.body.removeChild(element);
element.removeEventListener(getSupportedTransitionEvent(), onEnd);
};
}, [onInsetsChange]);
return /*#__PURE__*/React.createElement(View, {
style: style
}, children);
}
let _supportedTransitionEvent = null;
function getSupportedTransitionEvent() {
if (_supportedTransitionEvent !== null) {
return _supportedTransitionEvent;
}
const element = document.createElement('invalidtype');
_supportedTransitionEvent = CSSTransitions.Transition;
for (const key in CSSTransitions) {
if (element.style[key] !== undefined) {
_supportedTransitionEvent = CSSTransitions[key];
break;
}
}
return _supportedTransitionEvent;
}
let _supportedEnv = null;
function getSupportedEnv() {
if (_supportedEnv !== null) {
return _supportedEnv;
}
const {
CSS
} = window;
if (CSS && CSS.supports && CSS.supports('top: constant(safe-area-inset-top)')) {
_supportedEnv = 'constant';
} else {
_supportedEnv = 'env';
}
return _supportedEnv;
}
function getInset(side) {
return "".concat(getSupportedEnv(), "(safe-area-inset-").concat(side, ")");
}
function createContextElement() {
const element = document.createElement('div');
const {
style
} = element;
style.position = 'fixed';
style.left = '0';
style.top = '0';
style.width = '0';
style.height = '0';
style.zIndex = '-1';
style.overflow = 'hidden';
style.visibility = 'hidden'; // Bacon: Anything faster than this and the callback will be invoked too early with the wrong insets
style.transitionDuration = '0.05s';
style.transitionProperty = 'padding';
style.transitionDelay = '0s';
style.paddingTop = getInset('top');
style.paddingBottom = getInset('bottom');
style.paddingLeft = getInset('left');
style.paddingRight = getInset('right');
return element;
}
//# sourceMappingURL=NativeSafeAreaProvider.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,3 @@
import { CompatNativeSafeAreaProvider } from './CompatNativeSafeAreaProvider';
export default CompatNativeSafeAreaProvider;
//# sourceMappingURL=NativeSafeAreaProvider.macos.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["NativeSafeAreaProvider.macos.tsx"],"names":["CompatNativeSafeAreaProvider"],"mappings":"AAAA,SAASA,4BAAT,QAA6C,gCAA7C;AAEA,eAAeA,4BAAf","sourcesContent":["import { CompatNativeSafeAreaProvider } from './CompatNativeSafeAreaProvider';\n\nexport default CompatNativeSafeAreaProvider;\n"]}

View File

@ -0,0 +1,3 @@
import { requireNativeComponent } from 'react-native';
export default requireNativeComponent('RNCSafeAreaProvider');
//# sourceMappingURL=NativeSafeAreaProvider.native.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["NativeSafeAreaProvider.native.tsx"],"names":["requireNativeComponent"],"mappings":"AAAA,SAASA,sBAAT,QAAuC,cAAvC;AAGA,eAAeA,sBAAsB,CACnC,qBADmC,CAArC","sourcesContent":["import { requireNativeComponent } from 'react-native';\nimport { NativeSafeAreaProviderProps } from './SafeArea.types';\n\nexport default requireNativeComponent<NativeSafeAreaProviderProps>(\n 'RNCSafeAreaProvider',\n);\n"]}

View File

@ -0,0 +1,3 @@
import { CompatNativeSafeAreaProvider } from './CompatNativeSafeAreaProvider';
export default CompatNativeSafeAreaProvider;
//# sourceMappingURL=NativeSafeAreaProvider.windows.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["NativeSafeAreaProvider.windows.tsx"],"names":["CompatNativeSafeAreaProvider"],"mappings":"AAAA,SAASA,4BAAT,QAA6C,gCAA7C;AAEA,eAAeA,4BAAf","sourcesContent":["import { CompatNativeSafeAreaProvider } from './CompatNativeSafeAreaProvider';\n\nexport default CompatNativeSafeAreaProvider;\n"]}

View File

@ -0,0 +1,2 @@
//# sourceMappingURL=SafeArea.types.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":[],"names":[],"mappings":"","sourcesContent":[]}

View File

@ -0,0 +1,107 @@
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import * as React from 'react';
import { Dimensions, StyleSheet } from 'react-native';
import NativeSafeAreaProvider from './NativeSafeAreaProvider';
export const SafeAreaInsetsContext = React.createContext(null);
export const SafeAreaFrameContext = React.createContext(null);
export function SafeAreaProvider({
children,
initialMetrics,
initialSafeAreaInsets,
style
}) {
var _ref, _ref2, _initialMetrics$inset, _ref3, _initialMetrics$frame;
const parentInsets = useParentSafeAreaInsets();
const parentFrame = useParentSafeAreaFrame();
const [insets, setInsets] = React.useState((_ref = (_ref2 = (_initialMetrics$inset = initialMetrics === null || initialMetrics === void 0 ? void 0 : initialMetrics.insets) !== null && _initialMetrics$inset !== void 0 ? _initialMetrics$inset : initialSafeAreaInsets) !== null && _ref2 !== void 0 ? _ref2 : parentInsets) !== null && _ref !== void 0 ? _ref : null);
const [frame, setFrame] = React.useState((_ref3 = (_initialMetrics$frame = initialMetrics === null || initialMetrics === void 0 ? void 0 : initialMetrics.frame) !== null && _initialMetrics$frame !== void 0 ? _initialMetrics$frame : parentFrame) !== null && _ref3 !== void 0 ? _ref3 : {
// Backwards compat so we render anyway if we don't have frame.
x: 0,
y: 0,
width: Dimensions.get('window').width,
height: Dimensions.get('window').height
});
const onInsetsChange = React.useCallback(event => {
const {
nativeEvent: {
frame: nextFrame,
insets: nextInsets
}
} = event;
if ( // Backwards compat with old native code that won't send frame.
nextFrame && (nextFrame.height !== frame.height || nextFrame.width !== frame.width || nextFrame.x !== frame.x || nextFrame.y !== frame.y)) {
setFrame(nextFrame);
}
if (!insets || nextInsets.bottom !== insets.bottom || nextInsets.left !== insets.left || nextInsets.right !== insets.right || nextInsets.top !== insets.top) {
setInsets(nextInsets);
}
}, [frame, insets]);
return /*#__PURE__*/React.createElement(NativeSafeAreaProvider, {
style: [styles.fill, style],
onInsetsChange: onInsetsChange
}, insets != null ? /*#__PURE__*/React.createElement(SafeAreaFrameContext.Provider, {
value: frame
}, /*#__PURE__*/React.createElement(SafeAreaInsetsContext.Provider, {
value: insets
}, children)) : null);
}
const styles = StyleSheet.create({
fill: {
flex: 1
}
});
function useParentSafeAreaInsets() {
return React.useContext(SafeAreaInsetsContext);
}
function useParentSafeAreaFrame() {
return React.useContext(SafeAreaFrameContext);
}
export function useSafeAreaInsets() {
const safeArea = React.useContext(SafeAreaInsetsContext);
if (safeArea == null) {
throw new Error('No safe area insets value available. Make sure you are rendering `<SafeAreaProvider>` at the top of your app.');
}
return safeArea;
}
export function useSafeAreaFrame() {
const frame = React.useContext(SafeAreaFrameContext);
if (frame == null) {
throw new Error('No safe area frame value available. Make sure you are rendering `<SafeAreaProvider>` at the top of your app.');
}
return frame;
}
export function withSafeAreaInsets(WrappedComponent) {
return /*#__PURE__*/React.forwardRef((props, ref) => /*#__PURE__*/React.createElement(SafeAreaConsumer, null, insets => /*#__PURE__*/React.createElement(WrappedComponent, _extends({}, props, {
insets: insets,
ref: ref
}))));
}
/**
* @deprecated
*/
export function useSafeArea() {
return useSafeAreaInsets();
}
/**
* @deprecated
*/
export const SafeAreaConsumer = SafeAreaInsetsContext.Consumer;
/**
* @deprecated
*/
export const SafeAreaContext = SafeAreaInsetsContext;
//# sourceMappingURL=SafeAreaContext.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,81 @@
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
import * as React from 'react';
import { View, StyleSheet } from 'react-native';
import { useSafeAreaInsets } from './SafeAreaContext';
// prettier-ignore
const TOP = 0b1000,
RIGHT = 0b0100,
BOTTOM = 0b0010,
LEFT = 0b0001,
ALL = 0b1111;
/* eslint-disable no-bitwise */
const edgeBitmaskMap = {
top: TOP,
right: RIGHT,
bottom: BOTTOM,
left: LEFT
};
export function SafeAreaView(_ref) {
let {
style = {},
mode,
edges
} = _ref,
rest = _objectWithoutProperties(_ref, ["style", "mode", "edges"]);
const insets = useSafeAreaInsets();
const edgeBitmask = edges != null ? edges.reduce((accum, edge) => accum | edgeBitmaskMap[edge], 0) : ALL;
const appliedStyle = React.useMemo(() => {
const insetTop = edgeBitmask & TOP ? insets.top : 0;
const insetRight = edgeBitmask & RIGHT ? insets.right : 0;
const insetBottom = edgeBitmask & BOTTOM ? insets.bottom : 0;
const insetLeft = edgeBitmask & LEFT ? insets.left : 0;
const flatStyle = StyleSheet.flatten(style);
if (mode === 'margin') {
const {
margin = 0,
marginVertical = margin,
marginHorizontal = margin,
marginTop = marginVertical,
marginRight = marginHorizontal,
marginBottom = marginVertical,
marginLeft = marginHorizontal
} = flatStyle;
const marginStyle = {
marginTop: marginTop + insetTop,
marginRight: marginRight + insetRight,
marginBottom: marginBottom + insetBottom,
marginLeft: marginLeft + insetLeft
};
return [style, marginStyle];
} else {
const {
padding = 0,
paddingVertical = padding,
paddingHorizontal = padding,
paddingTop = paddingVertical,
paddingRight = paddingHorizontal,
paddingBottom = paddingVertical,
paddingLeft = paddingHorizontal
} = flatStyle;
const paddingStyle = {
paddingTop: paddingTop + insetTop,
paddingRight: paddingRight + insetRight,
paddingBottom: paddingBottom + insetBottom,
paddingLeft: paddingLeft + insetLeft
};
return [style, paddingStyle];
}
}, [style, insets, mode, edgeBitmask]);
return /*#__PURE__*/React.createElement(View, _extends({
style: appliedStyle
}, rest));
}
//# sourceMappingURL=SafeAreaView.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,3 @@
import { View } from 'react-native';
export const SafeAreaView = View;
//# sourceMappingURL=SafeAreaView.macos.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["SafeAreaView.macos.tsx"],"names":["View","SafeAreaView"],"mappings":"AAAA,SAASA,IAAT,QAAqB,cAArB;AAEA,OAAO,MAAMC,YAAY,GAAGD,IAArB","sourcesContent":["import { View } from 'react-native';\n\nexport const SafeAreaView = View;\n"]}

View File

@ -0,0 +1,3 @@
import { requireNativeComponent } from 'react-native';
export const SafeAreaView = requireNativeComponent('RNCSafeAreaView');
//# sourceMappingURL=SafeAreaView.native.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["SafeAreaView.native.tsx"],"names":["requireNativeComponent","SafeAreaView"],"mappings":"AAAA,SAASA,sBAAT,QAAuC,cAAvC;AAGA,OAAO,MAAMC,YAAY,GAAGD,sBAAsB,CAChD,iBADgD,CAA3C","sourcesContent":["import { requireNativeComponent } from 'react-native';\nimport { NativeSafeAreaViewProps } from './SafeArea.types';\n\nexport const SafeAreaView = requireNativeComponent<NativeSafeAreaViewProps>(\n 'RNCSafeAreaView',\n);\n"]}

View File

@ -0,0 +1,3 @@
import { View } from 'react-native';
export const SafeAreaView = View;
//# sourceMappingURL=SafeAreaView.windows.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["SafeAreaView.windows.tsx"],"names":["View","SafeAreaView"],"mappings":"AAAA,SAASA,IAAT,QAAqB,cAArB;AAEA,OAAO,MAAMC,YAAY,GAAGD,IAArB","sourcesContent":["import { View } from 'react-native';\n\nexport const SafeAreaView = View;\n"]}

View File

@ -0,0 +1,5 @@
export * from './SafeAreaContext';
export * from './SafeAreaView';
export * from './InitialWindow';
export * from './SafeArea.types';
//# sourceMappingURL=index.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["index.tsx"],"names":[],"mappings":"AAAA,cAAc,mBAAd;AACA,cAAc,gBAAd;AACA,cAAc,iBAAd;AACA,cAAc,kBAAd","sourcesContent":["export * from './SafeAreaContext';\nexport * from './SafeAreaView';\nexport * from './InitialWindow';\nexport * from './SafeArea.types';\n"]}

View File

@ -0,0 +1,29 @@
import { Dimensions } from 'react-native';
import { useEffect, useState } from 'react';
// Copied from https://github.com/facebook/react-native/blob/8d57691a/Libraries/Utilities/useWindowDimensions.js
// for compatibility with React Native < 0.61.
export default function useWindowDimensions() {
const [dimensions, setDimensions] = useState(() => Dimensions.get('window'));
useEffect(() => {
function handleChange({
window
}) {
if (dimensions.width !== window.width || dimensions.height !== window.height || dimensions.scale !== window.scale || dimensions.fontScale !== window.fontScale) {
setDimensions(window);
}
}
Dimensions.addEventListener('change', handleChange); // We might have missed an update between calling `get` in render and
// `addEventListener` in this handler, so we set it here. If there was
// no change, React will filter out this update as a no-op.
handleChange({
window: Dimensions.get('window')
});
return () => {
Dimensions.removeEventListener('change', handleChange);
};
}, [dimensions]);
return dimensions;
}
//# sourceMappingURL=useWindowDimensions.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["useWindowDimensions.tsx"],"names":["Dimensions","useEffect","useState","useWindowDimensions","dimensions","setDimensions","get","handleChange","window","width","height","scale","fontScale","addEventListener","removeEventListener"],"mappings":"AAAA,SAASA,UAAT,QAA2B,cAA3B;AACA,SAASC,SAAT,EAAoBC,QAApB,QAAoC,OAApC;AASA;AACA;AACA,eAAe,SAASC,mBAAT,GAA+C;AAC5D,QAAM,CAACC,UAAD,EAAaC,aAAb,IAA8BH,QAAQ,CAAC,MAAMF,UAAU,CAACM,GAAX,CAAe,QAAf,CAAP,CAA5C;AACAL,EAAAA,SAAS,CAAC,MAAM;AACd,aAASM,YAAT,CAAsB;AAAEC,MAAAA;AAAF,KAAtB,EAA8D;AAC5D,UACEJ,UAAU,CAACK,KAAX,KAAqBD,MAAM,CAACC,KAA5B,IACAL,UAAU,CAACM,MAAX,KAAsBF,MAAM,CAACE,MAD7B,IAEAN,UAAU,CAACO,KAAX,KAAqBH,MAAM,CAACG,KAF5B,IAGAP,UAAU,CAACQ,SAAX,KAAyBJ,MAAM,CAACI,SAJlC,EAKE;AACAP,QAAAA,aAAa,CAACG,MAAD,CAAb;AACD;AACF;;AACDR,IAAAA,UAAU,CAACa,gBAAX,CAA4B,QAA5B,EAAsCN,YAAtC,EAXc,CAYd;AACA;AACA;;AACAA,IAAAA,YAAY,CAAC;AAAEC,MAAAA,MAAM,EAAER,UAAU,CAACM,GAAX,CAAe,QAAf;AAAV,KAAD,CAAZ;AACA,WAAO,MAAM;AACXN,MAAAA,UAAU,CAACc,mBAAX,CAA+B,QAA/B,EAAyCP,YAAzC;AACD,KAFD;AAGD,GAnBQ,EAmBN,CAACH,UAAD,CAnBM,CAAT;AAoBA,SAAOA,UAAP;AACD","sourcesContent":["import { Dimensions } from 'react-native';\nimport { useEffect, useState } from 'react';\n\ntype DisplayMetrics = {\n width: number;\n height: number;\n scale: number;\n fontScale: number;\n};\n\n// Copied from https://github.com/facebook/react-native/blob/8d57691a/Libraries/Utilities/useWindowDimensions.js\n// for compatibility with React Native < 0.61.\nexport default function useWindowDimensions(): DisplayMetrics {\n const [dimensions, setDimensions] = useState(() => Dimensions.get('window'));\n useEffect(() => {\n function handleChange({ window }: { window: DisplayMetrics }) {\n if (\n dimensions.width !== window.width ||\n dimensions.height !== window.height ||\n dimensions.scale !== window.scale ||\n dimensions.fontScale !== window.fontScale\n ) {\n setDimensions(window);\n }\n }\n Dimensions.addEventListener('change', handleChange);\n // We might have missed an update between calling `get` in render and\n // `addEventListener` in this handler, so we set it here. If there was\n // no change, React will filter out this update as a no-op.\n handleChange({ window: Dimensions.get('window') });\n return () => {\n Dimensions.removeEventListener('change', handleChange);\n };\n }, [dimensions]);\n return dimensions;\n}\n"]}

View File

@ -0,0 +1,3 @@
/// <reference types="react" />
import { NativeSafeAreaProviderProps } from './SafeArea.types';
export declare function CompatNativeSafeAreaProvider({ children, style, onInsetsChange, }: NativeSafeAreaProviderProps): JSX.Element;

View File

@ -0,0 +1,6 @@
import { EdgeInsets, Metrics } from './SafeArea.types';
export declare const initialWindowMetrics: Metrics | null;
/**
* @deprecated
*/
export declare const initialWindowSafeAreaInsets: EdgeInsets | null;

View File

@ -0,0 +1,6 @@
import { Metrics } from './SafeArea.types';
export declare const initialWindowMetrics: Metrics | null;
/**
* @deprecated
*/
export declare const initialWindowSafeAreaInsets: import("./SafeArea.types").EdgeInsets | undefined;

Some files were not shown because too many files have changed in this diff Show More