├── .editorconfig
├── .github
├── CODE_OF_CONDUCT.md
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ ├── config.yml
│ └── feature_request.yml
├── PULL_REQUEST_TEMPLATE.md
├── stale.yml
└── workflows
│ └── verify.yml
├── .gitignore
├── .prettierignore
├── CODEOWNERS
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── android
├── build.gradle
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── AndroidManifestNew.xml
│ ├── java
│ │ └── com
│ │ │ └── zoontek
│ │ │ └── rnedgetoedge
│ │ │ ├── EdgeToEdgeModuleImpl.kt
│ │ │ └── EdgeToEdgePackage.kt
│ └── res
│ │ ├── values-night-v27
│ │ └── bools.xml
│ │ ├── values-night
│ │ └── bools.xml
│ │ ├── values-v27
│ │ ├── bools.xml
│ │ ├── colors.xml
│ │ └── styles.xml
│ │ ├── values-v29
│ │ └── styles.xml
│ │ ├── values-v30
│ │ └── styles.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── bools.xml
│ │ ├── colors.xml
│ │ ├── public.xml
│ │ └── styles.xml
│ ├── newarch
│ └── com
│ │ └── zoontek
│ │ └── rnedgetoedge
│ │ └── EdgeToEdgeModule.kt
│ └── oldarch
│ └── com
│ └── zoontek
│ └── rnedgetoedge
│ └── EdgeToEdgeModule.kt
├── app.plugin.js
├── docs
├── expo.svg
└── logo.svg
├── example
├── .bundle
│ └── config
├── Gemfile
├── Gemfile.lock
├── android
│ ├── app
│ │ ├── build.gradle
│ │ ├── debug.keystore
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── rnedgetoedgeexample
│ │ │ │ ├── MainActivity.kt
│ │ │ │ └── MainApplication.kt
│ │ │ └── res
│ │ │ ├── drawable
│ │ │ └── rn_edit_text_material.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ └── values
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ └── settings.gradle
├── app.json
├── babel.config.js
├── index.js
├── ios
│ ├── .xcode.env
│ ├── Podfile
│ ├── Podfile.lock
│ ├── RNEdgeToEdgeExample.xcodeproj
│ │ ├── project.pbxproj
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── RNEdgeToEdgeExample.xcscheme
│ ├── RNEdgeToEdgeExample.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── RNEdgeToEdgeExample
│ │ ├── AppDelegate.swift
│ │ ├── Images.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ │ ├── Info.plist
│ │ ├── LaunchScreen.storyboard
│ │ └── PrivacyInfo.xcprivacy
├── metro.config.js
├── package.json
├── src
│ └── App.tsx
├── tsconfig.json
└── yarn.lock
├── package.json
├── react-native-is-edge-to-edge
├── CHANGELOG.md
├── README.md
├── __tests__
│ └── controlEdgeToEdgeValues.test.ts
├── package.json
├── src
│ ├── index.android.ts
│ └── index.ts
├── tsconfig.build.json
├── tsconfig.json
├── tsup.config.ts
└── yarn.lock
├── src
├── SystemBars.ts
├── expo.ts
├── index.ts
├── specs
│ ├── NativeEdgeToEdgeModule.ts
│ └── NativeEdgeToEdgeModule.web.ts
└── types.ts
├── tsconfig.json
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_size = 2
6 | indent_style = space
7 | insert_final_newline = true
8 | trim_trailing_whitespace = true
9 |
10 | [*.bat]
11 | end_of_line = crlf
12 |
13 | [*.{gradle,xml}]
14 | indent_size = 4
15 |
16 | [*.md]
17 | trim_trailing_whitespace = false
18 |
--------------------------------------------------------------------------------
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, caste, color, religion, or sexual
10 | identity and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | - Demonstrating empathy and kindness toward other people
21 | - Being respectful of differing opinions, viewpoints, and experiences
22 | - Giving and gracefully accepting constructive feedback
23 | - Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | - Focusing on what is best not just for us as individuals, but for the overall
26 | community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | - The use of sexualized language or imagery, and sexual attention or advances of
31 | any kind
32 | - Trolling, insulting or derogatory comments, and personal or political attacks
33 | - Public or private harassment
34 | - Publishing others' private information, such as a physical or email address,
35 | without their explicit permission
36 | - Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official email address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | [INSERT CONTACT METHOD].
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series of
86 | actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or permanent
93 | ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within the
113 | community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.1, available at
119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
120 |
121 | Community Impact Guidelines were inspired by
122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
123 |
124 | For answers to common questions about this code of conduct, see the FAQ at
125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
126 | [https://www.contributor-covenant.org/translations][translations].
127 |
128 | [homepage]: https://www.contributor-covenant.org
129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
130 | [Mozilla CoC]: https://github.com/mozilla/diversity
131 | [FAQ]: https://www.contributor-covenant.org/faq
132 | [translations]: https://www.contributor-covenant.org/translations
133 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [zoontek]
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: 🐛 Bug report
2 | description: Report a reproducible bug or regression in this library.
3 | labels: [bug]
4 | assignees:
5 | - zoontek
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | # Bug report
11 |
12 | 👋 Hi!
13 |
14 | **🚨 Please fill the following carefully before opening a new issue 🚨**
15 | *(Your issue may be closed if it doesn't provide the required pieces of information)*
16 | - type: checkboxes
17 | attributes:
18 | label: Before submitting a new issue
19 | description: Please perform simple checks first.
20 | options:
21 | - label: I tested using the latest version of the library, as the bug might be already fixed.
22 | required: true
23 | - label: I tested using a [supported version](https://github.com/reactwg/react-native-releases/blob/main/docs/support.md) of react native.
24 | required: true
25 | - label: I checked for possible duplicate issues, with possible answers.
26 | required: true
27 | - type: textarea
28 | id: summary
29 | attributes:
30 | label: Bug summary
31 | description: |
32 | Provide a clear and concise description of what the bug is.
33 | If needed, you can also provide other samples: error messages / stack traces, screenshots, gifs, etc.
34 | validations:
35 | required: true
36 | - type: input
37 | id: library-version
38 | attributes:
39 | label: Library version
40 | description: What version of the library are you using?
41 | placeholder: "x.x.x"
42 | validations:
43 | required: true
44 | - type: textarea
45 | id: react-native-info
46 | attributes:
47 | label: Environment info
48 | description: Run `react-native info` in your terminal and paste the results here.
49 | render: shell
50 | validations:
51 | required: true
52 | - type: textarea
53 | id: steps-to-reproduce
54 | attributes:
55 | label: Steps to reproduce
56 | description: |
57 | - You must provide a clear list of steps and code to reproduce the problem.
58 | - Keep the code reproducing the bug as simple as possible, with the minimum amount of code required to reproduce the issue. See https://stackoverflow.com/help/mcve.
59 | - Is the issue happening on iOS, Android or both?
60 | - Do you run your app on a simulator (which OS version?) or on a physical device (which one? which OS version?)
61 | - If this library has additional install steps, describe them (e.g., pod install? jetify? etc).
62 | - Either re-create the bug using the repository's example app or link to a GitHub repository with code that reproduces the bug.
63 | - Explain the steps we need to take to reproduce the issue:
64 | value: |
65 | 1. …
66 | 2. …
67 | validations:
68 | required: true
69 | - type: textarea
70 | id: reproducible-sample-code
71 | attributes:
72 | label: Reproducible sample code
73 | description: Please add minimal runnable repro as explained above so that the bug can be tested in isolation.
74 | render: js
75 | validations:
76 | required: true
77 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: ❓ Stack Overflow
4 | url: https://stackoverflow.com
5 | about: If this library works as promised but you need help, please ask questions there.
6 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: 💡 Feature request
2 | description: Submit your idea for a change in the codebase.
3 | labels: [feature request]
4 | assignees:
5 | - zoontek
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | # Feature request
11 |
12 | This issue should serve for you to present or pitch an idea to the maintainers - but remember that it would be better if you were to submit a PR instead 🤗
13 | - type: textarea
14 | id: why-is-this-needed
15 | attributes:
16 | label: Why it is needed?
17 | description: Please tell us a bit more of why you want this feature to be added, what's its origin.
18 | validations:
19 | required: true
20 | - type: textarea
21 | id: possible-implementation
22 | attributes:
23 | label: Possible implementation
24 | description: It really helps if you could describe from a technical POV how this new feature would work, which code it rely on, etc.
25 | validations:
26 | required: false
27 | - type: textarea
28 | id: code-sample
29 | attributes:
30 | label: Code sample
31 | description: Please show how the new code could work, if doable.
32 | render: js
33 | validations:
34 | required: false
35 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Summary
4 |
5 |
13 |
14 | ## Test Plan
15 |
16 |
17 |
18 | ### What's required for testing (prerequisites)?
19 |
20 | ### What are the steps to test it (after prerequisites)?
21 |
22 | ## Compatibility
23 |
24 | | OS | Implemented |
25 | | ------- | :---------: |
26 | | iOS | ✅❌ |
27 | | Android | ✅❌ |
28 |
29 | ## Checklist
30 |
31 |
32 |
33 | - [ ] I have tested this on a device and a simulator
34 | - [ ] I added the documentation in `README.md`
35 | - [ ] I added a sample use of the API in the example project (`example/src/App.tsx`)
36 |
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | # Configuration for probot-stale based on: https://github.com/facebook/react-native/blob/master/.github/stale.yml
2 |
3 | # Number of days of inactivity before an Issue or Pull Request becomes stale
4 | daysUntilStale:
5 | 60
6 | # Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
7 | daysUntilClose:
8 | 7
9 | # Issues or Pull Requests.
10 | exemptLabels:
11 | - pinned
12 | - security
13 | - discussion
14 |
15 | # Set to true to ignore issues in a project (defaults to false)
16 | exemptProjects:
17 | false
18 | # Set to true to ignore issues in a milestone (defaults to false)
19 | exemptMilestones:
20 | false
21 | # Set to true to ignore issues with an assignee (defaults to false)
22 | exemptAssignees:
23 | false
24 | # Label to use when marking as stale
25 | staleLabel:
26 | stale
27 | # Comment to post when marking as stale. Set to `false` to disable
28 | markComment: >
29 | This issue has been automatically marked as stale because it has not had
30 | recent activity. It will be closed if no further activity occurs. Thank you
31 | for your contributions. You may also mark this issue as a "discussion" and I
32 | will leave this open.
33 | # Comment to post when closing a stale Issue or Pull Request.
34 | closeComment: >
35 | Closing this issue after a prolonged period of inactivity. Fell free to reopen
36 | this issue, if this still affecting you.
37 | # Limit the number of actions per hour, from 1-30. Default is 30
38 | limitPerRun:
39 | 30
40 | # Limit to only `issues` or `pulls`
41 | only: issues
42 |
--------------------------------------------------------------------------------
/.github/workflows/verify.yml:
--------------------------------------------------------------------------------
1 | name: Verify
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request:
7 | branches: [main]
8 |
9 | jobs:
10 | prepack:
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v4
15 |
16 | - uses: actions/setup-node@v4
17 | with:
18 | node-version: 20
19 |
20 | - run: yarn install --frozen-lockfile
21 | - run: yarn prepack
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | **/.xcode.env.local
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 | *.hprof
33 | .cxx/
34 | *.keystore
35 | !debug.keystore
36 | .kotlin/
37 |
38 | # Visual Studio Code
39 | #
40 | .vscode/
41 |
42 | # node.js
43 | #
44 | node_modules/
45 | npm-debug.log
46 | yarn-error.log
47 |
48 | # Bundle artifact
49 | *.jsbundle
50 |
51 | # Ruby / CocoaPods
52 | **/Pods/
53 | example/vendor/bundle/
54 |
55 | # Bob
56 | dist/
57 |
58 | # Temporary files created by Metro to check the health of the file watcher
59 | .metro-health-check*
60 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | dist/
2 | node_modules/
3 | Pods/
4 |
5 | example/android/app/build/
6 | example/ios/build/
7 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Global owners
2 | * @zoontek
3 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to react-native-edge-to-edge
2 |
3 | Thank you for your interest in contributing to **react-native-edge-to-edge**! We appreciate your help in improving this project. Please follow the guidelines below to ensure a smooth contribution process.
4 |
5 | ## Code of conduct
6 |
7 | This project and everyone participating in it is governed by the [Code of conduct](.github/CODE_OF_CONDUCT.md). By participating, you are expected to adhere to this code.
8 |
9 | ## How can I contribute?
10 |
11 | ### Reporting bugs
12 |
13 | If you encounter any bugs or issues, please report them via [GitHub issues](https://github.com/zoontek/react-native-edge-to-edge/issues). When submitting a bug report, please ensure that you follow the provided template.
14 |
15 | ### Suggesting features
16 |
17 | We are open to discussion! If you have a feature request, please submit it via [GitHub issues](https://github.com/zoontek/react-native-edge-to-edge/issues).
18 |
19 | ### Contributing code
20 |
21 | We welcome pull requests! Here’s how you can contribute:
22 |
23 | 1. Fork the repository and clone your fork.
24 | 2. Create a new branch for your feature or bugfix: `git checkout -b feature/a-name`
25 | 3. Write clear and concise code, following the coding guidelines (enforced by [`prettier`](https://prettier.io/)).
26 | 4. Test your code using the [example app](./example) on both iOS and Android, and on both React Native architectures.
27 | 5. Commit your changes and push to your fork.
28 | 6. Open a pull request from your branch to the `main` branch of the main repository.
29 |
30 | ## Development workflow
31 |
32 | ### Setting up the project
33 |
34 | 1. Fork the repository and clone your fork:
35 |
36 | ```bash
37 | git clone https://github.com/zoontek/react-native-edge-to-edge.git
38 | ```
39 |
40 | 2. Install the dependencies (using [yarn v1](https://github.com/yarnpkg/yarn)):
41 |
42 | ```bash
43 | cd react-native-edge-to-edge
44 | yarn install
45 | ```
46 |
47 | 3. Install the example app dependencies:
48 |
49 | ```bash
50 | cd example
51 | yarn install
52 |
53 | cd ios
54 | bundle install && bundle exec pod install
55 | ```
56 |
57 | 4. Start the app:
58 |
59 | ```bash
60 | yarn start
61 | ```
62 |
63 | ### Running checks
64 |
65 | We highly encourage running checks (formatting, typing, build, etc.) before committing.
66 |
67 | ```bash
68 | yarn prepack
69 | ```
70 |
71 | Thank you for your contributions! 🙌
72 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Mathieu Acthernoene
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-native-edge-to-edge
2 |
3 | Effortlessly enable [edge-to-edge](https://developer.android.com/develop/ui/views/layout/edge-to-edge) display in React Native, allowing your Android (v6 and above) app content to flow seamlessly beneath the system bars.
4 |
5 | [](https://github.com/zoontek/react-native-edge-to-edge/blob/main/LICENSE)
6 | [](https://www.npmjs.org/package/react-native-edge-to-edge)
7 | [](https://www.npmjs.org/package/react-native-edge-to-edge)
8 |
9 |
10 |
11 | ## Credits
12 |
13 | This project has been built and is maintained thanks to the support from [Expo](https://expo.dev).
14 |
15 |
16 |
17 |
18 |
19 | ## Support
20 |
21 | This library follows the React Native [releases support policy](https://github.com/reactwg/react-native-releases/blob/main/docs/support.md).
22 | It is supporting the **latest version**, and the **two previous minor series**.
23 |
24 | ## Motivations
25 |
26 | ### Android 15
27 |
28 | Recently, Google introduced a significant change: apps targeting SDK 35 will have edge-to-edge display [enforced by default](https://developer.android.com/about/versions/15/behavior-changes-15#edge-to-edge) on Android 15+. Google is _likely_ to mandate that app updates on the Play Store target SDK 35 starting on August 31, 2025. This assumption is based on the [previous years' requirements following a similar timeline](https://support.google.com/googleplay/android-developer/answer/11926878?sjid=11853000253346477363-EU#zippy=%2Care-there-any-exceptions-for-existing-apps-targeting-api-or-below:~:text=App%20update%20requirements).
29 |
30 | ### Consistency
31 |
32 | iOS has long used edge-to-edge displays, so adopting this design across all platforms ensures a consistent user experience. It also simplifies managing safe areas, eliminating the need for special cases specific to Android.
33 |
34 | ### Immersive mode
35 |
36 | [Immersive mode](https://developer.android.com/develop/ui/views/layout/immersive) allows you to hide the status and navigation bars, making it ideal for full-screen experiences. Currently, the built-in [`StatusBar`](https://reactnative.dev/docs/statusbar) component uses [`FLAG_FULLSCREEN`](https://developer.android.com/reference/android/view/WindowManager.LayoutParams#FLAG_FULLSCREEN), a flag that has been deprecated since Android 11.
37 |
38 | ## Installation
39 |
40 | ```bash
41 | $ npm i -S react-native-edge-to-edge
42 | # --- or ---
43 | $ yarn add react-native-edge-to-edge
44 | ```
45 |
46 | ### Pick a parent theme
47 |
48 | This library requires you to update the parent of your Android `AppTheme` to an edge-to-edge version. Don't worry, it's very easy to understand! You just need to choose a theme based on the current value:
49 |
50 | | If you currently have… | …you should use |
51 | | :--------------------------------------------------- | :----------------------------------------- |
52 | | `Theme.AppCompat.DayNight.NoActionBar` | `Theme.EdgeToEdge` |
53 | | `Theme.MaterialComponents.DayNight.NoActionBar` | `Theme.EdgeToEdge.Material2` |
54 | | `Theme.Material3.DayNight.NoActionBar` | `Theme.EdgeToEdge.Material3` |
55 | | `Theme.Material3.DynamicColors.DayNight.NoActionBar` | `Theme.EdgeToEdge.Material3.Dynamic` |
56 | | `Theme.AppCompat.Light.NoActionBar` | `Theme.EdgeToEdge.Light` |
57 | | `Theme.MaterialComponents.Light.NoActionBar` | `Theme.EdgeToEdge.Material2.Light` |
58 | | `Theme.Material3.Light.NoActionBar` | `Theme.EdgeToEdge.Material3.Light` |
59 | | `Theme.Material3.DynamicColors.Light.NoActionBar` | `Theme.EdgeToEdge.Material3.Dynamic.Light` |
60 |
61 | ### Expo
62 |
63 | Add the library plugin in your `app.json` config file and [create a new build](https://docs.expo.dev/develop/development-builds/create-a-build) 👷:
64 |
65 | ```json
66 | {
67 | "expo": {
68 | "plugins": [
69 | [
70 | "react-native-edge-to-edge",
71 | {
72 | "android": {
73 | "parentTheme": "Default",
74 | "enforceNavigationBarContrast": false
75 | }
76 | }
77 | ]
78 | ]
79 | }
80 | }
81 | ```
82 |
83 | _📌 The available plugins options are:_
84 |
85 | ```ts
86 | type ParentTheme =
87 | | "Default" // uses `Theme.EdgeToEdge`
88 | | "Material2" // uses `Theme.EdgeToEdge.Material2`
89 | | "Material3" // uses `Theme.EdgeToEdge.Material3`
90 | | "Material3.Dynamic" // uses `Theme.EdgeToEdge.Material3.Dynamic`
91 | | "Light" // uses `Theme.EdgeToEdge.Light`
92 | | "Material2.Light" // uses `Theme.EdgeToEdge.Material2.Light`
93 | | "Material3.Light" // uses `Theme.EdgeToEdge.Material3.Light`
94 | | "Material3.Dynamic.Light"; // uses `Theme.EdgeToEdge.Material3.Dynamic.Light`
95 |
96 | type Options = {
97 | android?: {
98 | // see the "Pick a parent theme" section
99 | parentTheme?: ParentTheme; // optional (default: `Default`)
100 | // see the "Transparent navigation bar" section
101 | enforceNavigationBarContrast?: boolean; // optional (default: `true`)
102 | };
103 | };
104 | ```
105 |
106 | > [!NOTE]
107 | > These configuration properties are not supported in the [Expo Go](https://expo.dev/go) sandbox app, use a [development build](https://docs.expo.dev/develop/development-builds/create-a-build/).
108 |
109 | ### Bare React Native
110 |
111 | Edit your `android/app/src/main/res/values/styles.xml` file to inherit from one of the provided themes:
112 |
113 | ```xml
114 |
115 |
116 |
121 |
122 | ```
123 |
124 | ## Considerations
125 |
126 | ### Transparent navigation bar
127 |
128 | By default, this library adopts [Android 15 defaults](https://developer.android.com/about/versions/15/behavior-changes-15#ux): a fully transparent status bar, a fully transparent gesture navigation bar, and a semi-opaque button navigation bar. To enforce full transparency in all cases, set the `enforceNavigationBarContrast` option to `false`.
129 | Note that by doing so, you will need to manage the navigation bar style (using `SystemBars`) in the same way you handle the status bar.
130 |
131 | ### Keyboard management
132 |
133 | Enabling edge-to-edge display disrupts Android keyboard management (`android:windowSoftInputMode="adjustResize"`), requiring an alternative solution. While [`KeyboardAvoidingView`](https://reactnative.dev/docs/keyboardavoidingview) is a viable option, we recommend using [react-native-keyboard-controller](https://github.com/kirillzyusko/react-native-keyboard-controller) for its enhanced capabilities.
134 |
135 | ### Safe area management
136 |
137 | Effective safe area management is essential to prevent content from being displayed behind transparent system bars. To achieve this, we highly recommend using [`react-native-safe-area-context`](https://github.com/th3rdwave/react-native-safe-area-context), a well-known and trusted library.
138 |
139 | ### Modal component quirks
140 |
141 | React native built-in [`Modal`](https://reactnative.dev/docs/modal) component runs in its own native context, so be sure to set both the `statusBarTranslucent` and `navigationBarTranslucent` props to `true`. However, we recommend using the [react-navigation modals](https://reactnavigation.org/docs/modal) or the [`expo-router` modal screens](https://docs.expo.dev/router/advanced/modals/#modal-screen-using-expo-router) instead.
142 |
143 | ## API
144 |
145 | ### SystemBars
146 |
147 | Using [`StatusBar`](https://reactnative.dev/docs/statusbar), [`expo-status-bar`](https://docs.expo.dev/versions/latest/sdk/status-bar), or [`expo-navigation-bar`](https://docs.expo.dev/versions/latest/sdk/navigation-bar/) in apps with edge-to-edge layout enabled may cause unexpected behavior, as they currently use [deprecated APIs](https://developer.android.com/about/versions/15/behavior-changes-15#deprecated-apis).
148 | To address this, we provide a component to replace them and manage your app's system bars: ``.
149 |
150 | ```tsx
151 | import { SystemBars } from "react-native-edge-to-edge";
152 |
153 | // "auto" is based on current color scheme (light -> dark content, dark -> light content)
154 | type Style = "auto" | "inverted" | "light" | "dark";
155 |
156 | type SystemBarsProps = {
157 | // set the color of the system bar content (as no effect on semi-opaque navigation bar)
158 | style?: Style | { statusBar?: Style; navigationBar?: Style };
159 | // hide system bars (the navigation bar cannot be hidden on iOS)
160 | hidden?: boolean | { statusBar?: boolean; navigationBar?: boolean };
161 | };
162 |
163 | const App = () => (
164 | <>
165 |
166 | {/* … */}
167 | >
168 | );
169 | ```
170 |
171 | #### SystemBars.pushStackEntry
172 |
173 | Push a `SystemBars` entry onto the stack. The return value should be passed to `popStackEntry` when complete.
174 |
175 | ```ts
176 | const entry: SystemBarsEntry = SystemBars.pushStackEntry(
177 | props /*: SystemBarsProps */,
178 | );
179 | ```
180 |
181 | #### SystemBars.popStackEntry
182 |
183 | Remove an existing `SystemBars` stack entry from the stack.
184 |
185 | ```ts
186 | SystemBars.popStackEntry(entry /*: SystemBarsEntry */);
187 | ```
188 |
189 | #### SystemBars.replaceStackEntry
190 |
191 | Replace an existing `SystemBars` stack entry with new props.
192 |
193 | ```ts
194 | const entry: SystemBarsEntry = SystemBars.replaceStackEntry(
195 | entry /*: SystemBarsEntry */,
196 | props /*: SystemBarsProps */,
197 | );
198 | ```
199 |
200 | #### SystemBars.setStyle
201 |
202 | Set the system bars style.
203 |
204 | ```ts
205 | SystemBars.setStyle(style /*: SystemBarsProps["style"] */);
206 | ```
207 |
208 | #### SystemBars.setHidden
209 |
210 | Show or hide the system bars.
211 |
212 | ```ts
213 | SystemBars.setHidden(style /*: SystemBarsProps["hidden"] */);
214 | ```
215 |
216 | ## Third-party libraries 🧩
217 |
218 | If you're an author and your package interferes with edge-to-edge, refer to the [`react-native-is-edge-to-edge` `README.md`](./react-native-is-edge-to-edge) for compatibility instructions.
219 |
220 | ## Troubleshooting 🤔
221 |
222 | #### The navigation bar style is erratic
223 |
224 | There's currently [an open issue](https://issuetracker.google.com/issues/346386744) with the Android 15 emulator image regarding the navigation bar style when it is is fully transparent. This issue does not occur on physical devices.
225 |
226 | #### The system bars stays opaque
227 |
228 | In recent months, support has been added across the React Native ecosystem. If you use any of the following libraries, make sure you're on the latest version:
229 |
230 | - `expo-router`
231 | - `galeria`
232 | - `react-native-avoid-softinput`
233 | - `react-native-bootsplash`
234 | - `react-native-bottom-tabs`
235 | - `react-native-keyboard-controller`
236 | - `react-native-reanimated`
237 | - `react-native-screens`
238 | - `react-native-true-sheet`
239 | - `react-native-unistyles (v3)`
240 |
241 | Make also sure to replace all occurrences of the built-in `StatusBar`, [`expo-status-bar`](https://docs.expo.dev/versions/latest/sdk/status-bar) and [`expo-navigation-bar`](https://docs.expo.dev/versions/latest/sdk/navigation-bar/) with `SystemBars`.
242 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.safeExtGet = {prop, fallback ->
3 | rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
4 | }
5 | repositories {
6 | google()
7 | gradlePluginPortal()
8 | }
9 | dependencies {
10 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet("kotlinVersion", "1.8.0")}")
11 | classpath("com.android.tools.build:gradle:8.1.1")
12 | }
13 | }
14 |
15 | def isNewArchitectureEnabled() {
16 | return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
17 | }
18 |
19 | apply plugin: "com.android.library"
20 | apply plugin: "kotlin-android"
21 |
22 | if (isNewArchitectureEnabled()) {
23 | apply plugin: "com.facebook.react"
24 | }
25 |
26 | android {
27 | buildToolsVersion safeExtGet("buildToolsVersion", "34.0.0")
28 | compileSdkVersion safeExtGet("compileSdkVersion", 34)
29 |
30 | if (project.android.hasProperty("namespace")) {
31 | namespace "com.zoontek.rnedgetoedge"
32 |
33 | buildFeatures {
34 | buildConfig true
35 | }
36 | sourceSets {
37 | main {
38 | manifest.srcFile "src/main/AndroidManifestNew.xml"
39 | }
40 | }
41 | }
42 | defaultConfig {
43 | buildConfigField("boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString())
44 | minSdkVersion safeExtGet("minSdkVersion", 23)
45 | targetSdkVersion safeExtGet("targetSdkVersion", 34)
46 | }
47 | lintOptions {
48 | abortOnError false
49 | }
50 | sourceSets {
51 | main {
52 | if (isNewArchitectureEnabled()) {
53 | java.srcDirs += ["src/newarch"]
54 | } else {
55 | java.srcDirs += ["src/oldarch"]
56 | }
57 | }
58 | }
59 | }
60 |
61 | repositories {
62 | maven {
63 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
64 | url("$rootDir/../node_modules/react-native/android")
65 | }
66 | mavenCentral()
67 | google()
68 | }
69 |
70 | dependencies {
71 | //noinspection GradleDynamicVersion
72 | implementation "com.facebook.react:react-native:+" // From node_modules
73 | implementation "com.google.android.material:material:${safeExtGet("materialVersion", "1.12.0")}"
74 | }
75 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifestNew.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/android/src/main/java/com/zoontek/rnedgetoedge/EdgeToEdgeModuleImpl.kt:
--------------------------------------------------------------------------------
1 | package com.zoontek.rnedgetoedge
2 |
3 | import android.os.Build.VERSION
4 | import android.os.Build.VERSION_CODES
5 |
6 | import android.app.Activity
7 | import android.content.res.Configuration
8 | import android.graphics.Color
9 | import android.util.TypedValue
10 | import android.view.Window
11 | import android.view.WindowManager
12 |
13 | import androidx.core.view.WindowCompat
14 | import androidx.core.view.WindowInsetsCompat
15 | import androidx.core.view.WindowInsetsControllerCompat
16 |
17 | import com.facebook.common.logging.FLog
18 | import com.facebook.react.bridge.ReactApplicationContext
19 | import com.facebook.react.common.ReactConstants
20 |
21 | internal val LightNavigationBarColor = Color.argb(0xe6, 0xFF, 0xFF, 0xFF)
22 | internal val DarkNavigationBarColor = Color.argb(0x80, 0x1b, 0x1b, 0x1b)
23 |
24 | object EdgeToEdgeModuleImpl {
25 | const val NAME = "RNEdgeToEdge"
26 |
27 | private const val NO_ACTIVITY_ERROR = "$NAME: Ignored system bars change, current activity is null."
28 | private val boolAttributes = mutableMapOf()
29 |
30 | private var statusBarHidden = false
31 | private var navigationBarHidden = false
32 |
33 | private fun resolveBoolAttribute(activity: Activity, resId: Int): Boolean =
34 | boolAttributes.getOrPut(resId) {
35 | val value = TypedValue()
36 | activity.theme.resolveAttribute(resId, value, true) && value.data != 0
37 | }
38 |
39 | private fun isDefaultLightSystemBars(activity: Activity): Boolean =
40 | resolveBoolAttribute(activity, R.attr.enforceSystemBarsLightTheme) ||
41 | activity.window.decorView.resources.configuration.uiMode and
42 | Configuration.UI_MODE_NIGHT_MASK != Configuration.UI_MODE_NIGHT_YES
43 |
44 | private fun isNavigationBarTransparent(activity: Activity): Boolean =
45 | !resolveBoolAttribute(activity, R.attr.enforceNavigationBarContrast)
46 |
47 | // re-apply statusBarHidden / navigationBarHidden each time we instantiate a WindowInsetsControllerCompat
48 | // see https://github.com/zoontek/react-native-edge-to-edge/issues/66
49 | private fun initInsetsController(window: Window): WindowInsetsControllerCompat =
50 | WindowInsetsControllerCompat(window, window.decorView).apply {
51 | systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
52 |
53 | when (statusBarHidden) {
54 | true -> hide(WindowInsetsCompat.Type.statusBars())
55 | else -> show(WindowInsetsCompat.Type.statusBars())
56 | }
57 | when (navigationBarHidden) {
58 | true -> hide(WindowInsetsCompat.Type.navigationBars())
59 | else -> show(WindowInsetsCompat.Type.navigationBars())
60 | }
61 | }
62 |
63 | @Suppress("DEPRECATION")
64 | fun applyEdgeToEdge(reactContext: ReactApplicationContext?) {
65 | val activity = reactContext?.currentActivity
66 | ?: return FLog.w(ReactConstants.TAG, "$NAME: Ignored, current activity is null.")
67 |
68 | activity.runOnUiThread {
69 | val window = activity.window
70 | val insetsController = initInsetsController(window)
71 |
72 | WindowCompat.setDecorFitsSystemWindows(window, false)
73 |
74 | window.statusBarColor = Color.TRANSPARENT
75 |
76 | if (VERSION.SDK_INT >= VERSION_CODES.O_MR1 && isNavigationBarTransparent(activity)) {
77 | window.navigationBarColor = Color.TRANSPARENT
78 |
79 | if (VERSION.SDK_INT >= VERSION_CODES.Q) {
80 | window.isStatusBarContrastEnforced = false
81 | window.isNavigationBarContrastEnforced = false
82 | }
83 | } else {
84 | val light = isDefaultLightSystemBars(activity)
85 |
86 | window.navigationBarColor = when {
87 | VERSION.SDK_INT >= VERSION_CODES.Q -> Color.TRANSPARENT
88 | VERSION.SDK_INT >= VERSION_CODES.O_MR1 && light -> LightNavigationBarColor
89 | else -> DarkNavigationBarColor
90 | }
91 |
92 | insetsController.run {
93 | isAppearanceLightNavigationBars = when {
94 | VERSION.SDK_INT >= VERSION_CODES.O_MR1 -> light
95 | else -> false
96 | }
97 | }
98 |
99 | if (VERSION.SDK_INT >= VERSION_CODES.Q) {
100 | window.isStatusBarContrastEnforced = false
101 | window.isNavigationBarContrastEnforced = true
102 | }
103 | }
104 |
105 | if (VERSION.SDK_INT >= VERSION_CODES.P) {
106 | window.attributes.layoutInDisplayCutoutMode = when {
107 | VERSION.SDK_INT >= VERSION_CODES.R -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
108 | else -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
109 | }
110 | }
111 | }
112 | }
113 |
114 | fun setStatusBarStyle(reactContext: ReactApplicationContext?, style: String) {
115 | val activity = reactContext?.currentActivity
116 | ?: return FLog.w(ReactConstants.TAG, NO_ACTIVITY_ERROR)
117 |
118 | activity.runOnUiThread {
119 | initInsetsController(activity.window).run {
120 | isAppearanceLightStatusBars = when (style) {
121 | "light-content" -> false
122 | "dark-content" -> true
123 | else -> isDefaultLightSystemBars(activity)
124 | }
125 | }
126 | }
127 | }
128 |
129 | fun setNavigationBarStyle(reactContext: ReactApplicationContext?, style: String) {
130 | val activity = reactContext?.currentActivity
131 | ?: return FLog.w(ReactConstants.TAG, NO_ACTIVITY_ERROR)
132 |
133 | if (VERSION.SDK_INT >= VERSION_CODES.O_MR1 && isNavigationBarTransparent(activity)) {
134 | activity.runOnUiThread {
135 | initInsetsController(activity.window).run {
136 | isAppearanceLightNavigationBars = when (style) {
137 | "light-content" -> false
138 | "dark-content" -> true
139 | else -> isDefaultLightSystemBars(activity)
140 | }
141 | }
142 | }
143 | }
144 | }
145 |
146 | fun setStatusBarHidden(reactContext: ReactApplicationContext?, hidden: Boolean) {
147 | val activity = reactContext?.currentActivity
148 | ?: return FLog.w(ReactConstants.TAG, NO_ACTIVITY_ERROR)
149 |
150 | statusBarHidden = hidden
151 | activity.runOnUiThread { initInsetsController(activity.window) }
152 | }
153 |
154 | fun setNavigationBarHidden(reactContext: ReactApplicationContext?, hidden: Boolean) {
155 | val activity = reactContext?.currentActivity
156 | ?: return FLog.w(ReactConstants.TAG, NO_ACTIVITY_ERROR)
157 |
158 | navigationBarHidden = hidden
159 | activity.runOnUiThread { initInsetsController(activity.window) }
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/android/src/main/java/com/zoontek/rnedgetoedge/EdgeToEdgePackage.kt:
--------------------------------------------------------------------------------
1 | package com.zoontek.rnedgetoedge
2 |
3 | import com.facebook.react.BaseReactPackage
4 | import com.facebook.react.bridge.NativeModule
5 | import com.facebook.react.bridge.ReactApplicationContext
6 | import com.facebook.react.module.model.ReactModuleInfo
7 | import com.facebook.react.module.model.ReactModuleInfoProvider
8 |
9 | class EdgeToEdgePackage : BaseReactPackage() {
10 | override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
11 | return when (name) {
12 | EdgeToEdgeModuleImpl.NAME -> EdgeToEdgeModule(reactContext)
13 | else -> null
14 | }
15 | }
16 |
17 | override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
18 | return ReactModuleInfoProvider {
19 | val isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
20 |
21 | val moduleInfo = ReactModuleInfo(
22 | EdgeToEdgeModuleImpl.NAME,
23 | EdgeToEdgeModuleImpl.NAME,
24 | false,
25 | true,
26 | true,
27 | false,
28 | isTurboModule
29 | )
30 |
31 | mapOf(
32 | EdgeToEdgeModuleImpl.NAME to moduleInfo
33 | )
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/android/src/main/res/values-night-v27/bools.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | false
4 |
5 |
--------------------------------------------------------------------------------
/android/src/main/res/values-night/bools.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | false
4 |
5 |
--------------------------------------------------------------------------------
/android/src/main/res/values-v27/bools.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 |
5 |
--------------------------------------------------------------------------------
/android/src/main/res/values-v27/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @android:color/transparent
4 |
5 |
--------------------------------------------------------------------------------
/android/src/main/res/values-v27/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
13 |
17 |
18 |
22 |
23 |
27 |
28 |
32 |
33 |
37 |
38 |
42 |
43 |
--------------------------------------------------------------------------------
/android/src/main/res/values-v29/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
16 |
17 |
23 |
24 |
30 |
31 |
37 |
38 |
44 |
45 |
51 |
52 |
58 |
59 |
--------------------------------------------------------------------------------
/android/src/main/res/values-v30/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
16 |
17 |
23 |
24 |
30 |
31 |
37 |
38 |
44 |
45 |
51 |
52 |
58 |
59 |
--------------------------------------------------------------------------------
/android/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/src/main/res/values/bools.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 |
5 |
--------------------------------------------------------------------------------
/android/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | #801b1b1b
6 |
7 |
--------------------------------------------------------------------------------
/android/src/main/res/values/public.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/android/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
24 |
25 |
35 |
36 |
46 |
47 |
57 |
58 |
68 |
69 |
79 |
80 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/android/src/newarch/com/zoontek/rnedgetoedge/EdgeToEdgeModule.kt:
--------------------------------------------------------------------------------
1 | package com.zoontek.rnedgetoedge
2 |
3 | import com.facebook.react.bridge.LifecycleEventListener
4 | import com.facebook.react.bridge.ReactApplicationContext
5 | import com.facebook.react.module.annotations.ReactModule
6 |
7 | @ReactModule(name = EdgeToEdgeModuleImpl.NAME)
8 | class EdgeToEdgeModule(reactContext: ReactApplicationContext) :
9 | NativeEdgeToEdgeModuleSpec(reactContext), LifecycleEventListener {
10 |
11 | init {
12 | reactApplicationContext.addLifecycleEventListener(this)
13 | }
14 |
15 | override fun invalidate() {
16 | reactApplicationContext.removeLifecycleEventListener(this)
17 | }
18 |
19 | override fun getName(): String {
20 | return EdgeToEdgeModuleImpl.NAME
21 | }
22 |
23 | override fun onHostResume() {
24 | EdgeToEdgeModuleImpl.applyEdgeToEdge(reactApplicationContext)
25 | }
26 |
27 | override fun onHostPause() {}
28 |
29 | override fun onHostDestroy() {}
30 |
31 | override fun onColorSchemeChange() {
32 | EdgeToEdgeModuleImpl.applyEdgeToEdge(reactApplicationContext)
33 | }
34 |
35 | override fun setStatusBarStyle(style: String) {
36 | EdgeToEdgeModuleImpl.setStatusBarStyle(reactApplicationContext, style)
37 | }
38 |
39 | override fun setNavigationBarStyle(style: String) {
40 | EdgeToEdgeModuleImpl.setNavigationBarStyle(reactApplicationContext, style)
41 | }
42 |
43 | override fun setStatusBarHidden(hidden: Boolean) {
44 | EdgeToEdgeModuleImpl.setStatusBarHidden(reactApplicationContext, hidden)
45 | }
46 |
47 | override fun setNavigationBarHidden(hidden: Boolean) {
48 | EdgeToEdgeModuleImpl.setNavigationBarHidden(reactApplicationContext, hidden)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/android/src/oldarch/com/zoontek/rnedgetoedge/EdgeToEdgeModule.kt:
--------------------------------------------------------------------------------
1 | package com.zoontek.rnedgetoedge
2 |
3 | import com.facebook.react.bridge.LifecycleEventListener
4 | import com.facebook.react.bridge.ReactApplicationContext
5 | import com.facebook.react.bridge.ReactContextBaseJavaModule
6 | import com.facebook.react.bridge.ReactMethod
7 | import com.facebook.react.module.annotations.ReactModule
8 |
9 | @ReactModule(name = EdgeToEdgeModuleImpl.NAME)
10 | class EdgeToEdgeModule(reactContext: ReactApplicationContext) :
11 | ReactContextBaseJavaModule(reactContext), LifecycleEventListener {
12 |
13 | init {
14 | reactApplicationContext.addLifecycleEventListener(this)
15 | }
16 |
17 | override fun invalidate() {
18 | reactApplicationContext.removeLifecycleEventListener(this)
19 | }
20 |
21 | override fun getName(): String {
22 | return EdgeToEdgeModuleImpl.NAME
23 | }
24 |
25 | override fun onHostResume() {
26 | EdgeToEdgeModuleImpl.applyEdgeToEdge(reactApplicationContext)
27 | }
28 |
29 | override fun onHostPause() {}
30 |
31 | override fun onHostDestroy() {}
32 |
33 | @ReactMethod
34 | fun onColorSchemeChange() {
35 | EdgeToEdgeModuleImpl.applyEdgeToEdge(reactApplicationContext)
36 | }
37 |
38 | @ReactMethod
39 | fun setStatusBarStyle(style: String) {
40 | EdgeToEdgeModuleImpl.setStatusBarStyle(reactApplicationContext, style)
41 | }
42 |
43 | @ReactMethod
44 | fun setNavigationBarStyle(style: String) {
45 | EdgeToEdgeModuleImpl.setNavigationBarStyle(reactApplicationContext, style)
46 | }
47 |
48 | @ReactMethod
49 | fun setStatusBarHidden(hidden: Boolean) {
50 | EdgeToEdgeModuleImpl.setStatusBarHidden(reactApplicationContext, hidden)
51 | }
52 |
53 | @ReactMethod
54 | fun setNavigationBarHidden(hidden: Boolean) {
55 | EdgeToEdgeModuleImpl.setNavigationBarHidden(reactApplicationContext, hidden)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app.plugin.js:
--------------------------------------------------------------------------------
1 | module.exports = require("./dist/commonjs/expo");
2 |
--------------------------------------------------------------------------------
/docs/expo.svg:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/docs/logo.svg:
--------------------------------------------------------------------------------
1 |
27 |
--------------------------------------------------------------------------------
/example/.bundle/config:
--------------------------------------------------------------------------------
1 | BUNDLE_PATH: "vendor/bundle"
2 | BUNDLE_FORCE_RUBY_PLATFORM: 1
3 |
--------------------------------------------------------------------------------
/example/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
4 | ruby ">= 2.6.10"
5 |
6 | # Exclude problematic versions of cocoapods and activesupport that causes build failures.
7 | gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1'
8 | gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0'
9 | gem 'xcodeproj', '< 1.26.0'
10 | gem 'concurrent-ruby', '< 1.3.4'
11 |
12 | # Ruby 3.4.0 has removed some libraries from the standard library.
13 | gem 'bigdecimal'
14 | gem 'logger'
15 | gem 'benchmark'
16 | gem 'mutex_m'
17 |
--------------------------------------------------------------------------------
/example/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | CFPropertyList (3.0.7)
5 | base64
6 | nkf
7 | rexml
8 | activesupport (7.2.2.1)
9 | base64
10 | benchmark (>= 0.3)
11 | bigdecimal
12 | concurrent-ruby (~> 1.0, >= 1.3.1)
13 | connection_pool (>= 2.2.5)
14 | drb
15 | i18n (>= 1.6, < 2)
16 | logger (>= 1.4.2)
17 | minitest (>= 5.1)
18 | securerandom (>= 0.3)
19 | tzinfo (~> 2.0, >= 2.0.5)
20 | addressable (2.8.7)
21 | public_suffix (>= 2.0.2, < 7.0)
22 | algoliasearch (1.27.5)
23 | httpclient (~> 2.8, >= 2.8.3)
24 | json (>= 1.5.1)
25 | atomos (0.1.3)
26 | base64 (0.2.0)
27 | benchmark (0.4.0)
28 | bigdecimal (3.1.9)
29 | claide (1.1.0)
30 | cocoapods (1.15.2)
31 | addressable (~> 2.8)
32 | claide (>= 1.0.2, < 2.0)
33 | cocoapods-core (= 1.15.2)
34 | cocoapods-deintegrate (>= 1.0.3, < 2.0)
35 | cocoapods-downloader (>= 2.1, < 3.0)
36 | cocoapods-plugins (>= 1.0.0, < 2.0)
37 | cocoapods-search (>= 1.0.0, < 2.0)
38 | cocoapods-trunk (>= 1.6.0, < 2.0)
39 | cocoapods-try (>= 1.1.0, < 2.0)
40 | colored2 (~> 3.1)
41 | escape (~> 0.0.4)
42 | fourflusher (>= 2.3.0, < 3.0)
43 | gh_inspector (~> 1.0)
44 | molinillo (~> 0.8.0)
45 | nap (~> 1.0)
46 | ruby-macho (>= 2.3.0, < 3.0)
47 | xcodeproj (>= 1.23.0, < 2.0)
48 | cocoapods-core (1.15.2)
49 | activesupport (>= 5.0, < 8)
50 | addressable (~> 2.8)
51 | algoliasearch (~> 1.0)
52 | concurrent-ruby (~> 1.1)
53 | fuzzy_match (~> 2.0.4)
54 | nap (~> 1.0)
55 | netrc (~> 0.11)
56 | public_suffix (~> 4.0)
57 | typhoeus (~> 1.0)
58 | cocoapods-deintegrate (1.0.5)
59 | cocoapods-downloader (2.1)
60 | cocoapods-plugins (1.0.0)
61 | nap
62 | cocoapods-search (1.0.1)
63 | cocoapods-trunk (1.6.0)
64 | nap (>= 0.8, < 2.0)
65 | netrc (~> 0.11)
66 | cocoapods-try (1.2.0)
67 | colored2 (3.1.2)
68 | concurrent-ruby (1.3.3)
69 | connection_pool (2.5.0)
70 | drb (2.2.1)
71 | escape (0.0.4)
72 | ethon (0.16.0)
73 | ffi (>= 1.15.0)
74 | ffi (1.17.1)
75 | fourflusher (2.3.1)
76 | fuzzy_match (2.0.4)
77 | gh_inspector (1.1.3)
78 | httpclient (2.9.0)
79 | mutex_m
80 | i18n (1.14.7)
81 | concurrent-ruby (~> 1.0)
82 | json (2.10.2)
83 | logger (1.7.0)
84 | minitest (5.25.5)
85 | molinillo (0.8.0)
86 | mutex_m (0.3.0)
87 | nanaimo (0.3.0)
88 | nap (1.1.0)
89 | netrc (0.11.0)
90 | nkf (0.2.0)
91 | public_suffix (4.0.7)
92 | rexml (3.4.1)
93 | ruby-macho (2.5.1)
94 | securerandom (0.4.1)
95 | typhoeus (1.4.1)
96 | ethon (>= 0.9.0)
97 | tzinfo (2.0.6)
98 | concurrent-ruby (~> 1.0)
99 | xcodeproj (1.25.1)
100 | CFPropertyList (>= 2.3.3, < 4.0)
101 | atomos (~> 0.1.3)
102 | claide (>= 1.0.2, < 2.0)
103 | colored2 (~> 3.1)
104 | nanaimo (~> 0.3.0)
105 | rexml (>= 3.3.6, < 4.0)
106 |
107 | PLATFORMS
108 | ruby
109 |
110 | DEPENDENCIES
111 | activesupport (>= 6.1.7.5, != 7.1.0)
112 | benchmark
113 | bigdecimal
114 | cocoapods (>= 1.13, != 1.15.1, != 1.15.0)
115 | concurrent-ruby (< 1.3.4)
116 | logger
117 | mutex_m
118 | xcodeproj (< 1.26.0)
119 |
120 | RUBY VERSION
121 | ruby 3.3.4p94
122 |
123 | BUNDLED WITH
124 | 2.6.3
125 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.application"
2 | apply plugin: "org.jetbrains.kotlin.android"
3 | apply plugin: "com.facebook.react"
4 |
5 | /**
6 | * This is the configuration block to customize your React Native Android app.
7 | * By default you don't need to apply any configuration, just uncomment the lines you need.
8 | */
9 | react {
10 | /* Folders */
11 | // The root of your project, i.e. where "package.json" lives. Default is '../..'
12 | // root = file("../../")
13 | // The folder where the react-native NPM package is. Default is ../../node_modules/react-native
14 | // reactNativeDir = file("../../node_modules/react-native")
15 | // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
16 | // codegenDir = file("../../node_modules/@react-native/codegen")
17 | // The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js
18 | // cliFile = file("../../node_modules/react-native/cli.js")
19 |
20 | /* Variants */
21 | // The list of variants to that are debuggable. For those we're going to
22 | // skip the bundling of the JS bundle and the assets. By default is just 'debug'.
23 | // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
24 | // debuggableVariants = ["liteDebug", "prodDebug"]
25 |
26 | /* Bundling */
27 | // A list containing the node command and its flags. Default is just 'node'.
28 | // nodeExecutableAndArgs = ["node"]
29 | //
30 | // The command to run when bundling. By default is 'bundle'
31 | // bundleCommand = "ram-bundle"
32 | //
33 | // The path to the CLI configuration file. Default is empty.
34 | // bundleConfig = file(../rn-cli.config.js)
35 | //
36 | // The name of the generated asset file containing your JS bundle
37 | // bundleAssetName = "MyApplication.android.bundle"
38 | //
39 | // The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
40 | // entryFile = file("../js/MyApplication.android.js")
41 | //
42 | // A list of extra flags to pass to the 'bundle' commands.
43 | // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
44 | // extraPackagerArgs = []
45 |
46 | /* Hermes Commands */
47 | // The hermes compiler command to run. By default it is 'hermesc'
48 | // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
49 | //
50 | // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
51 | // hermesFlags = ["-O", "-output-source-map"]
52 |
53 | /* Autolinking */
54 | autolinkLibrariesWithApp()
55 | }
56 |
57 | /**
58 | * Set this to true to Run Proguard on Release builds to minify the Java bytecode.
59 | */
60 | def enableProguardInReleaseBuilds = false
61 |
62 | /**
63 | * The preferred build flavor of JavaScriptCore (JSC)
64 | *
65 | * For example, to use the international variant, you can use:
66 | * `def jscFlavor = io.github.react-native-community:jsc-android-intl:2026004.+`
67 | *
68 | * The international variant includes ICU i18n library and necessary data
69 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
70 | * give correct results when using with locales other than en-US. Note that
71 | * this variant is about 6MiB larger per architecture than default.
72 | */
73 | def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'
74 |
75 | android {
76 | ndkVersion rootProject.ext.ndkVersion
77 | buildToolsVersion rootProject.ext.buildToolsVersion
78 | compileSdk rootProject.ext.compileSdkVersion
79 |
80 | namespace "com.rnedgetoedgeexample"
81 | defaultConfig {
82 | applicationId "com.rnedgetoedgeexample"
83 | minSdkVersion rootProject.ext.minSdkVersion
84 | targetSdkVersion rootProject.ext.targetSdkVersion
85 | versionCode 1
86 | versionName "1.0"
87 | }
88 | signingConfigs {
89 | debug {
90 | storeFile file('debug.keystore')
91 | storePassword 'android'
92 | keyAlias 'androiddebugkey'
93 | keyPassword 'android'
94 | }
95 | }
96 | buildTypes {
97 | debug {
98 | signingConfig signingConfigs.debug
99 | }
100 | release {
101 | // Caution! In production, you need to generate your own keystore file.
102 | // see https://reactnative.dev/docs/signed-apk-android.
103 | signingConfig signingConfigs.debug
104 | minifyEnabled enableProguardInReleaseBuilds
105 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
106 | }
107 | }
108 | }
109 |
110 | dependencies {
111 | // The version of react-native is set by the React Native Gradle Plugin
112 | implementation("com.facebook.react:react-android")
113 |
114 | if (hermesEnabled.toBoolean()) {
115 | implementation("com.facebook.react:hermes-android")
116 | } else {
117 | implementation jscFlavor
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/example/android/app/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zoontek/react-native-edge-to-edge/35b12323944b786c696f2107eb7f65bc944859b6/example/android/app/debug.keystore
--------------------------------------------------------------------------------
/example/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
13 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/rnedgetoedgeexample/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.rnedgetoedgeexample
2 |
3 | import android.os.Bundle
4 |
5 | import com.facebook.react.ReactActivity
6 | import com.facebook.react.ReactActivityDelegate
7 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
8 | import com.facebook.react.defaults.DefaultReactActivityDelegate
9 |
10 | class MainActivity : ReactActivity() {
11 |
12 | /**
13 | * Returns the name of the main component registered from JavaScript. This is used to schedule
14 | * rendering of the component.
15 | */
16 | override fun getMainComponentName(): String = "RNEdgeToEdgeExample"
17 |
18 | /**
19 | * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
20 | * which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
21 | */
22 | override fun createReactActivityDelegate(): ReactActivityDelegate =
23 | DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
24 |
25 | override fun onCreate(savedInstanceState: Bundle?) {
26 | super.onCreate(null)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/rnedgetoedgeexample/MainApplication.kt:
--------------------------------------------------------------------------------
1 | package com.rnedgetoedgeexample
2 |
3 | import android.app.Application
4 | import com.facebook.react.PackageList
5 | import com.facebook.react.ReactApplication
6 | import com.facebook.react.ReactHost
7 | import com.facebook.react.ReactNativeHost
8 | import com.facebook.react.ReactPackage
9 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
10 | import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
11 | import com.facebook.react.defaults.DefaultReactNativeHost
12 | import com.facebook.react.soloader.OpenSourceMergedSoMapping
13 | import com.facebook.soloader.SoLoader
14 |
15 | class MainApplication : Application(), ReactApplication {
16 |
17 | override val reactNativeHost: ReactNativeHost =
18 | object : DefaultReactNativeHost(this) {
19 | override fun getPackages(): List =
20 | PackageList(this).packages.apply {
21 | // Packages that cannot be autolinked yet can be added manually here, for example:
22 | // add(MyReactNativePackage())
23 | }
24 |
25 | override fun getJSMainModuleName(): String = "index"
26 |
27 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
28 |
29 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
30 | override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
31 | }
32 |
33 | override val reactHost: ReactHost
34 | get() = getDefaultReactHost(applicationContext, reactNativeHost)
35 |
36 | override fun onCreate() {
37 | super.onCreate()
38 | SoLoader.init(this, OpenSourceMergedSoMapping)
39 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
40 | // If you opted-in for the New Architecture, we load the native entry point for this app.
41 | load()
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/rn_edit_text_material.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
22 |
23 |
24 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zoontek/react-native-edge-to-edge/35b12323944b786c696f2107eb7f65bc944859b6/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zoontek/react-native-edge-to-edge/35b12323944b786c696f2107eb7f65bc944859b6/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zoontek/react-native-edge-to-edge/35b12323944b786c696f2107eb7f65bc944859b6/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zoontek/react-native-edge-to-edge/35b12323944b786c696f2107eb7f65bc944859b6/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zoontek/react-native-edge-to-edge/35b12323944b786c696f2107eb7f65bc944859b6/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zoontek/react-native-edge-to-edge/35b12323944b786c696f2107eb7f65bc944859b6/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zoontek/react-native-edge-to-edge/35b12323944b786c696f2107eb7f65bc944859b6/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zoontek/react-native-edge-to-edge/35b12323944b786c696f2107eb7f65bc944859b6/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zoontek/react-native-edge-to-edge/35b12323944b786c696f2107eb7f65bc944859b6/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zoontek/react-native-edge-to-edge/35b12323944b786c696f2107eb7f65bc944859b6/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | RNEdgeToEdgeExample
3 |
4 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext {
3 | buildToolsVersion = "35.0.0"
4 | minSdkVersion = 24
5 | compileSdkVersion = 35
6 | targetSdkVersion = 35
7 | ndkVersion = "27.1.12297006"
8 | kotlinVersion = "2.0.21"
9 | }
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 | dependencies {
15 | classpath("com.android.tools.build:gradle")
16 | classpath("com.facebook.react:react-native-gradle-plugin")
17 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
18 | }
19 | }
20 |
21 | apply plugin: "com.facebook.react.rootproject"
22 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | # AndroidX package structure to make it clearer which packages are bundled with the
21 | # Android operating system, and which are packaged with your app's APK
22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
23 | android.useAndroidX=true
24 |
25 | # Use this property to specify which architecture you want to build.
26 | # You can also override it from the CLI using
27 | # ./gradlew -PreactNativeArchitectures=x86_64
28 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
29 |
30 | # Use this property to enable support to the new architecture.
31 | # This will allow you to use TurboModules and the Fabric render in
32 | # your application. You should enable this flag either if you want
33 | # to write custom TurboModules/Fabric components OR use libraries that
34 | # are providing them.
35 | newArchEnabled=true
36 |
37 | # Use this property to enable or disable the Hermes JS engine.
38 | # If set to false, you will be using JSC instead.
39 | hermesEnabled=true
40 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zoontek/react-native-edge-to-edge/35b12323944b786c696f2107eb7f65bc944859b6/example/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/example/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 | # SPDX-License-Identifier: Apache-2.0
19 | #
20 |
21 | ##############################################################################
22 | #
23 | # Gradle start up script for POSIX generated by Gradle.
24 | #
25 | # Important for running:
26 | #
27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
28 | # noncompliant, but you have some other compliant shell such as ksh or
29 | # bash, then to run this script, type that shell name before the whole
30 | # command line, like:
31 | #
32 | # ksh Gradle
33 | #
34 | # Busybox and similar reduced shells will NOT work, because this script
35 | # requires all of these POSIX shell features:
36 | # * functions;
37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
39 | # * compound commands having a testable exit status, especially «case»;
40 | # * various built-in commands including «command», «set», and «ulimit».
41 | #
42 | # Important for patching:
43 | #
44 | # (2) This script targets any POSIX shell, so it avoids extensions provided
45 | # by Bash, Ksh, etc; in particular arrays are avoided.
46 | #
47 | # The "traditional" practice of packing multiple parameters into a
48 | # space-separated string is a well documented source of bugs and security
49 | # problems, so this is (mostly) avoided, by progressively accumulating
50 | # options in "$@", and eventually passing that to Java.
51 | #
52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
54 | # see the in-line comments for details.
55 | #
56 | # There are tweaks for specific operating systems such as AIX, CygWin,
57 | # Darwin, MinGW, and NonStop.
58 | #
59 | # (3) This script is generated from the Groovy template
60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
61 | # within the Gradle project.
62 | #
63 | # You can find Gradle at https://github.com/gradle/gradle/.
64 | #
65 | ##############################################################################
66 |
67 | # Attempt to set APP_HOME
68 |
69 | # Resolve links: $0 may be a link
70 | app_path=$0
71 |
72 | # Need this for daisy-chained symlinks.
73 | while
74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
75 | [ -h "$app_path" ]
76 | do
77 | ls=$( ls -ld "$app_path" )
78 | link=${ls#*' -> '}
79 | case $link in #(
80 | /*) app_path=$link ;; #(
81 | *) app_path=$APP_HOME$link ;;
82 | esac
83 | done
84 |
85 | # This is normally unused
86 | # shellcheck disable=SC2034
87 | APP_BASE_NAME=${0##*/}
88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | if ! command -v java >/dev/null 2>&1
137 | then
138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
139 |
140 | Please set the JAVA_HOME variable in your environment to match the
141 | location of your Java installation."
142 | fi
143 | fi
144 |
145 | # Increase the maximum file descriptors if we can.
146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
147 | case $MAX_FD in #(
148 | max*)
149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
150 | # shellcheck disable=SC2039,SC3045
151 | MAX_FD=$( ulimit -H -n ) ||
152 | warn "Could not query maximum file descriptor limit"
153 | esac
154 | case $MAX_FD in #(
155 | '' | soft) :;; #(
156 | *)
157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
158 | # shellcheck disable=SC2039,SC3045
159 | ulimit -n "$MAX_FD" ||
160 | warn "Could not set maximum file descriptor limit to $MAX_FD"
161 | esac
162 | fi
163 |
164 | # Collect all arguments for the java command, stacking in reverse order:
165 | # * args from the command line
166 | # * the main class name
167 | # * -classpath
168 | # * -D...appname settings
169 | # * --module-path (only if needed)
170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
171 |
172 | # For Cygwin or MSYS, switch paths to Windows format before running java
173 | if "$cygwin" || "$msys" ; then
174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
176 |
177 | JAVACMD=$( cygpath --unix "$JAVACMD" )
178 |
179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
180 | for arg do
181 | if
182 | case $arg in #(
183 | -*) false ;; # don't mess with options #(
184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
185 | [ -e "$t" ] ;; #(
186 | *) false ;;
187 | esac
188 | then
189 | arg=$( cygpath --path --ignore --mixed "$arg" )
190 | fi
191 | # Roll the args list around exactly as many times as the number of
192 | # args, so each arg winds up back in the position where it started, but
193 | # possibly modified.
194 | #
195 | # NB: a `for` loop captures its iteration list before it begins, so
196 | # changing the positional parameters here affects neither the number of
197 | # iterations, nor the values presented in `arg`.
198 | shift # remove old arg
199 | set -- "$@" "$arg" # push replacement arg
200 | done
201 | fi
202 |
203 |
204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
205 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
206 |
207 | # Collect all arguments for the java command:
208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
209 | # and any embedded shellness will be escaped.
210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
211 | # treated as '${Hostname}' itself on the command line.
212 |
213 | set -- \
214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
215 | -classpath "$CLASSPATH" \
216 | org.gradle.wrapper.GradleWrapperMain \
217 | "$@"
218 |
219 | # Stop when "xargs" is not available.
220 | if ! command -v xargs >/dev/null 2>&1
221 | then
222 | die "xargs is not available"
223 | fi
224 |
225 | # Use "xargs" to parse quoted args.
226 | #
227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
228 | #
229 | # In Bash we could simply go:
230 | #
231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
232 | # set -- "${ARGS[@]}" "$@"
233 | #
234 | # but POSIX shell has neither arrays nor command substitution, so instead we
235 | # post-process each arg (as a line of input to sed) to backslash-escape any
236 | # character that might be a shell metacharacter, then use eval to reverse
237 | # that process (while maintaining the separation between arguments), and wrap
238 | # the whole thing up as a single "set" statement.
239 | #
240 | # This will of course break if any of these variables contains a newline or
241 | # an unmatched quote.
242 | #
243 |
244 | eval "set -- $(
245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
246 | xargs -n1 |
247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
248 | tr '\n' ' '
249 | )" '"$@"'
250 |
251 | exec "$JAVACMD" "$@"
252 |
--------------------------------------------------------------------------------
/example/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 | @rem SPDX-License-Identifier: Apache-2.0
17 | @rem
18 |
19 | @if "%DEBUG%"=="" @echo off
20 | @rem ##########################################################################
21 | @rem
22 | @rem Gradle startup script for Windows
23 | @rem
24 | @rem ##########################################################################
25 |
26 | @rem Set local scope for the variables with windows NT shell
27 | if "%OS%"=="Windows_NT" setlocal
28 |
29 | set DIRNAME=%~dp0
30 | if "%DIRNAME%"=="" set DIRNAME=.
31 | @rem This is normally unused
32 | set APP_BASE_NAME=%~n0
33 | set APP_HOME=%DIRNAME%
34 |
35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
37 |
38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
40 |
41 | @rem Find java.exe
42 | if defined JAVA_HOME goto findJavaFromJavaHome
43 |
44 | set JAVA_EXE=java.exe
45 | %JAVA_EXE% -version >NUL 2>&1
46 | if %ERRORLEVEL% equ 0 goto execute
47 |
48 | echo. 1>&2
49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
50 | echo. 1>&2
51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
52 | echo location of your Java installation. 1>&2
53 |
54 | goto fail
55 |
56 | :findJavaFromJavaHome
57 | set JAVA_HOME=%JAVA_HOME:"=%
58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
59 |
60 | if exist "%JAVA_EXE%" goto execute
61 |
62 | echo. 1>&2
63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
64 | echo. 1>&2
65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
66 | echo location of your Java installation. 1>&2
67 |
68 | goto fail
69 |
70 | :execute
71 | @rem Setup the command line
72 |
73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
74 |
75 |
76 | @rem Execute Gradle
77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
78 |
79 | :end
80 | @rem End local scope for the variables with windows NT shell
81 | if %ERRORLEVEL% equ 0 goto mainEnd
82 |
83 | :fail
84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
85 | rem the _cmd.exe /c_ return code!
86 | set EXIT_CODE=%ERRORLEVEL%
87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
89 | exit /b %EXIT_CODE%
90 |
91 | :mainEnd
92 | if "%OS%"=="Windows_NT" endlocal
93 |
94 | :omega
95 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") }
2 | plugins { id("com.facebook.react.settings") }
3 | extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }
4 | rootProject.name = 'RNEdgeToEdgeExample'
5 | include ':app'
6 | includeBuild('../node_modules/@react-native/gradle-plugin')
7 |
--------------------------------------------------------------------------------
/example/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "RNEdgeToEdgeExample",
3 | "displayName": "RNEdgeToEdgeExample"
4 | }
5 |
--------------------------------------------------------------------------------
/example/babel.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const pkg = require("../package.json");
3 |
4 | const resolverConfig = {
5 | extensions: [".ts", ".tsx", ".js", ".jsx", ".json"],
6 | alias: { [pkg.name]: path.resolve(__dirname, "../src") },
7 | };
8 |
9 | module.exports = {
10 | presets: ["module:@react-native/babel-preset"],
11 | plugins: [["module-resolver", resolverConfig]],
12 | };
13 |
--------------------------------------------------------------------------------
/example/index.js:
--------------------------------------------------------------------------------
1 | import { AppRegistry } from "react-native";
2 | import { name as appName } from "./app.json";
3 | import { App } from "./src/App";
4 |
5 | AppRegistry.registerComponent(appName, () => App);
6 |
--------------------------------------------------------------------------------
/example/ios/.xcode.env:
--------------------------------------------------------------------------------
1 | # This `.xcode.env` file is versioned and is used to source the environment
2 | # used when running script phases inside Xcode.
3 | # To customize your local environment, you can create an `.xcode.env.local`
4 | # file that is not versioned.
5 |
6 | # NODE_BINARY variable contains the PATH to the node executable.
7 | #
8 | # Customize the NODE_BINARY variable here.
9 | # For example, to use nvm with brew, add the following line
10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use
11 | export NODE_BINARY=$(command -v node)
12 |
--------------------------------------------------------------------------------
/example/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Resolve react_native_pods.rb with node to allow for hoisting
2 | require Pod::Executable.execute_command('node', ['-p',
3 | 'require.resolve(
4 | "react-native/scripts/react_native_pods.rb",
5 | {paths: [process.argv[1]]},
6 | )', __dir__]).strip
7 |
8 | platform :ios, min_ios_version_supported
9 | prepare_react_native_project!
10 |
11 | linkage = ENV['USE_FRAMEWORKS']
12 | if linkage != nil
13 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
14 | use_frameworks! :linkage => linkage.to_sym
15 | end
16 |
17 | target 'RNEdgeToEdgeExample' do
18 | config = use_native_modules!
19 |
20 | use_react_native!(
21 | :path => config[:reactNativePath],
22 | # An absolute path to your application root.
23 | :app_path => "#{Pod::Config.instance.installation_root}/.."
24 | )
25 |
26 | post_install do |installer|
27 | # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202
28 | react_native_post_install(
29 | installer,
30 | config[:reactNativePath],
31 | :mac_catalyst_enabled => false,
32 | # :ccache_enabled => true
33 | )
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/example/ios/RNEdgeToEdgeExample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 54;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 0C80B921A6F3F58F76C31292 /* libPods-RNEdgeToEdgeExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-RNEdgeToEdgeExample.a */; };
11 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
12 | 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; };
13 | 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
14 | B959B4216756E98475778ED6 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; };
15 | /* End PBXBuildFile section */
16 |
17 | /* Begin PBXFileReference section */
18 | 13B07F961A680F5B00A75B9A /* RNEdgeToEdgeExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RNEdgeToEdgeExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
19 | 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = RNEdgeToEdgeExample/Images.xcassets; sourceTree = ""; };
20 | 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = RNEdgeToEdgeExample/Info.plist; sourceTree = ""; };
21 | 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = RNEdgeToEdgeExample/PrivacyInfo.xcprivacy; sourceTree = ""; };
22 | 3B4392A12AC88292D35C810B /* Pods-RNEdgeToEdgeExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNEdgeToEdgeExample.debug.xcconfig"; path = "Target Support Files/Pods-RNEdgeToEdgeExample/Pods-RNEdgeToEdgeExample.debug.xcconfig"; sourceTree = ""; };
23 | 5709B34CF0A7D63546082F79 /* Pods-RNEdgeToEdgeExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNEdgeToEdgeExample.release.xcconfig"; path = "Target Support Files/Pods-RNEdgeToEdgeExample/Pods-RNEdgeToEdgeExample.release.xcconfig"; sourceTree = ""; };
24 | 5DCACB8F33CDC322A6C60F78 /* libPods-RNEdgeToEdgeExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RNEdgeToEdgeExample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
25 | 761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = RNEdgeToEdgeExample/AppDelegate.swift; sourceTree = ""; };
26 | 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = RNEdgeToEdgeExample/LaunchScreen.storyboard; sourceTree = ""; };
27 | ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
28 | /* End PBXFileReference section */
29 |
30 | /* Begin PBXFrameworksBuildPhase section */
31 | 13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
32 | isa = PBXFrameworksBuildPhase;
33 | buildActionMask = 2147483647;
34 | files = (
35 | 0C80B921A6F3F58F76C31292 /* libPods-RNEdgeToEdgeExample.a in Frameworks */,
36 | );
37 | runOnlyForDeploymentPostprocessing = 0;
38 | };
39 | /* End PBXFrameworksBuildPhase section */
40 |
41 | /* Begin PBXGroup section */
42 | 13B07FAE1A68108700A75B9A /* RNEdgeToEdgeExample */ = {
43 | isa = PBXGroup;
44 | children = (
45 | 13B07FB51A68108700A75B9A /* Images.xcassets */,
46 | 761780EC2CA45674006654EE /* AppDelegate.swift */,
47 | 13B07FB61A68108700A75B9A /* Info.plist */,
48 | 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,
49 | 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */,
50 | );
51 | name = RNEdgeToEdgeExample;
52 | sourceTree = "";
53 | };
54 | 2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
55 | isa = PBXGroup;
56 | children = (
57 | ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
58 | 5DCACB8F33CDC322A6C60F78 /* libPods-RNEdgeToEdgeExample.a */,
59 | );
60 | name = Frameworks;
61 | sourceTree = "";
62 | };
63 | 832341AE1AAA6A7D00B99B32 /* Libraries */ = {
64 | isa = PBXGroup;
65 | children = (
66 | );
67 | name = Libraries;
68 | sourceTree = "";
69 | };
70 | 83CBB9F61A601CBA00E9B192 = {
71 | isa = PBXGroup;
72 | children = (
73 | 13B07FAE1A68108700A75B9A /* RNEdgeToEdgeExample */,
74 | 832341AE1AAA6A7D00B99B32 /* Libraries */,
75 | 83CBBA001A601CBA00E9B192 /* Products */,
76 | 2D16E6871FA4F8E400B85C8A /* Frameworks */,
77 | BBD78D7AC51CEA395F1C20DB /* Pods */,
78 | );
79 | indentWidth = 2;
80 | sourceTree = "";
81 | tabWidth = 2;
82 | usesTabs = 0;
83 | };
84 | 83CBBA001A601CBA00E9B192 /* Products */ = {
85 | isa = PBXGroup;
86 | children = (
87 | 13B07F961A680F5B00A75B9A /* RNEdgeToEdgeExample.app */,
88 | );
89 | name = Products;
90 | sourceTree = "";
91 | };
92 | BBD78D7AC51CEA395F1C20DB /* Pods */ = {
93 | isa = PBXGroup;
94 | children = (
95 | 3B4392A12AC88292D35C810B /* Pods-RNEdgeToEdgeExample.debug.xcconfig */,
96 | 5709B34CF0A7D63546082F79 /* Pods-RNEdgeToEdgeExample.release.xcconfig */,
97 | );
98 | path = Pods;
99 | sourceTree = "";
100 | };
101 | /* End PBXGroup section */
102 |
103 | /* Begin PBXNativeTarget section */
104 | 13B07F861A680F5B00A75B9A /* RNEdgeToEdgeExample */ = {
105 | isa = PBXNativeTarget;
106 | buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "RNEdgeToEdgeExample" */;
107 | buildPhases = (
108 | C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */,
109 | 13B07F871A680F5B00A75B9A /* Sources */,
110 | 13B07F8C1A680F5B00A75B9A /* Frameworks */,
111 | 13B07F8E1A680F5B00A75B9A /* Resources */,
112 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
113 | 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */,
114 | E235C05ADACE081382539298 /* [CP] Copy Pods Resources */,
115 | );
116 | buildRules = (
117 | );
118 | dependencies = (
119 | );
120 | name = RNEdgeToEdgeExample;
121 | productName = RNEdgeToEdgeExample;
122 | productReference = 13B07F961A680F5B00A75B9A /* RNEdgeToEdgeExample.app */;
123 | productType = "com.apple.product-type.application";
124 | };
125 | /* End PBXNativeTarget section */
126 |
127 | /* Begin PBXProject section */
128 | 83CBB9F71A601CBA00E9B192 /* Project object */ = {
129 | isa = PBXProject;
130 | attributes = {
131 | LastUpgradeCheck = 1210;
132 | TargetAttributes = {
133 | 13B07F861A680F5B00A75B9A = {
134 | LastSwiftMigration = 1120;
135 | };
136 | };
137 | };
138 | buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "RNEdgeToEdgeExample" */;
139 | compatibilityVersion = "Xcode 12.0";
140 | developmentRegion = en;
141 | hasScannedForEncodings = 0;
142 | knownRegions = (
143 | en,
144 | Base,
145 | );
146 | mainGroup = 83CBB9F61A601CBA00E9B192;
147 | productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
148 | projectDirPath = "";
149 | projectRoot = "";
150 | targets = (
151 | 13B07F861A680F5B00A75B9A /* RNEdgeToEdgeExample */,
152 | );
153 | };
154 | /* End PBXProject section */
155 |
156 | /* Begin PBXResourcesBuildPhase section */
157 | 13B07F8E1A680F5B00A75B9A /* Resources */ = {
158 | isa = PBXResourcesBuildPhase;
159 | buildActionMask = 2147483647;
160 | files = (
161 | 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
162 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
163 | B959B4216756E98475778ED6 /* PrivacyInfo.xcprivacy in Resources */,
164 | );
165 | runOnlyForDeploymentPostprocessing = 0;
166 | };
167 | /* End PBXResourcesBuildPhase section */
168 |
169 | /* Begin PBXShellScriptBuildPhase section */
170 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
171 | isa = PBXShellScriptBuildPhase;
172 | buildActionMask = 2147483647;
173 | files = (
174 | );
175 | inputPaths = (
176 | "$(SRCROOT)/.xcode.env.local",
177 | "$(SRCROOT)/.xcode.env",
178 | );
179 | name = "Bundle React Native code and images";
180 | outputPaths = (
181 | );
182 | runOnlyForDeploymentPostprocessing = 0;
183 | shellPath = /bin/sh;
184 | shellScript = "set -e\n\nWITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
185 | };
186 | 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = {
187 | isa = PBXShellScriptBuildPhase;
188 | buildActionMask = 2147483647;
189 | files = (
190 | );
191 | inputFileListPaths = (
192 | "${PODS_ROOT}/Target Support Files/Pods-RNEdgeToEdgeExample/Pods-RNEdgeToEdgeExample-frameworks-${CONFIGURATION}-input-files.xcfilelist",
193 | );
194 | name = "[CP] Embed Pods Frameworks";
195 | outputFileListPaths = (
196 | "${PODS_ROOT}/Target Support Files/Pods-RNEdgeToEdgeExample/Pods-RNEdgeToEdgeExample-frameworks-${CONFIGURATION}-output-files.xcfilelist",
197 | );
198 | runOnlyForDeploymentPostprocessing = 0;
199 | shellPath = /bin/sh;
200 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-RNEdgeToEdgeExample/Pods-RNEdgeToEdgeExample-frameworks.sh\"\n";
201 | showEnvVarsInLog = 0;
202 | };
203 | C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */ = {
204 | isa = PBXShellScriptBuildPhase;
205 | buildActionMask = 2147483647;
206 | files = (
207 | );
208 | inputFileListPaths = (
209 | );
210 | inputPaths = (
211 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
212 | "${PODS_ROOT}/Manifest.lock",
213 | );
214 | name = "[CP] Check Pods Manifest.lock";
215 | outputFileListPaths = (
216 | );
217 | outputPaths = (
218 | "$(DERIVED_FILE_DIR)/Pods-RNEdgeToEdgeExample-checkManifestLockResult.txt",
219 | );
220 | runOnlyForDeploymentPostprocessing = 0;
221 | shellPath = /bin/sh;
222 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
223 | showEnvVarsInLog = 0;
224 | };
225 | E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = {
226 | isa = PBXShellScriptBuildPhase;
227 | buildActionMask = 2147483647;
228 | files = (
229 | );
230 | inputFileListPaths = (
231 | "${PODS_ROOT}/Target Support Files/Pods-RNEdgeToEdgeExample/Pods-RNEdgeToEdgeExample-resources-${CONFIGURATION}-input-files.xcfilelist",
232 | );
233 | name = "[CP] Copy Pods Resources";
234 | outputFileListPaths = (
235 | "${PODS_ROOT}/Target Support Files/Pods-RNEdgeToEdgeExample/Pods-RNEdgeToEdgeExample-resources-${CONFIGURATION}-output-files.xcfilelist",
236 | );
237 | runOnlyForDeploymentPostprocessing = 0;
238 | shellPath = /bin/sh;
239 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-RNEdgeToEdgeExample/Pods-RNEdgeToEdgeExample-resources.sh\"\n";
240 | showEnvVarsInLog = 0;
241 | };
242 | /* End PBXShellScriptBuildPhase section */
243 |
244 | /* Begin PBXSourcesBuildPhase section */
245 | 13B07F871A680F5B00A75B9A /* Sources */ = {
246 | isa = PBXSourcesBuildPhase;
247 | buildActionMask = 2147483647;
248 | files = (
249 | 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */,
250 | );
251 | runOnlyForDeploymentPostprocessing = 0;
252 | };
253 | /* End PBXSourcesBuildPhase section */
254 |
255 | /* Begin XCBuildConfiguration section */
256 | 13B07F941A680F5B00A75B9A /* Debug */ = {
257 | isa = XCBuildConfiguration;
258 | baseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-RNEdgeToEdgeExample.debug.xcconfig */;
259 | buildSettings = {
260 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
261 | CLANG_ENABLE_MODULES = YES;
262 | CURRENT_PROJECT_VERSION = 1;
263 | DEVELOPMENT_TEAM = 745449BDR9;
264 | ENABLE_BITCODE = NO;
265 | INFOPLIST_FILE = RNEdgeToEdgeExample/Info.plist;
266 | IPHONEOS_DEPLOYMENT_TARGET = 15.1;
267 | LD_RUNPATH_SEARCH_PATHS = (
268 | "$(inherited)",
269 | "@executable_path/Frameworks",
270 | );
271 | MARKETING_VERSION = 1.0;
272 | OTHER_LDFLAGS = (
273 | "$(inherited)",
274 | "-ObjC",
275 | "-lc++",
276 | );
277 | PRODUCT_BUNDLE_IDENTIFIER = com.zoontek.rnedgetoedgesexample;
278 | PRODUCT_NAME = RNEdgeToEdgeExample;
279 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
280 | SWIFT_VERSION = 5.0;
281 | VERSIONING_SYSTEM = "apple-generic";
282 | };
283 | name = Debug;
284 | };
285 | 13B07F951A680F5B00A75B9A /* Release */ = {
286 | isa = XCBuildConfiguration;
287 | baseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-RNEdgeToEdgeExample.release.xcconfig */;
288 | buildSettings = {
289 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
290 | CLANG_ENABLE_MODULES = YES;
291 | CURRENT_PROJECT_VERSION = 1;
292 | DEVELOPMENT_TEAM = 745449BDR9;
293 | INFOPLIST_FILE = RNEdgeToEdgeExample/Info.plist;
294 | IPHONEOS_DEPLOYMENT_TARGET = 15.1;
295 | LD_RUNPATH_SEARCH_PATHS = (
296 | "$(inherited)",
297 | "@executable_path/Frameworks",
298 | );
299 | MARKETING_VERSION = 1.0;
300 | OTHER_LDFLAGS = (
301 | "$(inherited)",
302 | "-ObjC",
303 | "-lc++",
304 | );
305 | PRODUCT_BUNDLE_IDENTIFIER = com.zoontek.rnedgetoedgesexample;
306 | PRODUCT_NAME = RNEdgeToEdgeExample;
307 | SWIFT_VERSION = 5.0;
308 | VERSIONING_SYSTEM = "apple-generic";
309 | };
310 | name = Release;
311 | };
312 | 83CBBA201A601CBA00E9B192 /* Debug */ = {
313 | isa = XCBuildConfiguration;
314 | buildSettings = {
315 | ALWAYS_SEARCH_USER_PATHS = NO;
316 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
317 | CLANG_CXX_LANGUAGE_STANDARD = "c++20";
318 | CLANG_CXX_LIBRARY = "libc++";
319 | CLANG_ENABLE_MODULES = YES;
320 | CLANG_ENABLE_OBJC_ARC = YES;
321 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
322 | CLANG_WARN_BOOL_CONVERSION = YES;
323 | CLANG_WARN_COMMA = YES;
324 | CLANG_WARN_CONSTANT_CONVERSION = YES;
325 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
326 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
327 | CLANG_WARN_EMPTY_BODY = YES;
328 | CLANG_WARN_ENUM_CONVERSION = YES;
329 | CLANG_WARN_INFINITE_RECURSION = YES;
330 | CLANG_WARN_INT_CONVERSION = YES;
331 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
332 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
333 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
334 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
335 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
336 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
337 | CLANG_WARN_STRICT_PROTOTYPES = YES;
338 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
339 | CLANG_WARN_UNREACHABLE_CODE = YES;
340 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
341 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
342 | COPY_PHASE_STRIP = NO;
343 | ENABLE_STRICT_OBJC_MSGSEND = YES;
344 | ENABLE_TESTABILITY = YES;
345 | "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
346 | GCC_C_LANGUAGE_STANDARD = gnu99;
347 | GCC_DYNAMIC_NO_PIC = NO;
348 | GCC_NO_COMMON_BLOCKS = YES;
349 | GCC_OPTIMIZATION_LEVEL = 0;
350 | GCC_PREPROCESSOR_DEFINITIONS = (
351 | "DEBUG=1",
352 | "$(inherited)",
353 | );
354 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
355 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
356 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
357 | GCC_WARN_UNDECLARED_SELECTOR = YES;
358 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
359 | GCC_WARN_UNUSED_FUNCTION = YES;
360 | GCC_WARN_UNUSED_VARIABLE = YES;
361 | IPHONEOS_DEPLOYMENT_TARGET = 15.1;
362 | LD_RUNPATH_SEARCH_PATHS = (
363 | /usr/lib/swift,
364 | "$(inherited)",
365 | );
366 | LIBRARY_SEARCH_PATHS = (
367 | "\"$(SDKROOT)/usr/lib/swift\"",
368 | "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
369 | "\"$(inherited)\"",
370 | );
371 | MTL_ENABLE_DEBUG_INFO = YES;
372 | ONLY_ACTIVE_ARCH = YES;
373 | OTHER_CPLUSPLUSFLAGS = (
374 | "$(OTHER_CFLAGS)",
375 | "-DFOLLY_NO_CONFIG",
376 | "-DFOLLY_MOBILE=1",
377 | "-DFOLLY_USE_LIBCPP=1",
378 | "-DFOLLY_CFG_NO_COROUTINES=1",
379 | "-DFOLLY_HAVE_CLOCK_GETTIME=1",
380 | );
381 | OTHER_LDFLAGS = (
382 | "$(inherited)",
383 | " ",
384 | );
385 | REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
386 | SDKROOT = iphoneos;
387 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
388 | USE_HERMES = true;
389 | };
390 | name = Debug;
391 | };
392 | 83CBBA211A601CBA00E9B192 /* Release */ = {
393 | isa = XCBuildConfiguration;
394 | buildSettings = {
395 | ALWAYS_SEARCH_USER_PATHS = NO;
396 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
397 | CLANG_CXX_LANGUAGE_STANDARD = "c++20";
398 | CLANG_CXX_LIBRARY = "libc++";
399 | CLANG_ENABLE_MODULES = YES;
400 | CLANG_ENABLE_OBJC_ARC = YES;
401 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
402 | CLANG_WARN_BOOL_CONVERSION = YES;
403 | CLANG_WARN_COMMA = YES;
404 | CLANG_WARN_CONSTANT_CONVERSION = YES;
405 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
406 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
407 | CLANG_WARN_EMPTY_BODY = YES;
408 | CLANG_WARN_ENUM_CONVERSION = YES;
409 | CLANG_WARN_INFINITE_RECURSION = YES;
410 | CLANG_WARN_INT_CONVERSION = YES;
411 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
412 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
413 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
414 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
415 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
416 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
417 | CLANG_WARN_STRICT_PROTOTYPES = YES;
418 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
419 | CLANG_WARN_UNREACHABLE_CODE = YES;
420 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
421 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
422 | COPY_PHASE_STRIP = YES;
423 | ENABLE_NS_ASSERTIONS = NO;
424 | ENABLE_STRICT_OBJC_MSGSEND = YES;
425 | "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
426 | GCC_C_LANGUAGE_STANDARD = gnu99;
427 | GCC_NO_COMMON_BLOCKS = YES;
428 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
429 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
430 | GCC_WARN_UNDECLARED_SELECTOR = YES;
431 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
432 | GCC_WARN_UNUSED_FUNCTION = YES;
433 | GCC_WARN_UNUSED_VARIABLE = YES;
434 | IPHONEOS_DEPLOYMENT_TARGET = 15.1;
435 | LD_RUNPATH_SEARCH_PATHS = (
436 | /usr/lib/swift,
437 | "$(inherited)",
438 | );
439 | LIBRARY_SEARCH_PATHS = (
440 | "\"$(SDKROOT)/usr/lib/swift\"",
441 | "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
442 | "\"$(inherited)\"",
443 | );
444 | MTL_ENABLE_DEBUG_INFO = NO;
445 | OTHER_CPLUSPLUSFLAGS = (
446 | "$(OTHER_CFLAGS)",
447 | "-DFOLLY_NO_CONFIG",
448 | "-DFOLLY_MOBILE=1",
449 | "-DFOLLY_USE_LIBCPP=1",
450 | "-DFOLLY_CFG_NO_COROUTINES=1",
451 | "-DFOLLY_HAVE_CLOCK_GETTIME=1",
452 | );
453 | OTHER_LDFLAGS = (
454 | "$(inherited)",
455 | " ",
456 | );
457 | REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
458 | SDKROOT = iphoneos;
459 | USE_HERMES = true;
460 | VALIDATE_PRODUCT = YES;
461 | };
462 | name = Release;
463 | };
464 | /* End XCBuildConfiguration section */
465 |
466 | /* Begin XCConfigurationList section */
467 | 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "RNEdgeToEdgeExample" */ = {
468 | isa = XCConfigurationList;
469 | buildConfigurations = (
470 | 13B07F941A680F5B00A75B9A /* Debug */,
471 | 13B07F951A680F5B00A75B9A /* Release */,
472 | );
473 | defaultConfigurationIsVisible = 0;
474 | defaultConfigurationName = Release;
475 | };
476 | 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "RNEdgeToEdgeExample" */ = {
477 | isa = XCConfigurationList;
478 | buildConfigurations = (
479 | 83CBBA201A601CBA00E9B192 /* Debug */,
480 | 83CBBA211A601CBA00E9B192 /* Release */,
481 | );
482 | defaultConfigurationIsVisible = 0;
483 | defaultConfigurationName = Release;
484 | };
485 | /* End XCConfigurationList section */
486 | };
487 | rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
488 | }
489 |
--------------------------------------------------------------------------------
/example/ios/RNEdgeToEdgeExample.xcodeproj/xcshareddata/xcschemes/RNEdgeToEdgeExample.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/example/ios/RNEdgeToEdgeExample.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/ios/RNEdgeToEdgeExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/RNEdgeToEdgeExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import React
3 | import React_RCTAppDelegate
4 | import ReactAppDependencyProvider
5 |
6 | @main
7 | class AppDelegate: UIResponder, UIApplicationDelegate {
8 | var window: UIWindow?
9 |
10 | var reactNativeDelegate: ReactNativeDelegate?
11 | var reactNativeFactory: RCTReactNativeFactory?
12 |
13 | func application(
14 | _ application: UIApplication,
15 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
16 | ) -> Bool {
17 | let delegate = ReactNativeDelegate()
18 | let factory = RCTReactNativeFactory(delegate: delegate)
19 | delegate.dependencyProvider = RCTAppDependencyProvider()
20 |
21 | reactNativeDelegate = delegate
22 | reactNativeFactory = factory
23 |
24 | window = UIWindow(frame: UIScreen.main.bounds)
25 |
26 | factory.startReactNative(
27 | withModuleName: "RNEdgeToEdgeExample",
28 | in: window,
29 | launchOptions: launchOptions
30 | )
31 |
32 | return true
33 | }
34 | }
35 |
36 | class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate {
37 | override func sourceURL(for bridge: RCTBridge) -> URL? {
38 | self.bundleURL()
39 | }
40 |
41 | override func bundleURL() -> URL? {
42 | #if DEBUG
43 | RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
44 | #else
45 | Bundle.main.url(forResource: "main", withExtension: "jsbundle")
46 | #endif
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/example/ios/RNEdgeToEdgeExample/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "idiom": "iphone",
5 | "scale": "2x",
6 | "size": "20x20"
7 | },
8 | {
9 | "idiom": "iphone",
10 | "scale": "3x",
11 | "size": "20x20"
12 | },
13 | {
14 | "idiom": "iphone",
15 | "scale": "2x",
16 | "size": "29x29"
17 | },
18 | {
19 | "idiom": "iphone",
20 | "scale": "3x",
21 | "size": "29x29"
22 | },
23 | {
24 | "idiom": "iphone",
25 | "scale": "2x",
26 | "size": "40x40"
27 | },
28 | {
29 | "idiom": "iphone",
30 | "scale": "3x",
31 | "size": "40x40"
32 | },
33 | {
34 | "idiom": "iphone",
35 | "scale": "2x",
36 | "size": "60x60"
37 | },
38 | {
39 | "idiom": "iphone",
40 | "scale": "3x",
41 | "size": "60x60"
42 | },
43 | {
44 | "idiom": "ios-marketing",
45 | "scale": "1x",
46 | "size": "1024x1024"
47 | }
48 | ],
49 | "info": {
50 | "author": "xcode",
51 | "version": 1
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/example/ios/RNEdgeToEdgeExample/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info": {
3 | "version": 1,
4 | "author": "xcode"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/example/ios/RNEdgeToEdgeExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | RNEdgeToEdgeExample
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(MARKETING_VERSION)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(CURRENT_PROJECT_VERSION)
25 | LSRequiresIPhoneOS
26 |
27 | NSAppTransportSecurity
28 |
29 | NSAllowsArbitraryLoads
30 |
31 | NSAllowsLocalNetworking
32 |
33 |
34 | NSLocationWhenInUseUsageDescription
35 |
36 | UILaunchStoryboardName
37 | LaunchScreen
38 | UIRequiredDeviceCapabilities
39 |
40 | arm64
41 |
42 | UISupportedInterfaceOrientations
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationLandscapeLeft
46 | UIInterfaceOrientationLandscapeRight
47 |
48 | UIViewControllerBasedStatusBarAppearance
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/example/ios/RNEdgeToEdgeExample/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/example/ios/RNEdgeToEdgeExample/PrivacyInfo.xcprivacy:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSPrivacyAccessedAPITypes
6 |
7 |
8 | NSPrivacyAccessedAPIType
9 | NSPrivacyAccessedAPICategoryFileTimestamp
10 | NSPrivacyAccessedAPITypeReasons
11 |
12 | C617.1
13 |
14 |
15 |
16 | NSPrivacyAccessedAPIType
17 | NSPrivacyAccessedAPICategoryUserDefaults
18 | NSPrivacyAccessedAPITypeReasons
19 |
20 | CA92.1
21 |
22 |
23 |
24 | NSPrivacyAccessedAPIType
25 | NSPrivacyAccessedAPICategorySystemBootTime
26 | NSPrivacyAccessedAPITypeReasons
27 |
28 | 35F9.1
29 |
30 |
31 |
32 | NSPrivacyCollectedDataTypes
33 |
34 | NSPrivacyTracking
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/example/metro.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const pkg = require("../package.json");
3 |
4 | const { getDefaultConfig, mergeConfig } = require("@react-native/metro-config");
5 | const escape = require("escape-string-regexp");
6 | const exclusionList = require("metro-config/src/defaults/exclusionList");
7 |
8 | const peerDependencies = Object.keys(pkg.peerDependencies);
9 | const root = path.resolve(__dirname, "..");
10 | const projectNodeModules = path.join(__dirname, "node_modules");
11 | const rootNodeModules = path.join(root, "node_modules");
12 |
13 | // We need to make sure that only one version is loaded for peerDependencies
14 | // So we block them at the root, and alias them to the versions in example's node_modules
15 | const blacklistRE = exclusionList(
16 | peerDependencies.map(
17 | (name) => new RegExp(`^${escape(path.join(rootNodeModules, name))}\\/.*$`),
18 | ),
19 | );
20 |
21 | const extraNodeModules = peerDependencies.reduce((acc, name) => {
22 | acc[name] = path.join(projectNodeModules, name);
23 | return acc;
24 | }, {});
25 |
26 | /**
27 | * Metro configuration
28 | * https://reactnative.dev/docs/metro
29 | *
30 | * @type {import('@react-native/metro-config').MetroConfig}
31 | */
32 | const config = {
33 | projectRoot: __dirname,
34 | watchFolders: [root],
35 | resolver: { blacklistRE, extraNodeModules },
36 | };
37 |
38 | module.exports = mergeConfig(getDefaultConfig(__dirname), config);
39 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rn-edge-to-edge-example",
3 | "version": "0.0.1",
4 | "private": true,
5 | "engines": {
6 | "node": ">=18"
7 | },
8 | "scripts": {
9 | "clean": "rm -rf ./node_modules",
10 | "preinstall": "cd .. && yarn && yarn build && cd example",
11 | "start": "react-native start",
12 | "reinstall": "yarn clean && yarn install"
13 | },
14 | "dependencies": {
15 | "@react-native-segmented-control/segmented-control": "2.5.7",
16 | "@react-navigation/native": "7.1.6",
17 | "@react-navigation/native-stack": "7.3.10",
18 | "react": "19.0.0",
19 | "react-native": "0.79.0",
20 | "react-native-edge-to-edge": "link:../",
21 | "react-native-safe-area-context": "5.3.0",
22 | "react-native-screens": "4.10.0"
23 | },
24 | "devDependencies": {
25 | "@babel/core": "^7.25.2",
26 | "@babel/preset-env": "^7.25.3",
27 | "@babel/runtime": "^7.25.0",
28 | "@react-native-community/cli": "18.0.0",
29 | "@react-native-community/cli-platform-android": "18.0.0",
30 | "@react-native-community/cli-platform-ios": "18.0.0",
31 | "@react-native/babel-preset": "0.79.0",
32 | "@react-native/metro-config": "0.79.0",
33 | "@types/react": "^19.0.0",
34 | "babel-plugin-module-resolver": "^5.0.2",
35 | "typescript": "^5.8.3"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/example/src/App.tsx:
--------------------------------------------------------------------------------
1 | import SegmentedControl from "@react-native-segmented-control/segmented-control";
2 | import { NavigationContainer } from "@react-navigation/native";
3 | import {
4 | createNativeStackNavigator,
5 | NativeStackScreenProps,
6 | } from "@react-navigation/native-stack";
7 | import * as React from "react";
8 | import { ReactNode, useEffect, useState } from "react";
9 | import {
10 | Appearance,
11 | Text as BaseText,
12 | Modal,
13 | Platform,
14 | StyleProp,
15 | StyleSheet,
16 | Switch,
17 | TextProps,
18 | TouchableOpacity,
19 | useColorScheme,
20 | View,
21 | ViewStyle,
22 | } from "react-native";
23 | import { SystemBars, SystemBarStyle } from "react-native-edge-to-edge";
24 | import { useSafeAreaInsets } from "react-native-safe-area-context";
25 |
26 | const DARK_BACKGROUND = "#1F2937";
27 | const DARK_TEXT = "#374151";
28 | const LIGHT_BACKGROUND = "#F9FAFB";
29 | const LIGHT_TEXT = "#E5E7EB";
30 |
31 | const styles = StyleSheet.create({
32 | container: {
33 | backgroundColor: LIGHT_BACKGROUND,
34 | flex: 1,
35 | justifyContent: "center",
36 | paddingHorizontal: 16,
37 | },
38 | darkContainer: {
39 | backgroundColor: DARK_BACKGROUND,
40 | },
41 | row: {
42 | flexDirection: "row",
43 | alignItems: "center",
44 | justifyContent: "space-between",
45 | },
46 | });
47 |
48 | const Space = ({ size }: { size: number }) => (
49 |
54 | );
55 |
56 | const Text = ({ style, ...props }: TextProps) => {
57 | const dark = useColorScheme() === "dark";
58 |
59 | return (
60 |
64 | );
65 | };
66 |
67 | const Title = ({ children }: { children: ReactNode }) => (
68 | <>
69 | {children}
70 |
71 | >
72 | );
73 |
74 | const Button = ({
75 | title,
76 | style,
77 | onPress,
78 | }: {
79 | title: string;
80 | style?: StyleProp;
81 | onPress: () => void;
82 | }) => {
83 | const dark = useColorScheme() === "dark";
84 |
85 | return (
86 |
99 | {title}
100 |
101 | );
102 | };
103 |
104 | const SCHEMES = ["system", "light", "dark"];
105 | const STYLES: SystemBarStyle[] = ["auto", "inverted", "light", "dark"];
106 |
107 | type StackParamList = {
108 | Home: undefined;
109 | Modal: undefined;
110 | };
111 |
112 | const Stack = createNativeStackNavigator();
113 |
114 | const ModalContent = ({
115 | children,
116 | onClose,
117 | }: {
118 | children: ReactNode;
119 | onClose: () => void;
120 | }) => {
121 | const dark = useColorScheme() === "dark";
122 |
123 | const [styleIndex, setStyleIndex] = useState(0);
124 | const insets = useSafeAreaInsets();
125 |
126 | return (
127 |
128 |
137 |
138 |
139 |
140 | {children}
141 |
142 |
143 | {
147 | setStyleIndex(STYLES.indexOf(value as SystemBarStyle));
148 | }}
149 | />
150 |
151 | );
152 | };
153 |
154 | export const HomeScreen = ({
155 | navigation,
156 | }: NativeStackScreenProps) => {
157 | const dark = useColorScheme() === "dark";
158 |
159 | const thumbColor = dark ? LIGHT_TEXT : "#fff";
160 | const trackColor = dark
161 | ? { false: "#1c1c1f", true: "#2b3e55" }
162 | : { false: "#eeeef0", true: "#ccd8e5" };
163 |
164 | const [schemeIndex, setSchemeIndex] = useState(0);
165 | const [styleIndex, setStyleIndex] = useState(0);
166 | const [statusBarHidden, setStatusBarHidden] = useState(false);
167 | const [navigationBarHidden, setNavigationBarHidden] = useState(false);
168 | const [reactNativeModalVisible, setReactNativeModalVisible] = useState(false);
169 |
170 | useEffect(() => {
171 | const value = SCHEMES[schemeIndex];
172 | const scheme = value === "light" || value === "dark" ? value : null;
173 | Appearance.setColorScheme(scheme);
174 | }, [schemeIndex]);
175 |
176 | const closeReactNativeModal = () => {
177 | setReactNativeModalVisible(false);
178 | };
179 |
180 | return (
181 |
182 |
189 |
190 | Theme
191 |
192 | {
197 | setSchemeIndex(SCHEMES.indexOf(value));
198 | }}
199 | />
200 |
201 |
202 |
203 | {""}
204 |
205 | {
210 | setStyleIndex(STYLES.indexOf(value as SystemBarStyle));
211 | }}
212 | />
213 |
214 |
215 |
216 |
217 | Hide status bar
218 |
219 |
225 |
226 |
227 |
228 |
229 |
230 | Hide navigation bar (no effect on iOS)
231 |
232 |
238 |
239 |
240 |
241 |
242 |
273 | );
274 | };
275 |
276 | const ModalScreen = ({
277 | navigation,
278 | }: NativeStackScreenProps) => (
279 |
280 | This modal uses a React Navigation modal.{"\n"}Eveything behaves correctly.
281 |
282 | );
283 |
284 | export const App = () => (
285 |
286 |
287 |
288 |
289 |
298 |
299 |
300 | );
301 |
--------------------------------------------------------------------------------
/example/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "ESNext",
4 | "lib": ["ES2017"],
5 | "jsx": "react-native",
6 | "moduleResolution": "Node",
7 |
8 | "allowJs": false,
9 | "strict": true,
10 | "declaration": true,
11 | "sourceMap": true,
12 | "stripInternal": true,
13 | "skipLibCheck": true,
14 |
15 | "allowUnreachableCode": false,
16 | "allowUnusedLabels": false,
17 | "noFallthroughCasesInSwitch": true,
18 | "noImplicitOverride": true,
19 | "noImplicitReturns": false,
20 | "noUncheckedIndexedAccess": true,
21 | "noUnusedLocals": true,
22 | "noUnusedParameters": true,
23 |
24 | "paths": {
25 | "react-native-edge-to-edge": ["../src"]
26 | }
27 | },
28 | "include": ["src"],
29 | "exclude": ["node_modules", "babel.config.js", "metro.config.js"]
30 | }
31 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-edge-to-edge",
3 | "version": "1.6.1",
4 | "license": "MIT",
5 | "description": "Effortlessly enable edge-to-edge display in React Native",
6 | "author": "Mathieu Acthernoene ",
7 | "homepage": "https://github.com/zoontek/react-native-edge-to-edge",
8 | "main": "dist/commonjs/index.js",
9 | "module": "dist/module/index.js",
10 | "types": "dist/typescript/index.d.ts",
11 | "files": [
12 | "dist",
13 | "src",
14 | "app.plugin.js",
15 | "android",
16 | "!android/build",
17 | "!android/.cxx",
18 | "!android/.gradle"
19 | ],
20 | "repository": {
21 | "type": "git",
22 | "url": "https://github.com/zoontek/react-native-edge-to-edge.git"
23 | },
24 | "keywords": [
25 | "react",
26 | "react-native",
27 | "edge-to-edge",
28 | "status-bar",
29 | "navigation-bar",
30 | "system-bar",
31 | "system-bars"
32 | ],
33 | "scripts": {
34 | "clean": "rm -rf dist",
35 | "format": "prettier '**/*' -u -w",
36 | "typecheck": "tsc --noEmit",
37 | "build": "yarn clean && bob build && rm -rf dist/*/package.json",
38 | "prepack": "prettier '**/*' -u -c && yarn typecheck && yarn build"
39 | },
40 | "react-native-builder-bob": {
41 | "source": "src",
42 | "output": "dist",
43 | "targets": [
44 | "commonjs",
45 | "module",
46 | "typescript"
47 | ]
48 | },
49 | "prettier": {
50 | "plugins": [
51 | "prettier-plugin-organize-imports"
52 | ]
53 | },
54 | "peerDependencies": {
55 | "react": "*",
56 | "react-native": "*"
57 | },
58 | "devDependencies": {
59 | "@babel/core": "^7.25.2",
60 | "@babel/preset-env": "^7.25.3",
61 | "@expo/config-plugins": "^7.0.0 || ^8.0.0 || ^9.0.0",
62 | "@types/react": "^19.0.0",
63 | "prettier": "^3.5.3",
64 | "prettier-plugin-organize-imports": "^4.1.0",
65 | "react": "19.0.0",
66 | "react-native": "0.79.0",
67 | "react-native-builder-bob": "^0.40.6",
68 | "typescript": "^5.8.3"
69 | },
70 | "codegenConfig": {
71 | "name": "RNEdgeToEdge",
72 | "type": "modules",
73 | "jsSrcsDir": "./src/specs",
74 | "android": {
75 | "javaPackageName": "com.zoontek.rnedgetoedge"
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/react-native-is-edge-to-edge/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | # 1.1.7
4 |
5 | - Fix peer dependencies versions (3255daa)
6 |
7 | # 1.1.6
8 |
9 | - Fix module resolution - thanks to [@robjhogan](https://twitter.com/robjhogan/status/1850963256745025785) (44d3be7)
10 |
11 | # 1.1.5
12 |
13 | - Fix typo with plural in warnings (fe30873)
14 |
15 | # 1.1.4
16 |
17 | - Remove `browser` module entry from `package.json` (54c0c85)
18 |
19 | # 1.1.3
20 |
21 | - Fix `controlEdgeToEdgeValues` behavior on non-android platforms (6b22078)
22 |
23 | # 1.1.2
24 |
25 | - Fix metro module resolution with new architecture enabled (67a2bda)
26 |
27 | # 1.1.1
28 |
29 | - Make `isEdgeToEdge` function call lazy (5294ca6)
30 |
31 | # 1.1.0
32 |
33 | - Add `controlEdgeToEdgeValues` to warn users in development (cc7b248)
34 |
35 | # 1.0.0
36 |
37 | - Stable release. The API is not subject to changes anymore (a93e6af)
38 |
39 | ## 0.1.2
40 |
41 | - Add ES module build format (d7e932d)
42 |
43 | ## 0.1.1
44 |
45 | - Fix `react-native-web` compatibility (f375a84)
46 |
47 | ## 0.1.0
48 |
49 | - Initial release
50 |
--------------------------------------------------------------------------------
/react-native-is-edge-to-edge/README.md:
--------------------------------------------------------------------------------
1 | # react-native-is-edge-to-edge
2 |
3 | Many libraries provide options to account for the transparency of status and navigation bars. For example, the [`useHideAnimation`](https://github.com/zoontek/react-native-bootsplash?tab=readme-ov-file#usehideanimation) hook in `react-native-bootsplash` includes `statusBarTranslucent` and `navigationBarTranslucent` options, while the [`useAnimatedKeyboard`](https://docs.swmansion.com/react-native-reanimated/docs/device/useAnimatedKeyboard) hook in `react-native-reanimated` offers an `isStatusBarTranslucentAndroid` option, among others.
4 |
5 | > [!IMPORTANT]
6 | > Until third-party libraries officially add support for `react-native-edge-to-edge` to set these options automatically, you may need to adjust them manually to prevent interference with the library.
7 |
8 | To support library authors, we provide this lightweight package called `react-native-is-edge-to-edge` (note the `-is-`!), which checks whether `react-native-edge-to-edge` is installed, making it easier to update your library accordingly:
9 |
10 | ```tsx
11 | import {
12 | controlEdgeToEdgeValues,
13 | isEdgeToEdge,
14 | } from "react-native-is-edge-to-edge";
15 |
16 | const EDGE_TO_EDGE = isEdgeToEdge();
17 |
18 | function MyAwesomeLibraryComponent({
19 | statusBarTranslucent,
20 | navigationBarTranslucent,
21 | }) {
22 | if (__DEV__) {
23 | // warn the user once about unnecessary defined values
24 | controlEdgeToEdgeValues({
25 | statusBarTranslucent,
26 | navigationBarTranslucent,
27 | });
28 | }
29 |
30 | return (
31 |
36 | );
37 | }
38 | ```
39 |
40 | If you want to check for the library's presence on the native side to bypass certain parts of your code, consider using this small utility:
41 |
42 | ```kotlin
43 | object EdgeToEdge {
44 | // we cannot detect edge-to-edge, but we can detect react-native-edge-to-edge install
45 | val ENABLED: Boolean = try {
46 | Class.forName("com.zoontek.rnedgetoedge.EdgeToEdgePackage")
47 | true
48 | } catch (exception: ClassNotFoundException) {
49 | false
50 | }
51 | }
52 | ```
53 |
--------------------------------------------------------------------------------
/react-native-is-edge-to-edge/__tests__/controlEdgeToEdgeValues.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
2 |
3 | beforeAll(() => {
4 | Object.defineProperty(global, "__DEV__", {
5 | value: true,
6 | writable: false,
7 | });
8 | });
9 |
10 | vi.mock("react-native", () => ({
11 | TurboModuleRegistry: { get: () => ({}) },
12 | }));
13 |
14 | describe("controlEdgeToEdgeValues", () => {
15 | const mock = vi.spyOn(console, "warn").mockImplementation(() => {});
16 | const statusBarTranslucent = true;
17 | const navigationBarTranslucent = false;
18 |
19 | beforeEach(() => {
20 | mock.mockReset();
21 | vi.resetModules();
22 | });
23 |
24 | it("is called when some values are defined", async () => {
25 | const { controlEdgeToEdgeValues } = await import("../src/index.android");
26 |
27 | controlEdgeToEdgeValues({ statusBarTranslucent, navigationBarTranslucent });
28 |
29 | expect(mock).toHaveBeenCalledOnce();
30 | expect(mock).toHaveBeenCalledWith(
31 | "statusBarTranslucent and navigationBarTranslucent values are ignored when using react-native-edge-to-edge",
32 | );
33 | });
34 |
35 | it("is not called if the values are undefined", async () => {
36 | const { controlEdgeToEdgeValues } = await import("../src/index.android");
37 |
38 | controlEdgeToEdgeValues({ statusBarTranslucent: undefined });
39 | expect(mock).not.toHaveBeenCalled();
40 | });
41 |
42 | it("is called once if the values doesn't change", async () => {
43 | const { controlEdgeToEdgeValues } = await import("../src/index.android");
44 |
45 | controlEdgeToEdgeValues({ statusBarTranslucent, navigationBarTranslucent });
46 | controlEdgeToEdgeValues({ statusBarTranslucent, navigationBarTranslucent });
47 |
48 | expect(mock).toHaveBeenCalledOnce();
49 | expect(mock).toHaveBeenCalledWith(
50 | "statusBarTranslucent and navigationBarTranslucent values are ignored when using react-native-edge-to-edge",
51 | );
52 | });
53 |
54 | it("is called twice if the values change", async () => {
55 | const { controlEdgeToEdgeValues } = await import("../src/index.android");
56 |
57 | controlEdgeToEdgeValues({ statusBarTranslucent, navigationBarTranslucent });
58 | controlEdgeToEdgeValues({ statusBarTranslucent });
59 |
60 | expect(mock).toHaveBeenCalledTimes(2);
61 |
62 | expect(mock).toHaveBeenNthCalledWith(
63 | 1,
64 | "statusBarTranslucent and navigationBarTranslucent values are ignored when using react-native-edge-to-edge",
65 | );
66 | expect(mock).toHaveBeenNthCalledWith(
67 | 2,
68 | "statusBarTranslucent value is ignored when using react-native-edge-to-edge",
69 | );
70 | });
71 | });
72 |
--------------------------------------------------------------------------------
/react-native-is-edge-to-edge/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-is-edge-to-edge",
3 | "version": "1.1.7",
4 | "license": "MIT",
5 | "description": "Detect react-native-edge-to-edge package install",
6 | "author": "Mathieu Acthernoene ",
7 | "homepage": "https://github.com/zoontek/react-native-edge-to-edge",
8 | "source": "src/index",
9 | "main": "dist/index",
10 | "module": "dist/index",
11 | "types": "dist/index.d.ts",
12 | "files": [
13 | "dist"
14 | ],
15 | "repository": {
16 | "type": "git",
17 | "url": "https://github.com/zoontek/react-native-edge-to-edge.git"
18 | },
19 | "keywords": [
20 | "react",
21 | "react-native",
22 | "edge-to-edge",
23 | "status-bar",
24 | "navigation-bar",
25 | "system-bar",
26 | "system-bars"
27 | ],
28 | "scripts": {
29 | "clean": "rm -rf dist",
30 | "test": "vitest run",
31 | "build": "yarn clean && yarn test && tsup && tsc -p tsconfig.build.json --emitDeclarationOnly"
32 | },
33 | "peerDependencies": {
34 | "react": "*",
35 | "react-native": "*"
36 | },
37 | "devDependencies": {
38 | "react": "19.0.0",
39 | "react-native": "0.79.0",
40 | "tsup": "^8.4.0",
41 | "typescript": "^5.8.3",
42 | "vitest": "^3.1.1"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/react-native-is-edge-to-edge/src/index.android.ts:
--------------------------------------------------------------------------------
1 | import { TurboModuleRegistry } from "react-native";
2 |
3 | const warnings = new Set();
4 |
5 | export const isEdgeToEdge = () =>
6 | TurboModuleRegistry.get("RNEdgeToEdge") != null;
7 |
8 | export const controlEdgeToEdgeValues = (values: Record) => {
9 | if (__DEV__ && isEdgeToEdge()) {
10 | const entries = Object.entries(values).filter(
11 | ([, value]) => typeof value !== "undefined",
12 | );
13 |
14 | const stableKey = entries.join(" ");
15 |
16 | if (entries.length < 1 || warnings.has(stableKey)) {
17 | return;
18 | }
19 |
20 | warnings.add(stableKey);
21 |
22 | const isPlural = entries.length > 1;
23 | const lastIndex = entries.length - 1;
24 |
25 | const list = entries.reduce(
26 | (acc, [name], index) =>
27 | index === 0
28 | ? name
29 | : acc + (index === lastIndex ? " and " : ", ") + name,
30 | "",
31 | );
32 |
33 | console.warn(
34 | `${list} ${isPlural ? "values are" : "value is"} ignored when using react-native-edge-to-edge`,
35 | );
36 | }
37 | };
38 |
--------------------------------------------------------------------------------
/react-native-is-edge-to-edge/src/index.ts:
--------------------------------------------------------------------------------
1 | export const isEdgeToEdge = () => true;
2 |
3 | // @ts-expect-error noop on all platforms except android
4 | export const controlEdgeToEdgeValues = (values: Record) => {};
5 |
--------------------------------------------------------------------------------
/react-native-is-edge-to-edge/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "include": ["src"],
4 | "exclude": ["node_modules", "__tests__"]
5 | }
6 |
--------------------------------------------------------------------------------
/react-native-is-edge-to-edge/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "include": ["src", "__tests__"],
4 | "compilerOptions": { "outDir": "dist" }
5 | }
6 |
--------------------------------------------------------------------------------
/react-native-is-edge-to-edge/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "tsup";
2 |
3 | export default defineConfig({
4 | entry: ["src"],
5 | format: ["cjs", "esm"],
6 | target: "es2019",
7 | tsconfig: "./tsconfig.build.json",
8 | clean: true,
9 | dts: false,
10 | sourcemap: true,
11 | treeshake: true,
12 | });
13 |
--------------------------------------------------------------------------------
/src/SystemBars.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useMemo, useRef } from "react";
2 | import { Appearance, Platform, StatusBar, useColorScheme } from "react-native";
3 | import NativeModule from "./specs/NativeEdgeToEdgeModule";
4 | import { SystemBarsEntry, SystemBarsProps, SystemBarStyle } from "./types";
5 |
6 | type ResolvedBarStyle = "light" | "dark" | undefined;
7 |
8 | function isLightColorScheme() {
9 | const colorScheme = Appearance?.getColorScheme() ?? "light";
10 | return colorScheme === "light";
11 | }
12 |
13 | function resolveSystemBarStyle(
14 | style: SystemBarStyle | undefined,
15 | ): ResolvedBarStyle {
16 | switch (style) {
17 | case "auto":
18 | return isLightColorScheme() ? "dark" : "light";
19 | case "inverted":
20 | return isLightColorScheme() ? "light" : "dark";
21 | default:
22 | return style;
23 | }
24 | }
25 |
26 | function toNativeBarStyle(
27 | style: ResolvedBarStyle,
28 | ): "default" | "light-content" | "dark-content" {
29 | return style === "light" || style === "dark" ? `${style}-content` : "default";
30 | }
31 |
32 | /**
33 | * Merges the entries stack.
34 | */
35 | function mergeEntriesStack(entriesStack: SystemBarsEntry[]) {
36 | return entriesStack.reduce<{
37 | statusBarStyle: SystemBarStyle | undefined;
38 | navigationBarStyle: SystemBarStyle | undefined;
39 | statusBarHidden: boolean | undefined;
40 | navigationBarHidden: boolean | undefined;
41 | }>(
42 | (prev, cur) => {
43 | for (const prop in cur) {
44 | if (cur[prop as keyof SystemBarsEntry] != null) {
45 | // @ts-expect-error
46 | prev[prop] = cur[prop];
47 | }
48 | }
49 | return prev;
50 | },
51 | {
52 | statusBarStyle: undefined,
53 | navigationBarStyle: undefined,
54 | statusBarHidden: undefined,
55 | navigationBarHidden: undefined,
56 | },
57 | );
58 | }
59 |
60 | function resolveProps({ hidden, style }: SystemBarsProps) {
61 | const compactStyle = typeof style === "string";
62 | const compactHidden = typeof hidden === "boolean";
63 |
64 | return {
65 | statusBarStyle: compactStyle ? style : style?.statusBar,
66 | navigationBarStyle: compactStyle ? style : style?.navigationBar,
67 | statusBarHidden: compactHidden ? hidden : hidden?.statusBar,
68 | navigationBarHidden: compactHidden ? hidden : hidden?.navigationBar,
69 | };
70 | }
71 |
72 | /**
73 | * Returns an object to insert in the props stack from the props.
74 | */
75 | function createStackEntry(props: SystemBarsProps): SystemBarsEntry {
76 | return resolveProps(props);
77 | }
78 |
79 | const entriesStack: SystemBarsEntry[] = [];
80 |
81 | // Timer for updating the native module values at the end of the frame.
82 | let updateImmediate: NodeJS.Immediate | null = null;
83 |
84 | // The current merged values from the entries stack.
85 | const currentValues: {
86 | statusBarStyle: ResolvedBarStyle;
87 | navigationBarStyle: ResolvedBarStyle;
88 | statusBarHidden: boolean | undefined;
89 | navigationBarHidden: boolean | undefined;
90 | } = {
91 | statusBarStyle: undefined,
92 | navigationBarStyle: undefined,
93 | statusBarHidden: undefined,
94 | navigationBarHidden: undefined,
95 | };
96 |
97 | function setStatusBarStyle(style: ResolvedBarStyle) {
98 | if (style !== currentValues.statusBarStyle) {
99 | currentValues.statusBarStyle = style;
100 |
101 | const nativeStyle = toNativeBarStyle(style);
102 |
103 | if (Platform.OS === "android") {
104 | NativeModule?.setStatusBarStyle(nativeStyle);
105 | } else if (Platform.OS === "ios") {
106 | StatusBar.setBarStyle(nativeStyle, true);
107 | }
108 | }
109 | }
110 |
111 | function setNavigationBarStyle(style: ResolvedBarStyle) {
112 | if (style !== currentValues.navigationBarStyle) {
113 | currentValues.navigationBarStyle = style;
114 |
115 | if (Platform.OS === "android") {
116 | const nativeStyle = toNativeBarStyle(style);
117 | NativeModule?.setNavigationBarStyle(nativeStyle);
118 | }
119 | }
120 | }
121 |
122 | function setStatusBarHidden(hidden: boolean) {
123 | if (hidden !== currentValues.statusBarHidden) {
124 | currentValues.statusBarHidden = hidden;
125 |
126 | if (Platform.OS === "android") {
127 | NativeModule?.setStatusBarHidden(hidden);
128 | } else if (Platform.OS === "ios") {
129 | StatusBar.setHidden(hidden, "fade"); // 'slide' doesn't work in this context
130 | }
131 | }
132 | }
133 |
134 | function setNavigationBarHidden(hidden: boolean) {
135 | if (hidden !== currentValues.navigationBarHidden) {
136 | currentValues.navigationBarHidden = hidden;
137 |
138 | if (Platform.OS === "android") {
139 | NativeModule?.setNavigationBarHidden(hidden);
140 | }
141 | }
142 | }
143 |
144 | /**
145 | * Updates the native system bars with the entries from the stack.
146 | */
147 | function updateEntriesStack() {
148 | if (Platform.OS === "android" || Platform.OS === "ios") {
149 | if (updateImmediate != null) {
150 | clearImmediate(updateImmediate);
151 | }
152 |
153 | updateImmediate = setImmediate(() => {
154 | const mergedEntries = mergeEntriesStack(entriesStack);
155 | const { statusBarHidden, navigationBarHidden } = mergedEntries;
156 |
157 | const statusBarStyle = resolveSystemBarStyle(
158 | mergedEntries.statusBarStyle,
159 | );
160 | const navigationBarStyle = resolveSystemBarStyle(
161 | mergedEntries.navigationBarStyle,
162 | );
163 |
164 | setStatusBarStyle(statusBarStyle);
165 | setNavigationBarStyle(navigationBarStyle);
166 |
167 | if (statusBarHidden != null) {
168 | setStatusBarHidden(statusBarHidden);
169 | }
170 | if (navigationBarHidden != null) {
171 | setNavigationBarHidden(navigationBarHidden);
172 | }
173 | });
174 | }
175 | }
176 |
177 | /**
178 | * Push a `SystemBars` entry onto the stack.
179 | * The return value should be passed to `popStackEntry` when complete.
180 | *
181 | * @param props Object containing the `SystemBars` props to use in the stack entry.
182 | */
183 | function pushStackEntry(props: SystemBarsProps): SystemBarsEntry {
184 | const entry = createStackEntry(props);
185 | entriesStack.push(entry);
186 | updateEntriesStack();
187 | return entry;
188 | }
189 |
190 | /**
191 | * Remove an existing `SystemBars` stack entry from the stack.
192 | *
193 | * @param entry Entry returned from `pushStackEntry`.
194 | */
195 | function popStackEntry(entry: SystemBarsEntry): void {
196 | const index = entriesStack.indexOf(entry);
197 | if (index !== -1) {
198 | entriesStack.splice(index, 1);
199 | }
200 | updateEntriesStack();
201 | }
202 |
203 | /**
204 | * Replace an existing `SystemBars` stack entry with new props.
205 | *
206 | * @param entry Entry returned from `pushStackEntry` to replace.
207 | * @param props Object containing the `SystemBars` props to use in the replacement stack entry.
208 | */
209 | function replaceStackEntry(
210 | entry: SystemBarsEntry,
211 | props: SystemBarsProps,
212 | ): SystemBarsEntry {
213 | const newEntry = createStackEntry(props);
214 | const index = entriesStack.indexOf(entry);
215 | if (index !== -1) {
216 | entriesStack[index] = newEntry;
217 | }
218 | updateEntriesStack();
219 | return newEntry;
220 | }
221 |
222 | /**
223 | * Set the system bars style.
224 | *
225 | * @param style System bars style to set.
226 | */
227 | function setStyle(style: SystemBarsProps["style"]) {
228 | const props = resolveProps({ style });
229 |
230 | const statusBarStyle = resolveSystemBarStyle(props.statusBarStyle);
231 | const navigationBarStyle = resolveSystemBarStyle(props.navigationBarStyle);
232 |
233 | if (typeof statusBarStyle === "string") {
234 | setStatusBarStyle(statusBarStyle);
235 | }
236 | if (typeof navigationBarStyle === "string") {
237 | setNavigationBarStyle(navigationBarStyle);
238 | }
239 | }
240 |
241 | /**
242 | * Show or hide the system bars.
243 | *
244 | * @param hidden Hide the system bars.
245 | */
246 | function setHidden(hidden: SystemBarsProps["hidden"]) {
247 | const { statusBarHidden, navigationBarHidden } = resolveProps({ hidden });
248 |
249 | if (typeof statusBarHidden === "boolean") {
250 | setStatusBarHidden(statusBarHidden);
251 | }
252 | if (typeof navigationBarHidden === "boolean") {
253 | setNavigationBarHidden(navigationBarHidden);
254 | }
255 | }
256 |
257 | export function SystemBars(props: SystemBarsProps) {
258 | const {
259 | statusBarStyle,
260 | navigationBarStyle,
261 | statusBarHidden,
262 | navigationBarHidden,
263 | } = resolveProps(props);
264 |
265 | const stableProps = useMemo(
266 | () => ({
267 | style:
268 | statusBarStyle === navigationBarStyle
269 | ? statusBarStyle
270 | : { statusBar: statusBarStyle, navigationBar: navigationBarStyle },
271 | hidden:
272 | statusBarHidden === navigationBarHidden
273 | ? statusBarHidden
274 | : { statusBar: statusBarHidden, navigationBar: navigationBarHidden },
275 | }),
276 | [statusBarStyle, navigationBarStyle, statusBarHidden, navigationBarHidden],
277 | );
278 |
279 | const colorScheme = useColorScheme();
280 | const stackEntryRef = useRef(null);
281 |
282 | useEffect(() => {
283 | // Every time a SystemBars component is mounted, we push it's prop to a stack
284 | // and always update the native system bars with the props from the top of then
285 | // stack. This allows having multiple SystemBars components and the one that is
286 | // added last or is deeper in the view hierarchy will have priority.
287 | stackEntryRef.current = pushStackEntry(stableProps);
288 |
289 | return () => {
290 | // When a SystemBars is unmounted, remove itself from the stack and update
291 | // the native bars with the next props.
292 | if (stackEntryRef.current) {
293 | popStackEntry(stackEntryRef.current);
294 | }
295 | };
296 | }, []);
297 |
298 | useEffect(() => {
299 | if (stackEntryRef.current) {
300 | stackEntryRef.current = replaceStackEntry(
301 | stackEntryRef.current,
302 | stableProps,
303 | );
304 | }
305 | }, [colorScheme, stableProps]);
306 |
307 | return null;
308 | }
309 |
310 | SystemBars.pushStackEntry = pushStackEntry;
311 | SystemBars.popStackEntry = popStackEntry;
312 | SystemBars.replaceStackEntry = replaceStackEntry;
313 | SystemBars.setStyle = setStyle;
314 | SystemBars.setHidden = setHidden;
315 |
--------------------------------------------------------------------------------
/src/expo.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ConfigPlugin,
3 | createRunOncePlugin,
4 | withAndroidStyles,
5 | } from "@expo/config-plugins";
6 |
7 | type ParentTheme =
8 | | "Default"
9 | | "Material2"
10 | | "Material3"
11 | | "Material3.Dynamic"
12 | | "Light"
13 | | "Material2.Light"
14 | | "Material3.Light"
15 | | "Material3.Dynamic.Light";
16 |
17 | type AndroidProps = {
18 | enforceNavigationBarContrast?: boolean;
19 | parentTheme?: ParentTheme;
20 | };
21 |
22 | type Props = { android?: AndroidProps } | undefined;
23 |
24 | const withAndroidEdgeToEdgeTheme: ConfigPlugin = (
25 | config,
26 | props = {},
27 | ) => {
28 | const themes: Record = {
29 | Default: "Theme.EdgeToEdge",
30 | Material2: "Theme.EdgeToEdge.Material2",
31 | Material3: "Theme.EdgeToEdge.Material3",
32 | "Material3.Dynamic": "Theme.EdgeToEdge.Material3.Dynamic",
33 |
34 | Light: "Theme.EdgeToEdge.Light",
35 | "Material2.Light": "Theme.EdgeToEdge.Material2.Light",
36 | "Material3.Light": "Theme.EdgeToEdge.Material3.Light",
37 | "Material3.Dynamic.Light": "Theme.EdgeToEdge.Material3.Dynamic.Light",
38 | };
39 |
40 | const cleanupList = new Set([
41 | "enforceNavigationBarContrast",
42 | "android:enforceNavigationBarContrast",
43 | "android:enforceStatusBarContrast",
44 | "android:fitsSystemWindows",
45 | "android:navigationBarColor",
46 | "android:statusBarColor",
47 | "android:windowDrawsSystemBarBackgrounds",
48 | "android:windowLayoutInDisplayCutoutMode",
49 | "android:windowLightNavigationBar",
50 | "android:windowLightStatusBar",
51 | "android:windowTranslucentNavigation",
52 | "android:windowTranslucentStatus",
53 | ]);
54 |
55 | return withAndroidStyles(config, (config) => {
56 | const {
57 | androidNavigationBar = {},
58 | androidStatusBar = {},
59 | userInterfaceStyle = "light",
60 | } = config;
61 |
62 | const { barStyle: navigationBarStyle } = androidNavigationBar;
63 | const { barStyle: statusBarStyle } = androidStatusBar;
64 | const { android = {} } = props;
65 | const { enforceNavigationBarContrast, parentTheme = "Default" } = android;
66 |
67 | config.modResults.resources.style = config.modResults.resources.style?.map(
68 | (style): typeof style => {
69 | if (style.$.name === "AppTheme") {
70 | style.$.parent = themes[parentTheme] ?? themes["Default"];
71 |
72 | if (style.item != null) {
73 | style.item = style.item.filter(
74 | (item) => !cleanupList.has(item.$.name),
75 | );
76 | }
77 |
78 | if (statusBarStyle != null) {
79 | style.item.push({
80 | $: { name: "android:windowLightStatusBar" },
81 | _: String(statusBarStyle === "dark-content"),
82 | });
83 | } else if (userInterfaceStyle !== "automatic") {
84 | style.item.push({
85 | $: { name: "android:windowLightStatusBar" },
86 | _: String(userInterfaceStyle === "light"),
87 | });
88 | }
89 |
90 | if (enforceNavigationBarContrast === false) {
91 | if (navigationBarStyle != null) {
92 | style.item.push({
93 | $: { name: "android:windowLightNavigationBar" },
94 | _: String(navigationBarStyle === "dark-content"),
95 | });
96 | } else if (userInterfaceStyle !== "automatic") {
97 | style.item.push({
98 | $: { name: "android:windowLightNavigationBar" },
99 | _: String(navigationBarStyle === "light"),
100 | });
101 | }
102 |
103 | style.item.push({
104 | $: { name: "enforceNavigationBarContrast" },
105 | _: String(false),
106 | });
107 | }
108 | }
109 |
110 | return style;
111 | },
112 | );
113 |
114 | return config;
115 | });
116 | };
117 |
118 | export default createRunOncePlugin(
119 | withAndroidEdgeToEdgeTheme,
120 | "react-native-edge-to-edge",
121 | );
122 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export { SystemBars } from "./SystemBars";
2 | export { SystemBarStyle, SystemBarsEntry, SystemBarsProps } from "./types";
3 |
--------------------------------------------------------------------------------
/src/specs/NativeEdgeToEdgeModule.ts:
--------------------------------------------------------------------------------
1 | import type { TurboModule } from "react-native";
2 | import { Appearance, Platform, TurboModuleRegistry } from "react-native";
3 |
4 | interface Spec extends TurboModule {
5 | onColorSchemeChange(): void;
6 | setStatusBarStyle(style: string): void;
7 | setNavigationBarStyle(style: string): void;
8 | setStatusBarHidden(hidden: boolean): void;
9 | setNavigationBarHidden(hidden: boolean): void;
10 | }
11 |
12 | const NativeModule =
13 | Platform.OS === "android"
14 | ? TurboModuleRegistry.getEnforcing("RNEdgeToEdge")
15 | : null;
16 |
17 | if (NativeModule != null) {
18 | Appearance.addChangeListener(() => {
19 | NativeModule.onColorSchemeChange();
20 | });
21 | }
22 |
23 | export default NativeModule;
24 |
--------------------------------------------------------------------------------
/src/specs/NativeEdgeToEdgeModule.web.ts:
--------------------------------------------------------------------------------
1 | export default null;
2 |
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | type SystemBarsProp = T | { statusBar?: T; navigationBar?: T };
2 |
3 | export type SystemBarStyle = "auto" | "inverted" | "light" | "dark";
4 |
5 | export type SystemBarsEntry = {
6 | statusBarStyle: SystemBarStyle | undefined;
7 | navigationBarStyle: SystemBarStyle | undefined;
8 | statusBarHidden: boolean | undefined;
9 | navigationBarHidden: boolean | undefined;
10 | };
11 |
12 | export type SystemBarsProps = {
13 | style?: SystemBarsProp;
14 | hidden?: SystemBarsProp;
15 | };
16 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "ESNext",
4 | "lib": ["ES2017"],
5 | "jsx": "react-native",
6 | "moduleResolution": "Node",
7 |
8 | "allowJs": false,
9 | "strict": true,
10 | "declaration": true,
11 | "sourceMap": true,
12 | "stripInternal": true,
13 | "skipLibCheck": true,
14 |
15 | "allowUnreachableCode": false,
16 | "allowUnusedLabels": false,
17 | "noFallthroughCasesInSwitch": true,
18 | "noImplicitOverride": true,
19 | "noImplicitReturns": false,
20 | "noUncheckedIndexedAccess": true,
21 | "noUnusedLocals": true,
22 | "noUnusedParameters": true
23 | },
24 | "include": ["src"],
25 | "exclude": ["example", "node_modules"]
26 | }
27 |
--------------------------------------------------------------------------------