mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a429f4169c | ||
|
|
05f073d346 | ||
|
|
a0ca57538f | ||
|
|
292f3a4cab | ||
|
|
68231cb949 |
+1
-6
@@ -26,9 +26,6 @@
|
||||
; helloworld
|
||||
<PROJECT_ROOT>/packages/helloworld/ios/Pods/
|
||||
|
||||
; Ignore rn-tester Pods
|
||||
<PROJECT_ROOT>/packages/rn-tester/Pods/
|
||||
|
||||
[untyped]
|
||||
.*/node_modules/@react-native-community/cli/.*/.*
|
||||
|
||||
@@ -72,8 +69,6 @@ suppress_type=$FlowFixMeProps
|
||||
suppress_type=$FlowFixMeState
|
||||
suppress_type=$FlowFixMeEmpty
|
||||
|
||||
ban_spread_key_props=true
|
||||
|
||||
[lints]
|
||||
sketchy-null-number=warn
|
||||
sketchy-null-mixed=warn
|
||||
@@ -95,4 +90,4 @@ untyped-import
|
||||
untyped-type-import
|
||||
|
||||
[version]
|
||||
^0.253.0
|
||||
^0.251.1
|
||||
|
||||
@@ -3,6 +3,9 @@ description: Prepare iOS Tests
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: brew install xcbeautify
|
||||
run: brew install xcbeautify
|
||||
shell: bash
|
||||
- name: Run Ruby Tests
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
@@ -121,21 +121,21 @@ runs:
|
||||
if: ${{ inputs.run-unit-tests != 'true' && inputs.run-e2e-tests == 'false' }}
|
||||
shell: bash
|
||||
run: |
|
||||
xcodebuild build \
|
||||
set -o pipefail && xcodebuild build \
|
||||
-workspace packages/rn-tester/RNTesterPods.xcworkspace \
|
||||
-scheme RNTester \
|
||||
-sdk iphonesimulator
|
||||
-sdk iphonesimulator | xcbeautify
|
||||
- name: Build RNTester (E2E Tests)
|
||||
shell: bash
|
||||
if: ${{ inputs.run-e2e-tests == 'true' }}
|
||||
run: |
|
||||
xcodebuild \
|
||||
set -o pipefail && xcodebuild \
|
||||
-scheme "RNTester" \
|
||||
-workspace packages/rn-tester/RNTesterPods.xcworkspace \
|
||||
-configuration "${{ inputs.flavor }}" \
|
||||
-sdk "iphonesimulator" \
|
||||
-destination "generic/platform=iOS Simulator" \
|
||||
-derivedDataPath "/tmp/RNTesterBuild"
|
||||
-derivedDataPath "/tmp/RNTesterBuild" | xcbeautify
|
||||
|
||||
echo "Print path to *.app file"
|
||||
find "/tmp/RNTesterBuild" -type d -name "*.app"
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
name: test-library-on-nightly
|
||||
description: Tests a library on a nightly
|
||||
inputs:
|
||||
library-npm-package:
|
||||
description: The library npm package to add
|
||||
required: true
|
||||
platform:
|
||||
description: whether we want to build for iOS or Android
|
||||
required: true
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Create new app
|
||||
shell: bash
|
||||
run: |
|
||||
cd /tmp
|
||||
npx @react-native-community/cli init RNApp --skip-install --version nightly
|
||||
- name: Add library
|
||||
shell: bash
|
||||
run: |
|
||||
cd /tmp/RNApp
|
||||
yarn add ${{ inputs.library-npm-package }}
|
||||
|
||||
- name: Build iOS
|
||||
shell: bash
|
||||
if: ${{ inputs.platform == 'ios' }}
|
||||
run: |
|
||||
cd /tmp/RNApp/ios
|
||||
bundle install
|
||||
bundle exec pod install
|
||||
xcodebuild build \
|
||||
-workspace RNApp.xcworkspace \
|
||||
-scheme RNApp \
|
||||
-sdk iphonesimulator
|
||||
- name: Setup Java for Android
|
||||
if: ${{ inputs.platform == 'android' }}
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
- name: Build Android
|
||||
shell: bash
|
||||
if: ${{ inputs.platform == 'android' }}
|
||||
run: |
|
||||
cd /tmp/RNApp/android
|
||||
./gradlew assembleDebug
|
||||
@@ -48,84 +48,96 @@ module.exports = async (github, context, labelWithContext) => {
|
||||
switch (labelWithContext.label) {
|
||||
case 'Type: Invalid':
|
||||
await addComment(
|
||||
`> [!CAUTION]\n` +
|
||||
`> **Invalid issue**: This issue is not valid, either is not a bug in React Native, it doesn't match any of the issue template, or we can't help further with this.`,
|
||||
`| :warning: | Issue is Invalid |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | This issue doesn't match any of the expected types for this repository - closing. |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Type: Question':
|
||||
await addComment(
|
||||
`> [!NOTE]\n` +
|
||||
`> **Not a bug report**: This issue looks like a question. We are using GitHub issues exclusively to track bugs in React Native. GitHub may not be the ideal place to ask a question, but you can try asking over on [Stack Overflow](http://stackoverflow.com/questions/tagged/react-native), or on [Reactiflux](https://www.reactiflux.com/).`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Resolution: For Stack Overflow':
|
||||
await addComment(
|
||||
`> [!NOTE]\n` +
|
||||
`> **Not a bug report**: This issue looks like a question. We are using GitHub issues exclusively to track bugs in React Native. GitHub may not be the ideal place to ask a question, but you can try asking over on [Stack Overflow](http://stackoverflow.com/questions/tagged/react-native), or on [Reactiflux](https://www.reactiflux.com/).`,
|
||||
`| :warning: | Issue is a Question |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | We are using GitHub issues exclusively to track bugs in React Native. GitHub may not be the ideal place to ask a question, but you can try asking over on [Stack Overflow](http://stackoverflow.com/questions/tagged/react-native), or on [Reactiflux](https://www.reactiflux.com/). |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Type: Docs':
|
||||
await addComment(
|
||||
`> [!NOTE]\n` +
|
||||
`> **Docs issue**: This issue looks like an issue related to our docs. Please report documentation issues in the [react-native-website](https://github.com/facebook/react-native-website/issues) repository.`,
|
||||
`| :warning: | Documentation Issue |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | Please report documentation issues in the [react-native-website](https://github.com/facebook/react-native-website/issues) repository. |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Resolution: For Stack Overflow':
|
||||
await addComment(
|
||||
`| :warning: | Issue is a Question |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | We are using GitHub issues exclusively to track bugs in the core React Native library. Please try asking over on [Stack Overflow](http://stackoverflow.com/questions/tagged/react-native) as it is better suited for this type of question. |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Type: Expo':
|
||||
await addComment(
|
||||
`> [!NOTE]\n` +
|
||||
`> **Expo related**: It looks like your issue is related to Expo and not React Native core. Please open your issue in [Expo's repository](https://github.com/expo/expo/issues/new). If you are able to create a repro that showcases that this issue is also happening in React Native vanilla, we will be happy to re-open.`,
|
||||
`| :warning: | Issue is Related to Expo |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | It looks like your issue is related to Expo and not React Native core. Please open your issue in [Expo's repository](https://github.com/expo/expo/issues/new). If you are able to create a repro that showcases that this issue is also happening in React Native vanilla, we will be happy to re-open. |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Needs: Issue Template':
|
||||
await addComment(
|
||||
`> [!WARNING]\n` +
|
||||
`> **Missing issue template**: It looks like your issue may be missing some necessary information. GitHub provides an example template whenever a [new issue is created](https://github.com/facebook/react-native/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A&projects=&template=bug_report.yml). Could you go back and make sure to fill out the template? You may edit this issue, or close it and open a new one.`,
|
||||
`| :warning: | Missing Required Fields |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | It looks like your issue may be missing some necessary information. GitHub provides an example template whenever a [new issue is created](https://github.com/facebook/react-native/issues/new?template=bug_report.md). Could you go back and make sure to fill out the template? You may edit this issue, or close it and open a new one. |`,
|
||||
);
|
||||
await requestAuthorFeedback();
|
||||
return;
|
||||
case 'Needs: Environment Info':
|
||||
await addComment(
|
||||
`> [!WARNING]\n` +
|
||||
`> **Missing info**: It looks like your issue may be missing information about your development environment. You can obtain the missing information by running <code>react-native info</code> in a console.`,
|
||||
`| :warning: | Missing Environment Information |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | Your issue may be missing information about your development environment. You can obtain the missing information by running <code>react-native info</code> in a console. |`,
|
||||
);
|
||||
await requestAuthorFeedback();
|
||||
return;
|
||||
case 'Newer Patch Available':
|
||||
await addComment(
|
||||
`> [!TIP]\n` +
|
||||
`> **Newer version available**: You are on a supported minor version, but it looks like there's a newer patch available - ${labelWithContext.newestPatch}. Please [upgrade](https://reactnative.dev/docs/upgrading) to the highest patch for your minor or latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If it does not repro, please let us know so we can close out this issue. This helps us ensure we are looking at issues that still exist in the most recent releases.`,
|
||||
`| :warning: | Newer Version of React Native is Available! |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | You are on a supported minor version, but it looks like there's a newer patch available - ${labelWithContext.newestPatch}. Please [upgrade](https://reactnative.dev/docs/upgrading) to the highest patch for your minor or latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If it does not repro, please let us know so we can close out this issue. This helps us ensure we are looking at issues that still exist in the most recent releases. |`,
|
||||
);
|
||||
return;
|
||||
case 'Needs: Version Info':
|
||||
await addComment(
|
||||
`> [!WARNING]\n` +
|
||||
`> **Could not parse version**: We could not find or parse the version number of React Native in your issue report. Please use the template, and report your version including major, minor, and patch numbers - e.g. 0.76.2.`,
|
||||
`| :warning: | Add or Reformat Version Info |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | We could not find or parse the version number of React Native in your issue report. Please use the template, and report your version including major, minor, and patch numbers - e.g. 0.70.2 |`,
|
||||
);
|
||||
await requestAuthorFeedback();
|
||||
return;
|
||||
case 'Needs: Repro':
|
||||
await addComment(
|
||||
`> [!WARNING]\n` +
|
||||
`> **Missing reproducer**: We could not detect a reproducible example in your issue report. Please provide either: <br/><ul><li>If your bug is UI related: a [Snack](https://snack.expo.dev)</li><li> If your bug is build/upgrade related: a project using our [Reproducer Template](https://github.com/react-native-community/reproducer-react-native/generate)</li><li>Otherwise send us a Pull Request with the [RNTesterPlayground.js](https://github.com/facebook/react-native/blob/main/packages/rn-tester/js/examples/Playground/RNTesterPlayground.js) edited to reproduce your bug.</li></ul>`,
|
||||
`| :warning: | Missing Reproducible Example |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | We could not detect a reproducible example in your issue report. Please provide either: <br /><ul><li>If your bug is UI related: a [Snack](https://snack.expo.dev)</li><li> If your bug is build/update related: use our [Reproducer Template](https://github.com/react-native-community/reproducer-react-native/generate)</li></ul> |`,
|
||||
);
|
||||
await requestAuthorFeedback();
|
||||
return;
|
||||
case 'Type: Unsupported Version':
|
||||
await addComment(
|
||||
`> [!WARNING]\n` +
|
||||
`> **Unsupported version**: It looks like your issue or the example you provided uses an [unsupported version of React Native](https://github.com/reactwg/react-native-releases/blob/main/docs/support.md).<br/><br/>Due to the number of issues we receive, we're currently only accepting new issues against one of the supported versions. Please [upgrade](https://reactnative.dev/docs/upgrading) to latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If you cannot upgrade, please open your issue on [StackOverflow](https://stackoverflow.com/questions/tagged/react-native) to get further community support.`,
|
||||
`| :warning: | Unsupported Version of React Native |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | It looks like your issue or the example you provided uses an [unsupported version of React Native](https://github.com/reactwg/react-native-releases/blob/main/README.md#releases-support-policy).<br/><br/>Due to the number of issues we receive, we're currently only accepting new issues against one of the supported versions. Please [upgrade](https://reactnative.dev/docs/upgrading) to latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If you cannot upgrade, please open your issue on [StackOverflow](https://stackoverflow.com/questions/tagged/react-native) to get further community support. |`,
|
||||
);
|
||||
await requestAuthorFeedback();
|
||||
return;
|
||||
case 'Type: Too Old Version':
|
||||
await addComment(
|
||||
`> [!CAUTION]\n` +
|
||||
`> **Too old version**: It looks like your issue or the example you provided uses a [**Too Old Version of React Native**](https://github.com/reactwg/react-native-releases/blob/main/docs/support.md).<br/><br/>Due to the number of issues we receive, we're currently only accepting new issues against one of the supported versions. Please [upgrade](https://reactnative.dev/docs/upgrading) to latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If you cannot upgrade, please open your issue on [StackOverflow](https://stackoverflow.com/questions/tagged/react-native) to get further community support.`,
|
||||
`| :warning: | Too Old Version of React Native |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | It looks like your issue or the example you provided uses a [**Too Old Version of React Native**](https://github.com/reactwg/react-native-releases/blob/main/README.md#releases-support-policy).<br/><br/>Due to the number of issues we receive, we're currently only accepting new issues against one of the supported versions. Please [upgrade](https://reactnative.dev/docs/upgrading) to latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If you cannot upgrade, please open your issue on [StackOverflow](https://stackoverflow.com/questions/tagged/react-native) to get further community support. |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
|
||||
const NEEDS_REPRO_LABEL = 'Needs: Repro';
|
||||
const NEEDS_AUTHOR_FEEDBACK_LABEL = 'Needs: Author Feedback';
|
||||
const NEEDS_REPRO_HEADER = 'Missing Reproducible Example';
|
||||
const NEEDS_REPRO_MESSAGE =
|
||||
`| :warning: | Missing Reproducible Example |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | We could not detect a reproducible example in your issue report. Please provide either: <br /><ul><li>If your bug is UI related: a [Snack](https://snack.expo.dev)</li><li> If your bug is build/update related: use our [Reproducer Template](https://github.com/react-native-community/reproducer-react-native/generate). A reproducer needs to be in a GitHub repository under your username.</li></ul> |`;
|
||||
const SKIP_ISSUES_OLDER_THAN = '2023-07-01T00:00:00Z';
|
||||
|
||||
module.exports = async (github, context) => {
|
||||
@@ -20,6 +25,7 @@ module.exports = async (github, context) => {
|
||||
|
||||
const issue = await github.rest.issues.get(issueData);
|
||||
const comments = await github.rest.issues.listComments(issueData);
|
||||
|
||||
const author = issue.data.user.login;
|
||||
|
||||
const issueDate = issue.data.created_at;
|
||||
@@ -37,6 +43,10 @@ module.exports = async (github, context) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const botComment = comments.data.find(comment =>
|
||||
comment.body.includes(NEEDS_REPRO_HEADER),
|
||||
);
|
||||
|
||||
const entities = [issue.data, ...comments.data];
|
||||
|
||||
// Look for Snack or a GH repo associated with the user that added an issue or comment
|
||||
@@ -64,11 +74,25 @@ module.exports = async (github, context) => {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!botComment) return;
|
||||
|
||||
await github.rest.issues.deleteComment({
|
||||
...issueData,
|
||||
comment_id: botComment.id,
|
||||
});
|
||||
} else {
|
||||
await github.rest.issues.addLabels({
|
||||
...issueData,
|
||||
labels: [NEEDS_REPRO_LABEL, NEEDS_AUTHOR_FEEDBACK_LABEL],
|
||||
});
|
||||
|
||||
if (botComment) return;
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
...issueData,
|
||||
body: NEEDS_REPRO_MESSAGE,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -77,7 +101,7 @@ function containsPattern(body, pattern) {
|
||||
return body.search(regexp) !== -1;
|
||||
}
|
||||
|
||||
// Prevents the bot from responding when maintainer has changed the 'Needs: Repro' label
|
||||
// Prevents the bot from responding when maintainer has changed Needs: Repro the label
|
||||
async function hasMaintainerChangedLabel(github, issueData, author) {
|
||||
const timeline = await github.rest.issues.listEventsForTimeline(issueData);
|
||||
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
module.exports = async (github, context) => {
|
||||
const issue = context.payload.issue;
|
||||
|
||||
// Ignore issues using upgrade template (they use a special label)
|
||||
if (issue.labels.find(label => label.name === 'Type: Upgrade Issue')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const issueVersionUnparsed =
|
||||
getReactNativeVersionFromIssueBodyIfExists(issue);
|
||||
const issueVersion = parseVersionFromString(issueVersionUnparsed);
|
||||
|
||||
@@ -13,8 +13,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'facebook/react-native'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Check nightly
|
||||
run: |
|
||||
TODAY=$(date "+%Y%m%d")
|
||||
@@ -26,7 +24,3 @@ jobs:
|
||||
else
|
||||
echo 'Nightly Worked, All Good!'
|
||||
fi
|
||||
|
||||
test-libraries:
|
||||
uses: ./.github/workflows/test-libraries-on-nightlies.yml
|
||||
needs: check-nightly
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
name: Test Libraries on Nightlies
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
test-library-on-nightly-android:
|
||||
name: "[Android] ${{ matrix.library }}"
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
library: [
|
||||
"react-native-async-storage",
|
||||
"react-native-blob-util",
|
||||
"@react-native-clipboard/clipboard",
|
||||
"@react-native-community/datetimepicker",
|
||||
"react-native-gesture-handler",
|
||||
"react-native-image-picker",
|
||||
"react-native-linear-gradient",
|
||||
"@react-native-masked-view/masked-view",
|
||||
"react-native-maps",
|
||||
"@react-native-community/netinfo",
|
||||
"react-native-reanimated",
|
||||
"react-native-svg",
|
||||
"react-native-video",
|
||||
"react-native-webview",
|
||||
"react-native-mmkv",
|
||||
"react-native-screens",
|
||||
"react-native-pager-view",
|
||||
"@react-native-community/slider"
|
||||
]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Test ${{ inputs.library-name }}
|
||||
uses: ./.github/actions/test-library-on-nightly
|
||||
with:
|
||||
library-npm-package: ${{ matrix.library }}
|
||||
platform: android
|
||||
|
||||
test-library-on-nightly-ios:
|
||||
name: "[iOS] ${{ matrix.library }}"
|
||||
runs-on: macos-13-large
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
library: [
|
||||
"react-native-async-storage",
|
||||
"react-native-blob-util",
|
||||
"@react-native-clipboard/clipboard",
|
||||
"@react-native-community/datetimepicker",
|
||||
"react-native-gesture-handler",
|
||||
"react-native-image-picker",
|
||||
"react-native-linear-gradient",
|
||||
"@react-native-masked-view/masked-view",
|
||||
"react-native-maps",
|
||||
"@react-native-community/netinfo",
|
||||
"react-native-reanimated",
|
||||
"react-native-svg",
|
||||
"react-native-video",
|
||||
"react-native-webview",
|
||||
"react-native-mmkv",
|
||||
"react-native-screens",
|
||||
"react-native-pager-view",
|
||||
"@react-native-community/slider"
|
||||
]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Test ${{ inputs.library-name }}
|
||||
uses: ./.github/actions/test-library-on-nightly
|
||||
with:
|
||||
library-npm-package: ${{ matrix.library }}
|
||||
platform: ios
|
||||
+1
-4
@@ -124,7 +124,7 @@ vendor/
|
||||
!/packages/rn-tester/Pods/__offline_mirrors_jsc__
|
||||
|
||||
# @react-native/codegen
|
||||
/packages/react-native/React/FBReactNativeSpec/
|
||||
/packages/react-native/React/FBReactNativeSpec/FBReactNativeSpec
|
||||
/packages/react-native-codegen/lib
|
||||
/packages/react-native-codegen/tmp/
|
||||
/packages/react-native/ReactCommon/react/renderer/components/rncore/
|
||||
@@ -155,6 +155,3 @@ vendor/
|
||||
|
||||
# CircleCI
|
||||
.circleci/generated_config.yml
|
||||
|
||||
# Jest Integration
|
||||
/jest/integration/build/
|
||||
|
||||
@@ -1,40 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## v0.76.2
|
||||
|
||||
### Added
|
||||
|
||||
- **TypeScript** Add CodegenTypes for TS ([20b141508b](https://github.com/facebook/react-native/commit/20b141508b30324d52080c255dd3fb318718d746) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
|
||||
### Changed
|
||||
|
||||
- **infra** Bump CLI to 15.0.1 ([51b98c24bd](https://github.com/facebook/react-native/commit/51b98c24bdc6369ce6fabcacaf8df2d2a706eada) by [@szymonrybczak](https://github.com/szymonrybczak))
|
||||
|
||||
#### iOS specific
|
||||
|
||||
- **TextInput** Include existing attributes in newly typed text ([557e3447f5](https://github.com/facebook/react-native/commit/557e3447f520e40a1ec0ae344126b4f2836d2e83) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Hermes** Update Hermes to support Intl ([94d4bfd7c8](https://github.com/facebook/react-native/commit/94d4bfd7c80ba0d55adbff656441b55d59055bcc) by [@blakef](https://github.com/blakef))
|
||||
- **infra** Skip hermes-parser under Babel for non-Flow JS code ([ff1261e7dc](https://github.com/facebook/react-native/commit/ff1261e7dc0ab7e241e1f14aa0d6fd17f2ba9328) by [@huntie](https://github.com/huntie))
|
||||
- **infra** fix `semver` not being found in pnpm setups ([0def73d1a6](https://github.com/facebook/react-native/commit/0def73d1a6e398d451585032ea1213f96d84fe9c) by [@tido64](https://github.com/tido64))
|
||||
- **Error Handling** Fix `setUpErrorHandling` to show early JS errors ([dac6d508af](https://github.com/facebook/react-native/commit/dac6d508afd0f919943d8053330d6314201319c3) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
|
||||
#### Android specific
|
||||
|
||||
- **infra** Use absolute path when compiling appmodules.so sources ([3956955eaa](https://github.com/facebook/react-native/commit/3956955eaa3cd8c50dfe35a68a6cb8fdcac43155) by [@cortinico](https://github.com/cortinico))
|
||||
- **infra** Properly handle paths with spaces in autolinking ([1f62529dc4](https://github.com/facebook/react-native/commit/1f62529dc4583af88ef06bee04c89ce6c2ef737f) by [@cortinico](https://github.com/cortinico))
|
||||
- **Modal** Fix Regression - Modal content rendering below system bar on < API 30 when activity is edge-to-edge ([2cd48ef351](https://github.com/facebook/react-native/commit/2cd48ef351d10333a14091188bbe8e3bcd6a7a01) by [@alanleedev](https://github.com/alanleedev))
|
||||
- **runtime** Fix timers in headless tasks on bridgeless mode ([ee7b4e2763](https://github.com/facebook/react-native/commit/ee7b4e276355146be53958b402bfb2d5af2dd1bc) by [@j-piasecki](https://github.com/j-piasecki))
|
||||
|
||||
#### iOS specific
|
||||
|
||||
- **Codegen** Properly stop generating component registration for components defined in app. ([97a4234b6e](https://github.com/facebook/react-native/commit/97a4234b6e51b3c35c82095029ef00270ad02e29) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- **infra** Give apps access to Yoga headers ([e851e73c18](https://github.com/facebook/react-native/commit/e851e73c1806a7b7b898a67716be87f42ced491a) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- **TextInput** Fix missing emitter attributes on iOS TextInput when controlled component value specified using `value` instead of `children` ([52cdedb40e](https://github.com/facebook/react-native/commit/52cdedb40e242c9ed280b821f8493a3872ef2b54) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- **TextInput** Fix cursor moving in iOS controlled single line TextInput on Autocorrection (New Arch) ([36fd5533f6](https://github.com/facebook/react-native/commit/36fd5533f68b0f907a949db87884b58820015ba8) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
|
||||
## v0.76.1
|
||||
|
||||
### Fixed
|
||||
@@ -1441,21 +1406,6 @@ created on the mqt_native thread. ([c4a6bbc8fd](https://github.com/facebook/reac
|
||||
|
||||
- Bump activesupport to minimum 6.1.7.5 CVE-2023-38037. ([07a159f279](https://github.com/facebook/react-native/commit/07a159f279cdcbed29c9c437dec1c0b8ac2d852f) by [@lunaleaps](https://github.com/lunaleaps))
|
||||
|
||||
## v0.73.11
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
|
||||
#### Android specific
|
||||
|
||||
- Suppress path adjustment when not actually drawing a border ([c9cf6d4b60](https://github.com/facebook/react-native/commit/c9cf6d4b60b6c5f717b3e5c9f3e3720e8d588707) by [@tjzel](https://github.com/tjzel))
|
||||
|
||||
#### iOS specific
|
||||
|
||||
- Stop generating dSYM path in Hermes for the framework ([e992405e87](https://github.com/facebook/react-native/commit/e992405e87) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Pin Xcodeproj to < 1.26.0 ([dfcad7c678](https://github.com/facebook/react-native/commit/dfcad7c678) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
|
||||
## v0.73.10
|
||||
|
||||
### Removed
|
||||
|
||||
Vendored
-20
@@ -16,13 +16,6 @@ declare interface undici$Agent$Options {
|
||||
}
|
||||
|
||||
declare module 'undici' {
|
||||
declare export type RequestOptions = $ReadOnly<{
|
||||
dispatcher?: Dispatcher,
|
||||
method?: string,
|
||||
headers?: HeadersInit,
|
||||
...
|
||||
}>;
|
||||
|
||||
declare export class Dispatcher extends events$EventEmitter {
|
||||
constructor(): void;
|
||||
}
|
||||
@@ -30,17 +23,4 @@ declare module 'undici' {
|
||||
declare export class Agent extends Dispatcher {
|
||||
constructor(opts?: undici$Agent$Options): void;
|
||||
}
|
||||
|
||||
declare export function request(
|
||||
url: string | URL,
|
||||
options: RequestOptions,
|
||||
): Promise<{
|
||||
statusCode: number,
|
||||
headers: Headers,
|
||||
body: {
|
||||
read(): Promise<Buffer>,
|
||||
...
|
||||
},
|
||||
...
|
||||
}>;
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const baseConfig = require('../../../jest.config');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
rootDir: path.resolve(__dirname, '../../..'),
|
||||
roots: [
|
||||
'<rootDir>/packages/react-native',
|
||||
'<rootDir>/jest/integration/runtime',
|
||||
],
|
||||
// This allows running Meta-internal tests with the `-test.fb.js` suffix.
|
||||
testRegex: '/__tests__/.*-itest(\\.fb)?\\.js$',
|
||||
testPathIgnorePatterns: baseConfig.testPathIgnorePatterns,
|
||||
transformIgnorePatterns: ['.*'],
|
||||
testRunner: './jest/integration/runner/index.js',
|
||||
watchPathIgnorePatterns: ['<rootDir>/jest/integration/build/'],
|
||||
};
|
||||
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const {getDefaultConfig} = require('@react-native/metro-config');
|
||||
const {mergeConfig} = require('metro-config');
|
||||
const path = require('path');
|
||||
|
||||
const rnTesterConfig = getDefaultConfig(
|
||||
path.resolve('../../../packages/rn-tester'),
|
||||
);
|
||||
|
||||
const config = {
|
||||
projectRoot: path.resolve(__dirname, '../../..'),
|
||||
reporter: {
|
||||
update: () => {},
|
||||
},
|
||||
resolver: {
|
||||
blockList: null,
|
||||
sourceExts: [...rnTesterConfig.resolver.sourceExts, 'fb.js'],
|
||||
nodeModulesPaths: process.env.JS_DIR
|
||||
? [path.join(process.env.JS_DIR, 'public', 'node_modules')]
|
||||
: [],
|
||||
},
|
||||
transformer: {
|
||||
// We need to wrap the default transformer so we can run it from source
|
||||
// using babel-register.
|
||||
babelTransformerPath: path.resolve(__dirname, 'metro-babel-transformer.js'),
|
||||
},
|
||||
watchFolders: process.env.JS_DIR ? [process.env.JS_DIR] : [],
|
||||
};
|
||||
|
||||
module.exports = mergeConfig(rnTesterConfig, config);
|
||||
@@ -1,35 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
module.exports = function entrypointTemplate({
|
||||
testPath,
|
||||
setupModulePath,
|
||||
}: {
|
||||
testPath: string,
|
||||
setupModulePath: string,
|
||||
}): string {
|
||||
return `/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* ${'@'}generated
|
||||
* @noformat
|
||||
* @noflow
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import {registerTest} from '${setupModulePath}';
|
||||
|
||||
registerTest(() => require('${testPath}'));
|
||||
`;
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
require('../../../scripts/build/babel-register').registerForMonorepo();
|
||||
|
||||
module.exports = require('./runner');
|
||||
@@ -1,209 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import type {TestSuiteResult} from '../runtime/setup';
|
||||
|
||||
import entrypointTemplate from './entrypoint-template';
|
||||
import {spawnSync} from 'child_process';
|
||||
import crypto from 'crypto';
|
||||
import fs from 'fs';
|
||||
// $FlowExpectedError[untyped-import]
|
||||
import {formatResultsErrors} from 'jest-message-util';
|
||||
import Metro from 'metro';
|
||||
import nullthrows from 'nullthrows';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
const BUILD_OUTPUT_PATH = path.resolve(__dirname, '..', 'build');
|
||||
|
||||
function parseRNTesterCommandResult(
|
||||
commandArgs: $ReadOnlyArray<string>,
|
||||
result: ReturnType<typeof spawnSync>,
|
||||
): {logs: string, testResult: TestSuiteResult} {
|
||||
const stdout = result.stdout.toString();
|
||||
|
||||
const outputArray = stdout
|
||||
.trim()
|
||||
.split('\n')
|
||||
.filter(log => !log.startsWith('Running "')); // remove AppRegistry logs.
|
||||
|
||||
// The last line should be the test output in JSON format
|
||||
const testResultJSON = outputArray.pop();
|
||||
|
||||
let testResult;
|
||||
try {
|
||||
testResult = JSON.parse(nullthrows(testResultJSON));
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
[
|
||||
'Failed to parse test results from RN tester binary result. Full output:',
|
||||
'buck2 ' + commandArgs.join(' '),
|
||||
'stdout:',
|
||||
stdout,
|
||||
'stderr:',
|
||||
result.stderr.toString(),
|
||||
].join('\n'),
|
||||
);
|
||||
}
|
||||
|
||||
return {logs: outputArray.join('\n'), testResult};
|
||||
}
|
||||
|
||||
function getBuckModeForPlatform() {
|
||||
switch (os.platform()) {
|
||||
case 'linux':
|
||||
return '@//arvr/mode/linux/dev';
|
||||
case 'darwin':
|
||||
return os.arch() === 'arm64'
|
||||
? '@//arvr/mode/mac-arm/dev'
|
||||
: '@//arvr/mode/mac/dev';
|
||||
case 'win32':
|
||||
return '@//arvr/mode/win/dev';
|
||||
default:
|
||||
throw new Error(`Unsupported platform: ${os.platform()}`);
|
||||
}
|
||||
}
|
||||
|
||||
function getShortHash(contents: string): string {
|
||||
return crypto.createHash('md5').update(contents).digest('hex').slice(0, 8);
|
||||
}
|
||||
|
||||
module.exports = async function runTest(
|
||||
globalConfig: {...},
|
||||
config: {...},
|
||||
environment: {...},
|
||||
runtime: {...},
|
||||
testPath: string,
|
||||
): mixed {
|
||||
const startTime = Date.now();
|
||||
|
||||
const metroConfig = await Metro.loadConfig({
|
||||
config: path.resolve(__dirname, '..', 'config', 'metro.config.js'),
|
||||
});
|
||||
|
||||
const setupModulePath = path.resolve(__dirname, '../runtime/setup.js');
|
||||
|
||||
const entrypointContents = entrypointTemplate({
|
||||
testPath: `.${path.sep}${path.relative(BUILD_OUTPUT_PATH, testPath)}`,
|
||||
setupModulePath: `.${path.sep}${path.relative(BUILD_OUTPUT_PATH, setupModulePath)}`,
|
||||
});
|
||||
|
||||
const entrypointPath = path.join(
|
||||
BUILD_OUTPUT_PATH,
|
||||
`${getShortHash(entrypointContents)}-${path.basename(testPath)}`,
|
||||
);
|
||||
const testBundlePath = entrypointPath + '.bundle';
|
||||
|
||||
fs.mkdirSync(path.dirname(entrypointPath), {recursive: true});
|
||||
fs.writeFileSync(entrypointPath, entrypointContents, 'utf8');
|
||||
|
||||
await Metro.runBuild(metroConfig, {
|
||||
entry: entrypointPath,
|
||||
out: testBundlePath,
|
||||
platform: 'android',
|
||||
minify: false,
|
||||
dev: true,
|
||||
});
|
||||
|
||||
const rnTesterCommandArgs = [
|
||||
'run',
|
||||
getBuckModeForPlatform(),
|
||||
'//xplat/ReactNative/react-native-cxx/samples/tester:tester',
|
||||
'--',
|
||||
`--bundlePath=${testBundlePath}`,
|
||||
];
|
||||
const rnTesterCommandResult = spawnSync('buck2', rnTesterCommandArgs, {
|
||||
encoding: 'utf8',
|
||||
env: {
|
||||
...process.env,
|
||||
PATH: `/usr/local/bin:${process.env.PATH ?? ''}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (rnTesterCommandResult.status !== 0) {
|
||||
throw new Error(
|
||||
[
|
||||
'Failed to run test in RN tester binary. Full output:',
|
||||
'buck2 ' + rnTesterCommandArgs.join(' '),
|
||||
'stdout:',
|
||||
rnTesterCommandResult.stdout,
|
||||
'stderr:',
|
||||
rnTesterCommandResult.stderr,
|
||||
'error:',
|
||||
rnTesterCommandResult.error,
|
||||
].join('\n'),
|
||||
);
|
||||
}
|
||||
|
||||
const rnTesterParsedOutput = parseRNTesterCommandResult(
|
||||
rnTesterCommandArgs,
|
||||
rnTesterCommandResult,
|
||||
);
|
||||
|
||||
const testResultError = rnTesterParsedOutput.testResult.error;
|
||||
if (testResultError) {
|
||||
const error = new Error(testResultError.message);
|
||||
error.stack = testResultError.stack;
|
||||
throw error;
|
||||
}
|
||||
|
||||
const endTime = Date.now();
|
||||
|
||||
if (process.env.SANDCASTLE == null) {
|
||||
console.log(rnTesterParsedOutput.logs);
|
||||
}
|
||||
|
||||
const testResults =
|
||||
nullthrows(rnTesterParsedOutput.testResult.testResults).map(testResult => ({
|
||||
ancestorTitles: [] as Array<string>,
|
||||
failureDetails: [] as Array<string>,
|
||||
testFilePath: testPath,
|
||||
...testResult,
|
||||
})) ?? [];
|
||||
|
||||
return {
|
||||
testFilePath: testPath,
|
||||
failureMessage: formatResultsErrors(
|
||||
testResults,
|
||||
config,
|
||||
globalConfig,
|
||||
testPath,
|
||||
),
|
||||
leaks: false,
|
||||
openHandles: [],
|
||||
perfStats: {
|
||||
start: startTime,
|
||||
end: endTime,
|
||||
duration: endTime - startTime,
|
||||
runtime: endTime - startTime,
|
||||
slow: false,
|
||||
},
|
||||
snapshot: {
|
||||
added: 0,
|
||||
fileDeleted: false,
|
||||
matched: 0,
|
||||
unchecked: 0,
|
||||
uncheckedKeys: [],
|
||||
unmatched: 0,
|
||||
updated: 0,
|
||||
},
|
||||
numTotalTests: testResults.length,
|
||||
numPassingTests: testResults.filter(test => test.status === 'passed')
|
||||
.length,
|
||||
numFailingTests: testResults.filter(test => test.status === 'failed')
|
||||
.length,
|
||||
numPendingTests: testResults.filter(test => test.status === 'pending')
|
||||
.length,
|
||||
numTodoTests: 0,
|
||||
skipped: false,
|
||||
testResults,
|
||||
};
|
||||
};
|
||||
@@ -1,259 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import nullthrows from 'nullthrows';
|
||||
|
||||
export type TestCaseResult = {
|
||||
ancestorTitles: Array<string>,
|
||||
title: string,
|
||||
fullName: string,
|
||||
status: 'passed' | 'failed' | 'pending',
|
||||
duration: number,
|
||||
failureMessages: Array<string>,
|
||||
numPassingAsserts: number,
|
||||
// location: string,
|
||||
};
|
||||
|
||||
export type TestSuiteResult =
|
||||
| {
|
||||
testResults: Array<TestCaseResult>,
|
||||
}
|
||||
| {
|
||||
error: {
|
||||
message: string,
|
||||
stack: string,
|
||||
},
|
||||
};
|
||||
|
||||
const tests: Array<{
|
||||
title: string,
|
||||
ancestorTitles: Array<string>,
|
||||
implementation: () => mixed,
|
||||
isFocused: boolean,
|
||||
isSkipped: boolean,
|
||||
result?: TestCaseResult,
|
||||
}> = [];
|
||||
|
||||
const ancestorTitles: Array<string> = [];
|
||||
|
||||
const globalModifiers: Array<'focused' | 'skipped'> = [];
|
||||
|
||||
const globalDescribe = (global.describe = (
|
||||
title: string,
|
||||
implementation: () => mixed,
|
||||
) => {
|
||||
ancestorTitles.push(title);
|
||||
implementation();
|
||||
ancestorTitles.pop();
|
||||
});
|
||||
|
||||
const globalIt =
|
||||
(global.it =
|
||||
global.test =
|
||||
(title: string, implementation: () => mixed) =>
|
||||
tests.push({
|
||||
title,
|
||||
implementation,
|
||||
ancestorTitles: ancestorTitles.slice(),
|
||||
isFocused:
|
||||
globalModifiers.length > 0 &&
|
||||
globalModifiers[globalModifiers.length - 1] === 'focused',
|
||||
isSkipped:
|
||||
globalModifiers.length > 0 &&
|
||||
globalModifiers[globalModifiers.length - 1] === 'skipped',
|
||||
}));
|
||||
|
||||
// $FlowExpectedError[prop-missing]
|
||||
global.fdescribe = global.describe.only = (
|
||||
title: string,
|
||||
implementation: () => mixed,
|
||||
) => {
|
||||
globalModifiers.push('focused');
|
||||
globalDescribe(title, implementation);
|
||||
globalModifiers.pop();
|
||||
};
|
||||
|
||||
// $FlowExpectedError[prop-missing]
|
||||
global.it.only =
|
||||
global.fit =
|
||||
// $FlowExpectedError[prop-missing]
|
||||
global.test.only =
|
||||
(title: string, implementation: () => mixed) => {
|
||||
globalModifiers.push('focused');
|
||||
globalIt(title, implementation);
|
||||
globalModifiers.pop();
|
||||
};
|
||||
|
||||
// $FlowExpectedError[prop-missing]
|
||||
global.xdescribe = global.describe.skip = (
|
||||
title: string,
|
||||
implementation: () => mixed,
|
||||
) => {
|
||||
globalModifiers.push('skipped');
|
||||
globalDescribe(title, implementation);
|
||||
globalModifiers.pop();
|
||||
};
|
||||
|
||||
// $FlowExpectedError[prop-missing]
|
||||
global.it.skip =
|
||||
global.xit =
|
||||
// $FlowExpectedError[prop-missing]
|
||||
global.test.skip =
|
||||
global.xtest =
|
||||
(title: string, implementation: () => mixed) => {
|
||||
globalModifiers.push('skipped');
|
||||
globalIt(title, implementation);
|
||||
globalModifiers.pop();
|
||||
};
|
||||
|
||||
// flowlint unsafe-getters-setters:off
|
||||
|
||||
class Expect {
|
||||
#received: mixed;
|
||||
#isNot: boolean = false;
|
||||
|
||||
constructor(received: mixed) {
|
||||
this.#received = received;
|
||||
}
|
||||
|
||||
get not(): this {
|
||||
this.#isNot = !this.#isNot;
|
||||
return this;
|
||||
}
|
||||
|
||||
toBe(expected: mixed): void {
|
||||
const pass = this.#received === expected;
|
||||
if (!this.#isExpectedResult(pass)) {
|
||||
throw new Error(
|
||||
`Expected${this.#maybeNotLabel()} ${String(expected)} but received ${String(this.#received)}.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
toBeInstanceOf(expected: Class<mixed>): void {
|
||||
const pass = this.#received instanceof expected;
|
||||
if (!this.#isExpectedResult(pass)) {
|
||||
throw new Error(
|
||||
`expected ${String(this.#received)}${this.#maybeNotLabel()} to be an instance of ${String(expected)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
toBeCloseTo(expected: number, precision: number = 2): void {
|
||||
const pass =
|
||||
Math.abs(expected - Number(this.#received)) < Math.pow(10, -precision);
|
||||
if (!this.#isExpectedResult(pass)) {
|
||||
throw new Error(
|
||||
`expected ${String(this.#received)}${this.#maybeNotLabel()} to be close to ${expected}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
toThrow(error: mixed): void {
|
||||
if (error != null) {
|
||||
throw new Error('toThrow() implementation does not accept arguments.');
|
||||
}
|
||||
|
||||
let pass = false;
|
||||
try {
|
||||
// $FlowExpectedError[not-a-function]
|
||||
this.#received();
|
||||
} catch {
|
||||
pass = true;
|
||||
}
|
||||
if (!this.#isExpectedResult(pass)) {
|
||||
throw new Error(
|
||||
`expected ${String(this.#received)}${this.#maybeNotLabel()} to throw`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#isExpectedResult(pass: boolean): boolean {
|
||||
return this.#isNot ? !pass : pass;
|
||||
}
|
||||
|
||||
#maybeNotLabel(): string {
|
||||
return this.#isNot ? ' not' : '';
|
||||
}
|
||||
}
|
||||
|
||||
global.expect = (received: mixed) => new Expect(received);
|
||||
|
||||
function runWithGuard(fn: () => void) {
|
||||
try {
|
||||
fn();
|
||||
} catch (error) {
|
||||
let reportedError =
|
||||
error instanceof Error ? error : new Error(String(error));
|
||||
reportTestSuiteResult({
|
||||
error: {
|
||||
message: reportedError.message,
|
||||
stack: reportedError.stack,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function executeTests() {
|
||||
const hasFocusedTests = tests.some(test => test.isFocused);
|
||||
|
||||
for (const test of tests) {
|
||||
const result: TestCaseResult = {
|
||||
title: test.title,
|
||||
fullName: [...test.ancestorTitles, test.title].join(' '),
|
||||
ancestorTitles: test.ancestorTitles,
|
||||
status: 'pending',
|
||||
duration: 0,
|
||||
failureMessages: [],
|
||||
numPassingAsserts: 0,
|
||||
};
|
||||
|
||||
test.result = result;
|
||||
|
||||
if (!test.isSkipped && (!hasFocusedTests || test.isFocused)) {
|
||||
let status;
|
||||
let error;
|
||||
|
||||
const start = Date.now();
|
||||
|
||||
try {
|
||||
test.implementation();
|
||||
status = 'passed';
|
||||
} catch (e) {
|
||||
error = e;
|
||||
status = 'failed';
|
||||
}
|
||||
|
||||
result.status = status;
|
||||
result.duration = Date.now() - start;
|
||||
result.failureMessages =
|
||||
status === 'failed' && error ? [error.message] : [];
|
||||
}
|
||||
}
|
||||
|
||||
reportTestSuiteResult({
|
||||
testResults: tests.map(test => nullthrows(test.result)),
|
||||
});
|
||||
}
|
||||
|
||||
function reportTestSuiteResult(testSuiteResult: TestSuiteResult): void {
|
||||
console.log(JSON.stringify(testSuiteResult));
|
||||
}
|
||||
|
||||
global.$$RunTests$$ = () => {
|
||||
executeTests();
|
||||
};
|
||||
|
||||
export function registerTest(setUpTest: () => void) {
|
||||
runWithGuard(() => {
|
||||
setUpTest();
|
||||
});
|
||||
}
|
||||
+1
-4
@@ -77,7 +77,7 @@
|
||||
"eslint-plugin-redundant-undefined": "^0.4.0",
|
||||
"eslint-plugin-relay": "^1.8.3",
|
||||
"flow-api-translator": "0.24.0",
|
||||
"flow-bin": "^0.253.0",
|
||||
"flow-bin": "^0.251.1",
|
||||
"glob": "^7.1.1",
|
||||
"hermes-eslint": "0.24.0",
|
||||
"hermes-transform": "0.24.0",
|
||||
@@ -101,8 +101,5 @@
|
||||
"supports-color": "^7.1.0",
|
||||
"typescript": "5.0.4",
|
||||
"ws": "^6.2.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"react-is": "18.3.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,10 @@ import isDevServerRunning from '../../utils/isDevServerRunning';
|
||||
import loadMetroConfig from '../../utils/loadMetroConfig';
|
||||
import * as version from '../../utils/version';
|
||||
import attachKeyHandlers from './attachKeyHandlers';
|
||||
import {createDevServerMiddleware, indexPageMiddleware} from './middleware';
|
||||
import {
|
||||
createDevServerMiddleware,
|
||||
indexPageMiddleware,
|
||||
} from '@react-native-community/cli-server-api';
|
||||
import {createDevMiddleware} from '@react-native/dev-middleware';
|
||||
import chalk from 'chalk';
|
||||
import Metro from 'metro';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@generated SignedSource<<6b92b66e59525cef52902139f863f175>>
|
||||
Git revision: b61aae3ccc6e2684dfbf1e2a06b0f985b459f11f
|
||||
@generated SignedSource<<b5e82d2eb99e1ed4c012065a530ca78b>>
|
||||
Git revision: ff343d805527223750fafb8573ee48f8e2fb0d1e
|
||||
Built with --nohooks: false
|
||||
Is local checkout: false
|
||||
Remote URL: https://github.com/facebookexperimental/rn-chrome-devtools-frontend
|
||||
|
||||
+14
-14
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -10,9 +10,8 @@
|
||||
*/
|
||||
|
||||
import type {JSONSerializable} from '../inspector-proxy/types';
|
||||
import type {RequestOptions} from 'undici';
|
||||
|
||||
import {Agent, request} from 'undici';
|
||||
import {Agent} from 'undici';
|
||||
|
||||
declare var globalThis: $FlowFixMe;
|
||||
|
||||
@@ -20,22 +19,15 @@ declare var globalThis: $FlowFixMe;
|
||||
* A version of `fetch` that is usable with the HTTPS server created in
|
||||
* ServerUtils (which uses a self-signed certificate).
|
||||
*/
|
||||
export async function requestLocal(
|
||||
export async function fetchLocal(
|
||||
url: string,
|
||||
options?: RequestOptions,
|
||||
): Promise<{
|
||||
statusCode: number,
|
||||
headers: Headers,
|
||||
bodyBuffer: Buffer,
|
||||
}> {
|
||||
const {
|
||||
statusCode,
|
||||
headers: rawHeaders,
|
||||
body,
|
||||
} = await request(url, {
|
||||
options?: Partial<Parameters<typeof fetch>[1] & {dispatcher?: mixed}>,
|
||||
): ReturnType<typeof fetch> {
|
||||
return await fetch(url, {
|
||||
...options,
|
||||
|
||||
// Use undici's `dispatcher` to make it accept self-signed certificates.
|
||||
// Node's native `fetch` comes from undici and supports the same options,
|
||||
// including `dispatcher` which we use to make it accept self-signed
|
||||
// certificates.
|
||||
dispatcher:
|
||||
options?.dispatcher ??
|
||||
new Agent({
|
||||
@@ -44,22 +36,14 @@ export async function requestLocal(
|
||||
},
|
||||
}),
|
||||
});
|
||||
return {
|
||||
statusCode,
|
||||
bodyBuffer: await body.read(),
|
||||
headers: new Headers(rawHeaders),
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchJson<T: JSONSerializable>(url: string): Promise<T> {
|
||||
const response = await requestLocal(url);
|
||||
if (response.statusCode !== 200) {
|
||||
throw new Error(`HTTP ${response.statusCode}`);
|
||||
const response = await fetchLocal(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status} ${response.statusText}`);
|
||||
}
|
||||
if (!response.headers.get('Content-Type')?.startsWith('application/json')) {
|
||||
throw new Error('Expected Content-Type: application/json');
|
||||
}
|
||||
return JSON.parse(response.bodyBuffer.toString());
|
||||
return response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -295,42 +295,6 @@ describe.each(['HTTP', 'HTTPS'])(
|
||||
debugger_.close();
|
||||
}
|
||||
});
|
||||
|
||||
describe('Network.loadNetworkResource', () => {
|
||||
test('should respond with an error without forwarding to the client', async () => {
|
||||
const {device, debugger_} = await createAndConnectTarget(
|
||||
serverRef,
|
||||
autoCleanup.signal,
|
||||
{
|
||||
app: 'bar-app',
|
||||
id: 'page1',
|
||||
title: 'bar-title',
|
||||
vm: 'bar-vm',
|
||||
},
|
||||
);
|
||||
try {
|
||||
const response = await debugger_.sendAndGetResponse({
|
||||
id: 1,
|
||||
method: 'Network.loadNetworkResource',
|
||||
params: {
|
||||
url: 'http://example.com',
|
||||
},
|
||||
});
|
||||
expect(response.result).toEqual(
|
||||
expect.objectContaining({
|
||||
error: {
|
||||
code: -32601,
|
||||
message:
|
||||
'[inspector-proxy]: Page lacks nativeSourceCodeFetching capability.',
|
||||
},
|
||||
}),
|
||||
);
|
||||
} finally {
|
||||
device.close();
|
||||
debugger_.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -617,33 +581,6 @@ describe.each(['HTTP', 'HTTPS'])(
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Network.loadNetworkResource', () => {
|
||||
test('should forward event directly to client (does not rewrite url host)', async () => {
|
||||
const {device, debugger_} = await createAndConnectTarget(
|
||||
serverRef,
|
||||
autoCleanup.signal,
|
||||
pageDescription,
|
||||
);
|
||||
try {
|
||||
const message = {
|
||||
id: 1,
|
||||
method: 'Network.loadNetworkResource',
|
||||
params: {
|
||||
url: `${protocol.toLowerCase()}://10.0.2.2:${serverRef.port}`,
|
||||
},
|
||||
};
|
||||
await sendFromDebuggerToTarget(debugger_, device, 'page1', message);
|
||||
expect(device.wrappedEventParsed).toBeCalledWith({
|
||||
pageId: 'page1',
|
||||
wrappedEvent: message,
|
||||
});
|
||||
} finally {
|
||||
device.close();
|
||||
debugger_.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -15,7 +15,7 @@ import type {
|
||||
} from '../inspector-proxy/types';
|
||||
|
||||
import DefaultBrowserLauncher from '../utils/DefaultBrowserLauncher';
|
||||
import {fetchJson, requestLocal} from './FetchUtils';
|
||||
import {fetchJson, fetchLocal} from './FetchUtils';
|
||||
import {createDeviceMock} from './InspectorDeviceUtils';
|
||||
import {withAbortSignalForEachTest} from './ResourceUtils';
|
||||
import {withServerForEachTest} from './ServerUtils';
|
||||
@@ -362,7 +362,7 @@ describe('inspector proxy HTTP API', () => {
|
||||
|
||||
jest.advanceTimersByTime(PAGES_POLLING_DELAY);
|
||||
|
||||
const response = await requestLocal(
|
||||
const response = await fetchLocal(
|
||||
`${serverRef.serverBaseUrl}${endpoint}`,
|
||||
);
|
||||
expect(response.headers.get('Content-Length')).not.toBeNull();
|
||||
@@ -415,12 +415,10 @@ describe('inspector proxy HTTP API', () => {
|
||||
);
|
||||
openUrl.searchParams.set('target', firstPage.id);
|
||||
// Request to open the debugger for the first device
|
||||
const response = await requestLocal(openUrl.toString(), {
|
||||
method: 'POST',
|
||||
});
|
||||
const response = await fetchLocal(openUrl.toString(), {method: 'POST'});
|
||||
|
||||
// Ensure the request was handled properly
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.status).toBe(200);
|
||||
// Ensure the debugger was launched
|
||||
expect(launchDebuggerSpy).toHaveBeenCalledWith(expect.any(String));
|
||||
} finally {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import {requestLocal} from './FetchUtils';
|
||||
import {fetchLocal} from './FetchUtils';
|
||||
import {withServerForEachTest} from './ServerUtils';
|
||||
|
||||
jest.useRealTimers();
|
||||
@@ -22,10 +22,11 @@ describe('embedder script', () => {
|
||||
});
|
||||
|
||||
test('is always served', async () => {
|
||||
const resp = await requestLocal(
|
||||
const resp = await fetchLocal(
|
||||
serverRef.serverBaseUrl +
|
||||
'/debugger-frontend/embedder-static/embedderScript.js',
|
||||
);
|
||||
expect(resp.statusCode).toBe(200);
|
||||
expect(resp.ok).toBeTruthy();
|
||||
expect(resp.status).toBe(200);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import getBaseUrlFromRequest from '../utils/getBaseUrlFromRequest';
|
||||
|
||||
test('returns a base url based on req.headers.host', () => {
|
||||
expect(
|
||||
getBaseUrlFromRequest(makeRequest('localhost:8081', false))?.href,
|
||||
).toEqual('http://localhost:8081/');
|
||||
});
|
||||
|
||||
test('identifies https using socket.encrypted', () => {
|
||||
expect(
|
||||
getBaseUrlFromRequest(makeRequest('secure.net:8443', true))?.href,
|
||||
).toEqual('https://secure.net:8443/');
|
||||
});
|
||||
|
||||
test('works with ipv6 hosts', () => {
|
||||
expect(getBaseUrlFromRequest(makeRequest('[::1]:8081', false))?.href).toEqual(
|
||||
'http://[::1]:8081/',
|
||||
);
|
||||
});
|
||||
|
||||
test('returns null on an invalid host header', () => {
|
||||
expect(getBaseUrlFromRequest(makeRequest('local[]host', false))).toBeNull();
|
||||
});
|
||||
|
||||
test('returns null on an empty host header', () => {
|
||||
expect(getBaseUrlFromRequest(makeRequest(null, false))).toBeNull();
|
||||
});
|
||||
|
||||
function makeRequest(
|
||||
host: ?string,
|
||||
encrypted: boolean,
|
||||
): http$IncomingMessage<> | http$IncomingMessage<tls$TLSSocket> {
|
||||
// $FlowIgnore[incompatible-return] Partial mock of request
|
||||
return {
|
||||
socket: encrypted ? {encrypted: true} : {},
|
||||
headers: host != null ? {host} : {},
|
||||
};
|
||||
}
|
||||
@@ -28,8 +28,11 @@ type Options = $ReadOnly<{
|
||||
projectRoot: string,
|
||||
|
||||
/**
|
||||
* The base URL to the dev server, as reachable from the machine on which
|
||||
* dev-middleware is hosted. Typically `http://localhost:${metroPort}`.
|
||||
* The base URL to the dev server, as addressible from the local developer
|
||||
* machine. This is used in responses which return URLs to other endpoints,
|
||||
* e.g. the debugger frontend and inspector proxy targets.
|
||||
*
|
||||
* Example: `'http://localhost:8081'`.
|
||||
*/
|
||||
serverBaseUrl: string,
|
||||
|
||||
|
||||
@@ -133,7 +133,6 @@ export default class Device {
|
||||
projectRoot: string,
|
||||
eventReporter: ?EventReporter,
|
||||
createMessageMiddleware: ?CreateCustomMessageHandlerFn,
|
||||
serverBaseUrl?: URL,
|
||||
) {
|
||||
this.#dangerouslyConstruct(
|
||||
id,
|
||||
@@ -800,31 +799,6 @@ export default class Device {
|
||||
// Sends response to debugger via side-effect
|
||||
this.#processDebuggerGetScriptSource(req, socket);
|
||||
return null;
|
||||
case 'Network.loadNetworkResource':
|
||||
// If we're rewriting URLs (to frontend-relative), we don't want to
|
||||
// pass these URLs to the device, since it may try to fetch, return a
|
||||
// CDP *result* (not error) with a network failure, and CDT
|
||||
// will *not* then fall back to fetching locally.
|
||||
//
|
||||
// Instead, take the absence of a nativeSourceCodeFetching
|
||||
// capability as a signal to never pass a loadNetworkResource request
|
||||
// to the device. By returning a CDP error, the frontend should fetch.
|
||||
const result = {
|
||||
error: {
|
||||
code: -32601, // Method not found
|
||||
message:
|
||||
'[inspector-proxy]: Page lacks nativeSourceCodeFetching capability.',
|
||||
},
|
||||
};
|
||||
const response = {id: req.id, result};
|
||||
socket.send(JSON.stringify(response));
|
||||
const pageId = this.#debuggerConnection?.pageId ?? null;
|
||||
this.#deviceEventReporter?.logResponse(response, 'proxy', {
|
||||
pageId,
|
||||
frontendUserAgent: this.#debuggerConnection?.userAgent ?? null,
|
||||
prefersFuseboxFrontend: this.#isPageFuseboxFrontend(pageId),
|
||||
});
|
||||
return null;
|
||||
default:
|
||||
return req;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import type {IncomingMessage, ServerResponse} from 'http';
|
||||
// $FlowFixMe[cannot-resolve-module] libdef missing in RN OSS
|
||||
import type {Timeout} from 'timers';
|
||||
|
||||
import getBaseUrlFromRequest from '../utils/getBaseUrlFromRequest';
|
||||
import Device from './Device';
|
||||
import nullthrows from 'nullthrows';
|
||||
// Import these from node:timers to get the correct Flow types.
|
||||
@@ -48,7 +47,7 @@ export interface InspectorProxyQueries {
|
||||
* Returns list of page descriptions ordered by device connection order, then
|
||||
* page addition order.
|
||||
*/
|
||||
getPageDescriptions(requestorRelativeBaseUrl: URL): Array<PageDescription>;
|
||||
getPageDescriptions(): Array<PageDescription>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,8 +57,8 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
// Root of the project used for relative to absolute source path conversion.
|
||||
#projectRoot: string;
|
||||
|
||||
// The base URL to the dev server from the dev-middleware host.
|
||||
#serverBaseUrl: URL;
|
||||
/** The base URL to the dev server from the developer machine. */
|
||||
#serverBaseUrl: string;
|
||||
|
||||
// Maps device ID to Device instance.
|
||||
#devices: Map<string, Device>;
|
||||
@@ -82,14 +81,14 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
customMessageHandler: ?CreateCustomMessageHandlerFn,
|
||||
) {
|
||||
this.#projectRoot = projectRoot;
|
||||
this.#serverBaseUrl = new URL(serverBaseUrl);
|
||||
this.#serverBaseUrl = serverBaseUrl;
|
||||
this.#devices = new Map();
|
||||
this.#eventReporter = eventReporter;
|
||||
this.#experiments = experiments;
|
||||
this.#customMessageHandler = customMessageHandler;
|
||||
}
|
||||
|
||||
getPageDescriptions(requestorRelativeBaseUrl: URL): Array<PageDescription> {
|
||||
getPageDescriptions(): Array<PageDescription> {
|
||||
// Build list of pages from all devices.
|
||||
let result: Array<PageDescription> = [];
|
||||
Array.from(this.#devices.entries()).forEach(([deviceId, device]) => {
|
||||
@@ -97,12 +96,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
device
|
||||
.getPagesList()
|
||||
.map((page: Page) =>
|
||||
this.#buildPageDescription(
|
||||
deviceId,
|
||||
device,
|
||||
page,
|
||||
requestorRelativeBaseUrl,
|
||||
),
|
||||
this.#buildPageDescription(deviceId, device, page),
|
||||
),
|
||||
);
|
||||
});
|
||||
@@ -123,12 +117,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
pathname === PAGES_LIST_JSON_URL ||
|
||||
pathname === PAGES_LIST_JSON_URL_2
|
||||
) {
|
||||
this.#sendJsonResponse(
|
||||
response,
|
||||
this.getPageDescriptions(
|
||||
getBaseUrlFromRequest(request) ?? this.#serverBaseUrl,
|
||||
),
|
||||
);
|
||||
this.#sendJsonResponse(response, this.getPageDescriptions());
|
||||
} else if (pathname === PAGES_LIST_JSON_VERSION_URL) {
|
||||
this.#sendJsonResponse(response, {
|
||||
Browser: 'Mobile JavaScript',
|
||||
@@ -154,9 +143,8 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
deviceId: string,
|
||||
device: Device,
|
||||
page: Page,
|
||||
requestorRelativeBaseUrl: URL,
|
||||
): PageDescription {
|
||||
const {host, protocol} = requestorRelativeBaseUrl;
|
||||
const {host, protocol} = new URL(this.#serverBaseUrl);
|
||||
const webSocketScheme = protocol === 'https:' ? 'wss' : 'ws';
|
||||
|
||||
const webSocketUrlWithoutProtocol = `${host}${WS_DEBUGGER_URL}?device=${deviceId}&page=${page.id}`;
|
||||
|
||||
@@ -44,7 +44,6 @@ export type CDPClientMessage =
|
||||
| CDPRequest<'Debugger.getScriptSource'>
|
||||
| CDPRequest<'Debugger.scriptParsed'>
|
||||
| CDPRequest<'Debugger.setBreakpointByUrl'>
|
||||
| CDPRequest<'Network.loadNetworkResource'>
|
||||
| CDPRequest<>;
|
||||
|
||||
export type CDPServerMessage =
|
||||
|
||||
@@ -72,14 +72,12 @@ export default function openDebuggerMiddleware({
|
||||
...
|
||||
} = query;
|
||||
|
||||
const targets = inspectorProxy
|
||||
.getPageDescriptions(new URL(serverBaseUrl))
|
||||
.filter(
|
||||
// Only use targets with better reloading support
|
||||
app =>
|
||||
app.title === LEGACY_SYNTHETIC_PAGE_TITLE ||
|
||||
app.reactNative.capabilities?.nativePageReloads === true,
|
||||
);
|
||||
const targets = inspectorProxy.getPageDescriptions().filter(
|
||||
// Only use targets with better reloading support
|
||||
app =>
|
||||
app.title === LEGACY_SYNTHETIC_PAGE_TITLE ||
|
||||
app.reactNative.capabilities?.nativePageReloads === true,
|
||||
);
|
||||
|
||||
let target;
|
||||
|
||||
|
||||
@@ -18,10 +18,6 @@ export interface BrowserLauncher {
|
||||
* Attempt to open a debugger frontend URL in a browser app window,
|
||||
* optionally returning an object to control the launched browser instance.
|
||||
* The browser used should be capable of running Chrome DevTools.
|
||||
*
|
||||
* The provided url is based on serverBaseUrl, and therefore reachable from
|
||||
* the host of dev-middleware. Implementations are responsible for rewriting
|
||||
* this as necessary where the server is remote.
|
||||
*/
|
||||
launchDebuggerAppWindow: (url: string) => Promise<void>;
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
// Determine the base URL (scheme and host) used by a client to reach this
|
||||
// server.
|
||||
//
|
||||
// TODO: Support X-Forwarded-Host, etc. for trusted proxies
|
||||
export default function getBaseUrlFromRequest(
|
||||
req: http$IncomingMessage<tls$TLSSocket> | http$IncomingMessage<net$Socket>,
|
||||
): ?URL {
|
||||
const hostHeader = req.headers.host;
|
||||
if (hostHeader == null) {
|
||||
return null;
|
||||
}
|
||||
// `encrypted` is always true for TLS sockets and undefined for net
|
||||
// https://github.com/nodejs/node/issues/41863#issuecomment-1030709186
|
||||
const scheme = req.socket.encrypted === true ? 'https' : 'http';
|
||||
const url = `${scheme}://${req.headers.host}`;
|
||||
return URL.canParse(url) ? new URL(url) : null;
|
||||
}
|
||||
@@ -65,11 +65,7 @@ function getWsParam({
|
||||
const serverHost = new URL(devServerUrl).host;
|
||||
let value;
|
||||
if (wsUrl.host === serverHost) {
|
||||
// Use a path-absolute (host-relative) URL if the WS server and frontend
|
||||
// server are colocated. This is more robust for cases where the frontend
|
||||
// may actually load through a tunnel or proxy, and the WS connection
|
||||
// should therefore do the same.
|
||||
//
|
||||
// Use a path-absolute (host-relative) URL
|
||||
// Depends on https://github.com/facebookexperimental/rn-chrome-devtools-frontend/pull/4
|
||||
value = wsUrl.pathname + wsUrl.search + wsUrl.hash;
|
||||
} else {
|
||||
|
||||
+1
-5
@@ -15,7 +15,6 @@ import java.math.BigInteger
|
||||
import java.security.MessageDigest
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.min
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.initialization.Settings
|
||||
@@ -160,10 +159,7 @@ abstract class ReactSettingsExtension @Inject constructor(val settings: Settings
|
||||
val logger = Logging.getLogger("ReactSettingsExtension")
|
||||
logger.error(message)
|
||||
if (cacheJsonConfig.length() != 0L) {
|
||||
logger.error(
|
||||
cacheJsonConfig
|
||||
.readText()
|
||||
.substring(0, min(1024, cacheJsonConfig.length().toInt())))
|
||||
logger.error(cacheJsonConfig.readText().substring(0, 1024))
|
||||
}
|
||||
cacheJsonConfig.delete()
|
||||
throw GradleException(message)
|
||||
|
||||
@@ -97,7 +97,6 @@ PLATFORMS
|
||||
DEPENDENCIES
|
||||
activesupport (>= 6.1.7.5, < 7.1.0)
|
||||
cocoapods (~> 1.13, != 1.15.1, != 1.15.0)
|
||||
xcodeproj (< 1.26.0)
|
||||
|
||||
RUBY VERSION
|
||||
ruby 3.3.0p0
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
00E356F31AD99517003FC87E /* HelloWorldTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* HelloWorldTests.m */; };
|
||||
0C80B921A6F3F58F76C31292 /* libPods-HelloWorld.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-HelloWorld.a */; };
|
||||
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||
68D852E4B70E7C539AF156EA /* libPods-HelloWorld-HelloWorldTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE12D37B885C99EE7D4A2086 /* libPods-HelloWorld-HelloWorldTests.a */; };
|
||||
6EA01F72FAC10D00AECACF94 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 0EC7AB76F90EED035707BA4E /* PrivacyInfo.xcprivacy */; };
|
||||
7699B88040F8A987B510C191 /* libPods-HelloWorld-HelloWorldTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-HelloWorld-HelloWorldTests.a */; };
|
||||
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
|
||||
D463203D20D2FDD34F945C74 /* libPods-HelloWorld.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 82822864BCFA4BE42C6C2969 /* libPods-HelloWorld.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -39,13 +39,13 @@
|
||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = HelloWorld/Info.plist; sourceTree = "<group>"; };
|
||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = HelloWorld/main.m; sourceTree = "<group>"; };
|
||||
13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = HelloWorld/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
19F6CBCC0A4E27FBF8BF4A61 /* libPods-HelloWorld-HelloWorldTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld-HelloWorldTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3B4392A12AC88292D35C810B /* Pods-HelloWorld.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.debug.xcconfig"; path = "Target Support Files/Pods-HelloWorld/Pods-HelloWorld.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
5709B34CF0A7D63546082F79 /* Pods-HelloWorld.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.release.xcconfig"; path = "Target Support Files/Pods-HelloWorld/Pods-HelloWorld.release.xcconfig"; sourceTree = "<group>"; };
|
||||
5B7EB9410499542E8C5724F5 /* Pods-HelloWorld-HelloWorldTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld-HelloWorldTests.debug.xcconfig"; path = "Target Support Files/Pods-HelloWorld-HelloWorldTests/Pods-HelloWorld-HelloWorldTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
5DCACB8F33CDC322A6C60F78 /* libPods-HelloWorld.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = HelloWorld/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
82822864BCFA4BE42C6C2969 /* libPods-HelloWorld.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
89C6BE57DB24E9ADA2F236DE /* Pods-HelloWorld-HelloWorldTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld-HelloWorldTests.release.xcconfig"; path = "Target Support Files/Pods-HelloWorld-HelloWorldTests/Pods-HelloWorld-HelloWorldTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
CE12D37B885C99EE7D4A2086 /* libPods-HelloWorld-HelloWorldTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld-HelloWorldTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
68D852E4B70E7C539AF156EA /* libPods-HelloWorld-HelloWorldTests.a in Frameworks */,
|
||||
7699B88040F8A987B510C191 /* libPods-HelloWorld-HelloWorldTests.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -62,7 +62,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D463203D20D2FDD34F945C74 /* libPods-HelloWorld.a in Frameworks */,
|
||||
0C80B921A6F3F58F76C31292 /* libPods-HelloWorld.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -105,8 +105,8 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
|
||||
82822864BCFA4BE42C6C2969 /* libPods-HelloWorld.a */,
|
||||
CE12D37B885C99EE7D4A2086 /* libPods-HelloWorld-HelloWorldTests.a */,
|
||||
5DCACB8F33CDC322A6C60F78 /* libPods-HelloWorld.a */,
|
||||
19F6CBCC0A4E27FBF8BF4A61 /* libPods-HelloWorld-HelloWorldTests.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@@ -165,7 +165,6 @@
|
||||
00E356EB1AD99517003FC87E /* Frameworks */,
|
||||
00E356EC1AD99517003FC87E /* Resources */,
|
||||
F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */,
|
||||
A44ED3CC3037C88F69E3AF15 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -187,7 +186,6 @@
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */,
|
||||
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
|
||||
E235C05ADACE081382539298 /* [CP] Copy Pods Resources */,
|
||||
D32CB2BA406E97DB62F51C6B /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -272,23 +270,6 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "set -e\n\nexport CONFIG_JSON=$(sed -e \"s|HELLOWORLD_PATH|$(realpath \"${SRCROOT}/../\")|g\" \"${SRCROOT}/../.react-native.config\")\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";
|
||||
};
|
||||
A44ED3CC3037C88F69E3AF15 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-HelloWorld-HelloWorldTests/Pods-HelloWorld-HelloWorldTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-HelloWorld-HelloWorldTests/Pods-HelloWorld-HelloWorldTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-HelloWorld-HelloWorldTests/Pods-HelloWorld-HelloWorldTests-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -333,23 +314,6 @@
|
||||
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";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
D32CB2BA406E97DB62F51C6B /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -571,17 +535,6 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios",
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
/usr/lib/swift,
|
||||
@@ -602,14 +555,8 @@
|
||||
"-DFOLLY_CFG_NO_COROUTINES=1",
|
||||
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
" ",
|
||||
);
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../react-native";
|
||||
OTHER_LDFLAGS = "$(inherited) ";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
|
||||
USE_HERMES = true;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -655,17 +602,6 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios",
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
/usr/lib/swift,
|
||||
@@ -685,13 +621,8 @@
|
||||
"-DFOLLY_CFG_NO_COROUTINES=1",
|
||||
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
" ",
|
||||
);
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../react-native";
|
||||
OTHER_LDFLAGS = "$(inherited) ";
|
||||
SDKROOT = iphoneos;
|
||||
USE_HERMES = true;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
|
||||
@@ -8,14 +8,12 @@
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import <React/RCTBundleURLProvider.h>
|
||||
#import <ReactCodegen/RCTAppDependencyProvider.h>
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
self.moduleName = @"HelloWorld";
|
||||
self.dependencyProvider = [RCTAppDependencyProvider new];
|
||||
// You can add your custom initial props in the dictionary below.
|
||||
// They will be passed down to the ViewController used by React Native.
|
||||
self.initialProps = @{};
|
||||
|
||||
@@ -553,48 +553,6 @@ if (global.nativeLoggingHook) {
|
||||
assert: consoleAssertPolyfill,
|
||||
};
|
||||
|
||||
// TODO(T206796580): This was copy-pasted from ExceptionsManager.js
|
||||
// Delete the copy there after the c++ pipeline is rolled out everywhere.
|
||||
if (global.RN$useAlwaysAvailableJSErrorHandling === true) {
|
||||
let originalConsoleError = console.error;
|
||||
console.reportErrorsAsExceptions = true;
|
||||
function stringifySafe(arg) {
|
||||
return inspect(arg, {depth: 10}).replaceAll(/\n\s*/g, ' ');
|
||||
}
|
||||
console.error = function (...args) {
|
||||
originalConsoleError.apply(this, args);
|
||||
if (!console.reportErrorsAsExceptions) {
|
||||
return;
|
||||
}
|
||||
if (global.RN$inExceptionHandler?.()) {
|
||||
return;
|
||||
}
|
||||
let error;
|
||||
|
||||
const firstArg = args[0];
|
||||
if (firstArg?.stack) {
|
||||
// RN$handleException will console.error this with high enough fidelity.
|
||||
error = firstArg;
|
||||
} else {
|
||||
if (typeof firstArg === 'string' && firstArg.startsWith('Warning: ')) {
|
||||
// React warnings use console.error so that a stack trace is shown, but
|
||||
// we don't (currently) want these to show a redbox
|
||||
return;
|
||||
}
|
||||
const message = args
|
||||
.map(arg => (typeof arg === 'string' ? arg : stringifySafe(arg)))
|
||||
.join(' ');
|
||||
|
||||
error = new Error(message);
|
||||
error.name = 'console.error';
|
||||
}
|
||||
|
||||
const isFatal = false;
|
||||
const reportToConsole = false;
|
||||
global.RN$handleException(error, isFatal, reportToConsole);
|
||||
};
|
||||
}
|
||||
|
||||
Object.defineProperty(console, '_isPolyfilled', {
|
||||
value: true,
|
||||
enumerable: false,
|
||||
|
||||
@@ -19,12 +19,12 @@ type Fn<Args, Return> = (...Args) => Return;
|
||||
* when loading a module. This will report any errors encountered before
|
||||
* ExceptionsManager is configured.
|
||||
*/
|
||||
let _globalHandler: ErrorHandler =
|
||||
global.RN$useAlwaysAvailableJSErrorHandling === true
|
||||
? global.RN$handleException
|
||||
: (e: mixed, isFatal: boolean) => {
|
||||
throw e;
|
||||
};
|
||||
let _globalHandler: ErrorHandler = function onError(
|
||||
e: mixed,
|
||||
isFatal: boolean,
|
||||
) {
|
||||
throw e;
|
||||
};
|
||||
|
||||
/**
|
||||
* The particular require runtime that we are using looks for a global
|
||||
|
||||
-1
@@ -1717,7 +1717,6 @@ const REAL_MODULE_EXAMPLE: SchemaType = {
|
||||
|
||||
const CXX_ONLY_NATIVE_MODULES: SchemaType = {
|
||||
modules: {
|
||||
// $FlowFixMe[incompatible-type]
|
||||
NativeSampleTurboModule: {
|
||||
type: 'NativeModule',
|
||||
aliasMap: {
|
||||
|
||||
-30
@@ -265,35 +265,6 @@ export interface Spec extends TurboModule {
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('MixedValuesEnumNativeModule');
|
||||
`;
|
||||
|
||||
const NUMERIC_VALUES_ENUM_NATIVE_MODULE = `
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {TurboModule} from '../RCTExport';
|
||||
import * as TurboModuleRegistry from '../TurboModuleRegistry';
|
||||
|
||||
export enum SomeEnum {
|
||||
NUM = 1,
|
||||
NEGATIVE = -1,
|
||||
SUBFACTORIAL = !5,
|
||||
}
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+getEnums: (a: SomeEnum) => string;
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('NumericValuesEnumNativeModule');
|
||||
`;
|
||||
|
||||
const MAP_WITH_EXTRA_KEYS_NATIVE_MODULE = `
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
@@ -333,6 +304,5 @@ module.exports = {
|
||||
TWO_NATIVE_EXTENDING_TURBO_MODULE,
|
||||
EMPTY_ENUM_NATIVE_MODULE,
|
||||
MIXED_VALUES_ENUM_NATIVE_MODULE,
|
||||
NUMERIC_VALUES_ENUM_NATIVE_MODULE,
|
||||
MAP_WITH_EXTRA_KEYS_NATIVE_MODULE,
|
||||
};
|
||||
|
||||
-1
@@ -782,7 +782,6 @@ export enum Quality {
|
||||
}
|
||||
|
||||
export enum Resolution {
|
||||
Corrupted = -1,
|
||||
Low = 720,
|
||||
High = 1080,
|
||||
}
|
||||
|
||||
-10
@@ -25,12 +25,6 @@ exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULES_WITH_REA
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULES_WITH_UNNAMED_PARAMS 1`] = `"Module NativeSampleTurboModule: All function parameters must be named."`;
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message NUMERIC_VALUES_ENUM_NATIVE_MODULE 1`] = `
|
||||
"Syntax error in path/NativeSampleTurboModule.js: 'true', 'false', 'string', 'number' or 'bigint' expected in enum member initializer (20:17)
|
||||
SUBFACTORIAL = !5,
|
||||
~~~~~~~~~~~~~~~^"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message TWO_NATIVE_EXTENDING_TURBO_MODULE 1`] = `"Module NativeSampleTurboModule: Every NativeModule spec file must declare exactly one NativeModule Flow interface. This file declares 2: 'Spec', and 'Spec2'. Please remove the extraneous Flow interface declarations."`;
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message TWO_NATIVE_MODULES_EXPORTED_WITH_DEFAULT 1`] = `"Module NativeSampleTurboModule: No Flow interfaces extending TurboModule were detected in this NativeModule spec."`;
|
||||
@@ -160,10 +154,6 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`]
|
||||
'type': 'EnumDeclarationWithMembers',
|
||||
'memberType': 'NumberTypeAnnotation',
|
||||
'members': [
|
||||
{
|
||||
'name': 'Corrupted',
|
||||
'value': -1
|
||||
},
|
||||
{
|
||||
'name': 'Low',
|
||||
'value': 720
|
||||
|
||||
-29
@@ -208,34 +208,6 @@ export default TurboModuleRegistry.getEnforcing<Spec>(
|
||||
);
|
||||
`;
|
||||
|
||||
const NUMERIC_VALUES_ENUM_NATIVE_MODULE = `
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
|
||||
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
|
||||
|
||||
export enum SomeEnum {
|
||||
NUM = 1,
|
||||
NEGATIVE = -1,
|
||||
SUBFACTORIAL = !5,
|
||||
}
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
readonly getEnums: (a: SomeEnum) => string;
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>(
|
||||
'NumericValuesEnumNativeModule',
|
||||
);
|
||||
`;
|
||||
|
||||
const MAP_WITH_EXTRA_KEYS_NATIVE_MODULE = `
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
@@ -271,6 +243,5 @@ module.exports = {
|
||||
TWO_NATIVE_EXTENDING_TURBO_MODULE,
|
||||
EMPTY_ENUM_NATIVE_MODULE,
|
||||
MIXED_VALUES_ENUM_NATIVE_MODULE,
|
||||
NUMERIC_VALUES_ENUM_NATIVE_MODULE,
|
||||
MAP_WITH_EXTRA_KEYS_NATIVE_MODULE,
|
||||
};
|
||||
|
||||
-1
@@ -866,7 +866,6 @@ export enum Quality {
|
||||
}
|
||||
|
||||
export enum Resolution {
|
||||
Corrupted = -1,
|
||||
Low = 720,
|
||||
High = 1080,
|
||||
}
|
||||
|
||||
-6
@@ -16,8 +16,6 @@ exports[`RN Codegen TypeScript Parser Fails with error message NATIVE_MODULES_WI
|
||||
|
||||
exports[`RN Codegen TypeScript Parser Fails with error message NATIVE_MODULES_WITH_UNNAMED_PARAMS 1`] = `"Module NativeSampleTurboModule: All function parameters must be named."`;
|
||||
|
||||
exports[`RN Codegen TypeScript Parser Fails with error message NUMERIC_VALUES_ENUM_NATIVE_MODULE 1`] = `"Module NativeSampleTurboModule: Failed parsing the enum SomeEnum in NativeSampleTurboModule with the error: Enum values can not be mixed. They all must be either blank, number, or string values."`;
|
||||
|
||||
exports[`RN Codegen TypeScript Parser Fails with error message TWO_NATIVE_EXTENDING_TURBO_MODULE 1`] = `"Module NativeSampleTurboModule: Every NativeModule spec file must declare exactly one NativeModule TypeScript interface. This file declares 2: 'Spec', and 'Spec2'. Please remove the extraneous TypeScript interface declarations."`;
|
||||
|
||||
exports[`RN Codegen TypeScript Parser Fails with error message TWO_NATIVE_MODULES_EXPORTED_WITH_DEFAULT 1`] = `"Module NativeSampleTurboModule: No TypeScript interfaces extending TurboModule were detected in this NativeModule spec."`;
|
||||
@@ -147,10 +145,6 @@ exports[`RN Codegen TypeScript Parser can generate fixture CXX_ONLY_NATIVE_MODUL
|
||||
'type': 'EnumDeclarationWithMembers',
|
||||
'memberType': 'NumberTypeAnnotation',
|
||||
'members': [
|
||||
{
|
||||
'name': 'Corrupted',
|
||||
'value': -1
|
||||
},
|
||||
{
|
||||
'name': 'Low',
|
||||
'value': 720
|
||||
|
||||
-46
@@ -106,52 +106,6 @@ describe('TypeScript Module Parser', () => {
|
||||
expect(parser).toThrow(UnnamedFunctionParamParserError);
|
||||
});
|
||||
|
||||
it('should properly parse negative enums', () => {
|
||||
const parser = () =>
|
||||
parseModule(`
|
||||
import type {TurboModule} from 'RCTExport';
|
||||
import * as TurboModuleRegistry from 'TurboModuleRegistry';
|
||||
enum MyEnum {
|
||||
ZERO = 0,
|
||||
POSITIVE = 1,
|
||||
NEGATIVE = -1,
|
||||
}
|
||||
export interface Spec extends TurboModule {
|
||||
useArg(arg: MyEnum): void;
|
||||
}
|
||||
export default TurboModuleRegistry.get<Spec>('Foo');
|
||||
`);
|
||||
|
||||
expect(parser).not.toThrow();
|
||||
expect(parser().enumMap.MyEnum.members).toEqual([
|
||||
{name: 'ZERO', value: 0},
|
||||
{name: 'POSITIVE', value: 1},
|
||||
{name: 'NEGATIVE', value: -1},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should properly parse enums', () => {
|
||||
const parser = () =>
|
||||
parseModule(`
|
||||
import type {TurboModule} from 'RCTExport';
|
||||
import * as TurboModuleRegistry from 'TurboModuleRegistry';
|
||||
enum MyEnum {
|
||||
ZERO = 0,
|
||||
POSITIVE = 1,
|
||||
}
|
||||
export interface Spec extends TurboModule {
|
||||
useArg(arg: MyEnum): void;
|
||||
}
|
||||
export default TurboModuleRegistry.get<Spec>('Foo');
|
||||
`);
|
||||
|
||||
expect(parser).not.toThrow();
|
||||
expect(parser().enumMap.MyEnum.members).toEqual([
|
||||
{name: 'ZERO', value: 0},
|
||||
{name: 'POSITIVE', value: 1},
|
||||
]);
|
||||
});
|
||||
|
||||
[
|
||||
{nullable: false, optional: false},
|
||||
{nullable: false, optional: true},
|
||||
|
||||
+13
-46
@@ -183,30 +183,12 @@ class TypeScriptParser implements Parser {
|
||||
|
||||
parseEnumMembersType(typeAnnotation: $FlowFixMe): NativeModuleEnumMemberType {
|
||||
const enumInitializer = typeAnnotation.members[0]?.initializer;
|
||||
const enumInitializerType = enumInitializer?.type;
|
||||
|
||||
let enumMembersType: ?NativeModuleEnumMemberType = null;
|
||||
|
||||
if (!enumInitializerType) {
|
||||
return 'StringTypeAnnotation';
|
||||
}
|
||||
|
||||
switch (enumInitializerType) {
|
||||
case 'StringLiteral':
|
||||
enumMembersType = 'StringTypeAnnotation';
|
||||
break;
|
||||
case 'NumericLiteral':
|
||||
enumMembersType = 'NumberTypeAnnotation';
|
||||
break;
|
||||
case 'UnaryExpression':
|
||||
if (enumInitializer.operator === '-') {
|
||||
enumMembersType = 'NumberTypeAnnotation';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
enumMembersType = null;
|
||||
}
|
||||
|
||||
const enumMembersType: ?NativeModuleEnumMemberType =
|
||||
!enumInitializer || enumInitializer.type === 'StringLiteral'
|
||||
? 'StringTypeAnnotation'
|
||||
: enumInitializer.type === 'NumericLiteral'
|
||||
? 'NumberTypeAnnotation'
|
||||
: null;
|
||||
if (!enumMembersType) {
|
||||
throw new Error(
|
||||
'Enum values must be either blank, number, or string values.',
|
||||
@@ -231,14 +213,9 @@ class TypeScriptParser implements Parser {
|
||||
: null;
|
||||
|
||||
typeAnnotation.members.forEach(member => {
|
||||
const isNegative =
|
||||
member.initializer?.type === 'UnaryExpression' &&
|
||||
member.initializer?.operator === '-';
|
||||
const initializerType = isNegative
|
||||
? member.initializer?.argument?.type
|
||||
: member.initializer?.type;
|
||||
|
||||
if ((initializerType ?? 'StringLiteral') !== enumInitializerType) {
|
||||
if (
|
||||
(member.initializer?.type ?? 'StringLiteral') !== enumInitializerType
|
||||
) {
|
||||
throw new Error(
|
||||
'Enum values can not be mixed. They all must be either blank, number, or string values.',
|
||||
);
|
||||
@@ -249,20 +226,10 @@ class TypeScriptParser implements Parser {
|
||||
parseEnumMembers(
|
||||
typeAnnotation: $FlowFixMe,
|
||||
): $ReadOnlyArray<NativeModuleEnumMember> {
|
||||
return typeAnnotation.members.map(member => {
|
||||
// Handle negative values
|
||||
if (member.initializer?.operator === '-') {
|
||||
return {
|
||||
name: member.id.name,
|
||||
value: -member.initializer?.argument?.value ?? member.id.name,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
name: member.id.name,
|
||||
value: member.initializer?.value ?? member.id.name,
|
||||
};
|
||||
});
|
||||
return typeAnnotation.members.map(member => ({
|
||||
name: member.id.name,
|
||||
value: member.initializer?.value ?? member.id.name,
|
||||
}));
|
||||
}
|
||||
|
||||
isModuleInterface(node: $FlowFixMe): boolean {
|
||||
|
||||
@@ -44,11 +44,6 @@
|
||||
"includesGeneratedCode": true,
|
||||
"android": {
|
||||
"javaPackageName": "com.reactnative.osslibraryexample"
|
||||
},
|
||||
"ios": {
|
||||
"componentProvider": {
|
||||
"SampleNativeComponent": "RCTSampleNativeComponentComponentView"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ export interface ActionSheetIOSOptions {
|
||||
anchor?: number | undefined;
|
||||
tintColor?: ColorValue | ProcessedColorValue | undefined;
|
||||
cancelButtonTintColor?: ColorValue | ProcessedColorValue | undefined;
|
||||
disabledButtonTintColor?: ColorValue | ProcessedColorValue | undefined;
|
||||
userInterfaceStyle?: 'light' | 'dark' | undefined;
|
||||
disabledButtonIndices?: number[] | undefined;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ const ActionSheetIOS = {
|
||||
+anchor?: ?number,
|
||||
+tintColor?: ColorValue | ProcessedColorValue,
|
||||
+cancelButtonTintColor?: ColorValue | ProcessedColorValue,
|
||||
+disabledButtonTintColor?: ColorValue | ProcessedColorValue,
|
||||
+userInterfaceStyle?: string,
|
||||
+disabledButtonIndices?: Array<number>,
|
||||
|},
|
||||
@@ -65,7 +64,6 @@ const ActionSheetIOS = {
|
||||
const {
|
||||
tintColor,
|
||||
cancelButtonTintColor,
|
||||
disabledButtonTintColor,
|
||||
destructiveButtonIndex,
|
||||
...remainingOptions
|
||||
} = options;
|
||||
@@ -79,10 +77,6 @@ const ActionSheetIOS = {
|
||||
|
||||
const processedTintColor = processColor(tintColor);
|
||||
const processedCancelButtonTintColor = processColor(cancelButtonTintColor);
|
||||
const processedDisabledButtonTintColor = processColor(
|
||||
disabledButtonTintColor,
|
||||
);
|
||||
|
||||
invariant(
|
||||
processedTintColor == null || typeof processedTintColor === 'number',
|
||||
'Unexpected color given for ActionSheetIOS.showActionSheetWithOptions tintColor',
|
||||
@@ -92,11 +86,6 @@ const ActionSheetIOS = {
|
||||
typeof processedCancelButtonTintColor === 'number',
|
||||
'Unexpected color given for ActionSheetIOS.showActionSheetWithOptions cancelButtonTintColor',
|
||||
);
|
||||
invariant(
|
||||
processedDisabledButtonTintColor == null ||
|
||||
typeof processedDisabledButtonTintColor === 'number',
|
||||
'Unexpected color given for ActionSheetIOS.showActionSheetWithOptions disabledButtonTintColor',
|
||||
);
|
||||
RCTActionSheetManager.showActionSheetWithOptions(
|
||||
{
|
||||
...remainingOptions,
|
||||
@@ -104,8 +93,6 @@ const ActionSheetIOS = {
|
||||
tintColor: processedTintColor,
|
||||
// $FlowFixMe[incompatible-call]
|
||||
cancelButtonTintColor: processedCancelButtonTintColor,
|
||||
// $FlowFixMe[incompatible-call]
|
||||
disabledButtonTintColor: processedDisabledButtonTintColor,
|
||||
destructiveButtonIndices,
|
||||
},
|
||||
callback,
|
||||
|
||||
@@ -121,12 +121,10 @@ describe('Animated', () => {
|
||||
|
||||
await unmount(root);
|
||||
|
||||
expect(callback).not.toBeCalled();
|
||||
await jest.runOnlyPendingTimersAsync();
|
||||
expect(callback).toBeCalledWith({finished: false});
|
||||
});
|
||||
|
||||
it('triggers callback when spring is at rest', async () => {
|
||||
it('triggers callback when spring is at rest', () => {
|
||||
const anim = new Animated.Value(0);
|
||||
const callback = jest.fn();
|
||||
Animated.spring(anim, {
|
||||
@@ -134,10 +132,7 @@ describe('Animated', () => {
|
||||
velocity: 0,
|
||||
useNativeDriver: false,
|
||||
}).start(callback);
|
||||
|
||||
expect(callback).not.toBeCalled();
|
||||
await jest.runOnlyPendingTimersAsync();
|
||||
expect(callback).toBeCalledWith({finished: true});
|
||||
expect(callback).toBeCalled();
|
||||
});
|
||||
|
||||
it('send toValue when a critically damped spring stops', () => {
|
||||
|
||||
@@ -165,7 +165,11 @@ export default class Animation {
|
||||
const callback = this.#onEnd;
|
||||
if (callback != null) {
|
||||
this.#onEnd = null;
|
||||
queueMicrotask(() => callback(result));
|
||||
if (ReactNativeFeatureFlags.scheduleAnimatedEndCallbackInMicrotask()) {
|
||||
queueMicrotask(() => callback(result));
|
||||
} else {
|
||||
callback(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {SectionBase} from '../../Lists/SectionList';
|
||||
import type {AnimatedComponentType} from '../createAnimatedComponent';
|
||||
|
||||
import SectionList from '../../Lists/SectionList';
|
||||
@@ -17,6 +16,5 @@ import * as React from 'react';
|
||||
|
||||
export default (createAnimatedComponent(SectionList): AnimatedComponentType<
|
||||
React.ElementConfig<typeof SectionList>,
|
||||
// $FlowExpectedError[unclear-type]
|
||||
SectionList<SectionBase<any>>,
|
||||
React.ElementRef<typeof SectionList>,
|
||||
>);
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
@protocol RCTComponentViewProtocol;
|
||||
@class RCTRootView;
|
||||
@class RCTSurfacePresenterBridgeAdapter;
|
||||
@protocol RCTDependencyProvider;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@@ -71,7 +70,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, strong, nullable) NSString *moduleName;
|
||||
@property (nonatomic, strong, nullable) NSDictionary *initialProps;
|
||||
@property (nonatomic, strong, nonnull) RCTRootViewFactory *rootViewFactory;
|
||||
@property (nonatomic, strong) id<RCTDependencyProvider> dependencyProvider;
|
||||
|
||||
/// If `automaticallyLoadReactNativeWindow` is set to `true`, the React Native window will be loaded automatically.
|
||||
@property (nonatomic, assign) BOOL automaticallyLoadReactNativeWindow;
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#import <react/renderer/graphics/ColorComponents.h>
|
||||
#import "RCTAppDelegate+Protected.h"
|
||||
#import "RCTAppSetupUtils.h"
|
||||
#import "RCTDependencyProvider.h"
|
||||
|
||||
#if RN_DISABLE_OSS_PLUGIN_HEADER
|
||||
#import <RCTTurboModulePlugin/RCTTurboModulePlugin.h>
|
||||
@@ -229,14 +228,14 @@ using namespace facebook::react;
|
||||
|
||||
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
|
||||
{
|
||||
return RCTAppSetupDefaultModuleFromClass(moduleClass, self.dependencyProvider);
|
||||
return RCTAppSetupDefaultModuleFromClass(moduleClass);
|
||||
}
|
||||
|
||||
#pragma mark - RCTComponentViewFactoryComponentProvider
|
||||
|
||||
- (NSDictionary<NSString *, Class<RCTComponentViewProtocol>> *)thirdPartyFabricComponents
|
||||
{
|
||||
return self.dependencyProvider ? self.dependencyProvider.thirdPartyFabricComponents : @{};
|
||||
return @{};
|
||||
}
|
||||
|
||||
- (RCTRootViewFactory *)createRCTRootViewFactory
|
||||
|
||||
@@ -25,16 +25,12 @@
|
||||
|
||||
#import <ReactCommon/RCTTurboModuleManager.h>
|
||||
|
||||
@protocol RCTDependencyProvider;
|
||||
|
||||
// Forward declaration to decrease compilation coupling
|
||||
namespace facebook::react {
|
||||
class RuntimeScheduler;
|
||||
}
|
||||
|
||||
RCT_EXTERN id<RCTTurboModule> RCTAppSetupDefaultModuleFromClass(
|
||||
Class moduleClass,
|
||||
id<RCTDependencyProvider> dependencyProvider);
|
||||
RCT_EXTERN id<RCTTurboModule> RCTAppSetupDefaultModuleFromClass(Class moduleClass);
|
||||
|
||||
std::unique_ptr<facebook::react::JSExecutorFactory> RCTAppSetupDefaultJsExecutorFactory(
|
||||
RCTBridge *bridge,
|
||||
|
||||
@@ -27,7 +27,13 @@
|
||||
// jsinspector-modern
|
||||
#import <jsinspector-modern/InspectorFlags.h>
|
||||
|
||||
#import "RCTDependencyProvider.h"
|
||||
#if __has_include(<ReactCodegen/RCTModulesConformingToProtocolsProvider.h>)
|
||||
#define USE_OSS_CODEGEN 1
|
||||
#import <ReactCodegen/RCTModulesConformingToProtocolsProvider.h>
|
||||
#else
|
||||
// Meta internal system do not generate the RCTModulesConformingToProtocolsProvider.h file
|
||||
#define USE_OSS_CODEGEN 0
|
||||
#endif
|
||||
|
||||
void RCTAppSetupPrepareApp(UIApplication *application, BOOL turboModuleEnabled)
|
||||
{
|
||||
@@ -54,20 +60,22 @@ RCTAppSetupDefaultRootView(RCTBridge *bridge, NSString *moduleName, NSDictionary
|
||||
return [[RCTRootView alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties];
|
||||
}
|
||||
|
||||
id<RCTTurboModule> RCTAppSetupDefaultModuleFromClass(Class moduleClass, id<RCTDependencyProvider> dependencyProvider)
|
||||
id<RCTTurboModule> RCTAppSetupDefaultModuleFromClass(Class moduleClass)
|
||||
{
|
||||
// private block used to filter out modules depending on protocol conformance
|
||||
NSArray * (^extractModuleConformingToProtocol)(RCTModuleRegistry *, Protocol *) =
|
||||
^NSArray *(RCTModuleRegistry *moduleRegistry, Protocol *protocol) {
|
||||
NSArray<NSString *> *classNames = @[];
|
||||
|
||||
#if USE_OSS_CODEGEN
|
||||
if (protocol == @protocol(RCTImageURLLoader)) {
|
||||
classNames = dependencyProvider ? dependencyProvider.imageURLLoaderClassNames : @[];
|
||||
classNames = [RCTModulesConformingToProtocolsProvider imageURLLoaderClassNames];
|
||||
} else if (protocol == @protocol(RCTImageDataDecoder)) {
|
||||
classNames = dependencyProvider ? dependencyProvider.imageDataDecoderClassNames : @[];
|
||||
classNames = [RCTModulesConformingToProtocolsProvider imageDataDecoderClassNames];
|
||||
} else if (protocol == @protocol(RCTURLRequestHandler)) {
|
||||
classNames = dependencyProvider ? dependencyProvider.URLRequestHandlerClassNames : @[];
|
||||
classNames = [RCTModulesConformingToProtocolsProvider URLRequestHandlerClassNames];
|
||||
}
|
||||
#endif
|
||||
|
||||
NSMutableArray *modules = [NSMutableArray new];
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@protocol RCTComponentViewProtocol;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol RCTDependencyProvider <NSObject>
|
||||
|
||||
- (NSArray<NSString *> *)imageURLLoaderClassNames;
|
||||
|
||||
- (NSArray<NSString *> *)imageDataDecoderClassNames;
|
||||
|
||||
- (NSArray<NSString *> *)URLRequestHandlerClassNames;
|
||||
|
||||
- (NSDictionary<NSString *, Class<RCTComponentViewProtocol>> *)thirdPartyFabricComponents;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -26,6 +26,7 @@
|
||||
#import <React/RCTFabricSurface.h>
|
||||
#import <React/RCTSurfaceHostingProxyRootView.h>
|
||||
#import <React/RCTSurfacePresenter.h>
|
||||
#import <ReactCommon/RCTContextContainerHandling.h>
|
||||
#if USE_HERMES
|
||||
#import <ReactCommon/RCTHermesInstance.h>
|
||||
#else
|
||||
@@ -34,10 +35,22 @@
|
||||
#import <ReactCommon/RCTHost+Internal.h>
|
||||
#import <ReactCommon/RCTHost.h>
|
||||
#import <ReactCommon/RCTTurboModuleManager.h>
|
||||
#import <react/config/ReactNativeConfig.h>
|
||||
#import <react/renderer/runtimescheduler/RuntimeScheduler.h>
|
||||
#import <react/renderer/runtimescheduler/RuntimeSchedulerCallInvoker.h>
|
||||
#import <react/runtime/JSRuntimeFactory.h>
|
||||
|
||||
static NSString *const kRNConcurrentRoot = @"concurrentRoot";
|
||||
|
||||
static NSDictionary *updateInitialProps(NSDictionary *initialProps, BOOL isFabricEnabled)
|
||||
{
|
||||
NSMutableDictionary *mutableProps = initialProps != NULL ? [initialProps mutableCopy] : [NSMutableDictionary new];
|
||||
// Hardcoding the Concurrent Root as it it not recommended to
|
||||
// have the concurrentRoot turned off when Fabric is enabled.
|
||||
mutableProps[kRNConcurrentRoot] = @(isFabricEnabled);
|
||||
return mutableProps;
|
||||
}
|
||||
|
||||
@implementation RCTRootViewFactoryConfiguration
|
||||
|
||||
- (instancetype)initWithBundleURL:(NSURL *)bundleURL newArchEnabled:(BOOL)newArchEnabled
|
||||
@@ -86,8 +99,13 @@
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTRootViewFactory () <RCTCxxBridgeDelegate> {
|
||||
@interface RCTRootViewFactory () <RCTContextContainerHandling> {
|
||||
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
|
||||
facebook::react::ContextContainer::Shared _contextContainer;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface RCTRootViewFactory () <RCTCxxBridgeDelegate> {
|
||||
std::shared_ptr<facebook::react::RuntimeScheduler> _runtimeScheduler;
|
||||
}
|
||||
@end
|
||||
@@ -106,6 +124,8 @@
|
||||
_configuration = configuration;
|
||||
_hostDelegate = hostdelegate;
|
||||
_contextContainer = std::make_shared<const facebook::react::ContextContainer>();
|
||||
_reactNativeConfig = std::make_shared<const facebook::react::EmptyReactNativeConfig>();
|
||||
_contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
|
||||
_turboModuleManagerDelegate = turboModuleManagerDelegate;
|
||||
}
|
||||
return self;
|
||||
@@ -138,9 +158,11 @@
|
||||
}
|
||||
|
||||
- (UIView *)viewWithModuleName:(NSString *)moduleName
|
||||
initialProperties:(NSDictionary *)initProps
|
||||
initialProperties:(NSDictionary *)initialProperties
|
||||
launchOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
NSDictionary *initProps = updateInitialProps(initialProperties, _configuration.fabricEnabled);
|
||||
|
||||
if (_configuration.bridgelessEnabled) {
|
||||
// Enable TurboModule interop by default in Bridgeless mode
|
||||
RCTEnableTurboModuleInterop(YES);
|
||||
@@ -154,8 +176,8 @@
|
||||
[[RCTSurfaceHostingProxyRootView alloc] initWithSurface:surface];
|
||||
|
||||
surfaceHostingProxyRootView.backgroundColor = [UIColor systemBackgroundColor];
|
||||
if (_configuration.customizeRootView != nil) {
|
||||
_configuration.customizeRootView(surfaceHostingProxyRootView);
|
||||
if (self->_configuration.customizeRootView != nil) {
|
||||
self->_configuration.customizeRootView(surfaceHostingProxyRootView);
|
||||
}
|
||||
return surfaceHostingProxyRootView;
|
||||
}
|
||||
@@ -169,8 +191,8 @@
|
||||
} else {
|
||||
rootView = [self createRootViewWithBridge:self.bridge moduleName:moduleName initProps:initProps];
|
||||
}
|
||||
if (_configuration.customizeRootView != nil) {
|
||||
_configuration.customizeRootView(rootView);
|
||||
if (self->_configuration.customizeRootView != nil) {
|
||||
self->_configuration.customizeRootView(rootView);
|
||||
}
|
||||
return rootView;
|
||||
}
|
||||
@@ -184,9 +206,11 @@
|
||||
moduleName:(NSString *)moduleName
|
||||
initProps:(NSDictionary *)initProps
|
||||
{
|
||||
BOOL enableFabric = _configuration.fabricEnabled;
|
||||
BOOL enableFabric = self->_configuration.fabricEnabled;
|
||||
UIView *rootView = RCTAppSetupDefaultRootView(bridge, moduleName, initProps, enableFabric);
|
||||
|
||||
rootView.backgroundColor = [UIColor systemBackgroundColor];
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@@ -257,6 +281,7 @@
|
||||
[reactHost setBundleURLProvider:^NSURL *() {
|
||||
return [weakSelf bundleURL];
|
||||
}];
|
||||
[reactHost setContextContainerHandler:self];
|
||||
[reactHost start];
|
||||
return reactHost;
|
||||
}
|
||||
@@ -264,12 +289,18 @@
|
||||
- (std::shared_ptr<facebook::react::JSRuntimeFactory>)createJSRuntimeFactory
|
||||
{
|
||||
#if USE_HERMES
|
||||
return std::make_shared<facebook::react::RCTHermesInstance>(nullptr, nullptr, /* allocInOldGenBeforeTTI */ false);
|
||||
return std::make_shared<facebook::react::RCTHermesInstance>(
|
||||
_reactNativeConfig, nullptr, /* allocInOldGenBeforeTTI */ false);
|
||||
#else
|
||||
return std::make_shared<facebook::react::RCTJscInstance>();
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)didCreateContextContainer:(std::shared_ptr<facebook::react::ContextContainer>)contextContainer
|
||||
{
|
||||
contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
|
||||
}
|
||||
|
||||
- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge
|
||||
{
|
||||
if (_configuration.extraModulesForBridge != nil) {
|
||||
|
||||
@@ -74,7 +74,7 @@ Pod::Spec.new do |s|
|
||||
s.dependency "React-RCTImage"
|
||||
s.dependency "React-CoreModules"
|
||||
s.dependency "React-nativeconfig"
|
||||
s.dependency "React-RCTFBReactNativeSpec"
|
||||
s.dependency "ReactCodegen"
|
||||
s.dependency "React-defaultsnativemodule"
|
||||
|
||||
add_dependency(s, "ReactCommon", :subspec => "turbomodule/core", :additional_framework_paths => ["react/nativemodule/core"])
|
||||
|
||||
@@ -57,7 +57,7 @@ Pod::Spec.new do |s|
|
||||
s.dependency "React-Core/RCTWebSocket"
|
||||
s.dependency "React-RCTNetwork"
|
||||
|
||||
add_dependency(s, "React-RCTFBReactNativeSpec")
|
||||
add_dependency(s, "ReactCodegen")
|
||||
add_dependency(s, "React-NativeModulesApple")
|
||||
add_dependency(s, "React-jsinspector", :framework_name => 'jsinspector_modern')
|
||||
add_dependency(s, "ReactCommon", :subspec => "turbomodule/core", :additional_framework_paths => ["react/nativemodule/core"])
|
||||
|
||||
+1
-8
@@ -56,7 +56,6 @@ const EventNames: Map<
|
||||
['screenReaderChanged', 'touchExplorationDidChange'],
|
||||
['accessibilityServiceChanged', 'accessibilityServiceDidChange'],
|
||||
['invertColorsChanged', 'invertColorDidChange'],
|
||||
['grayscaleChanged', 'grayscaleModeDidChange'],
|
||||
])
|
||||
: new Map([
|
||||
['announcementFinished', 'announcementFinished'],
|
||||
@@ -115,13 +114,7 @@ const AccessibilityInfo = {
|
||||
*/
|
||||
isGrayscaleEnabled(): Promise<boolean> {
|
||||
if (Platform.OS === 'android') {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (NativeAccessibilityInfoAndroid?.isGrayscaleEnabled != null) {
|
||||
NativeAccessibilityInfoAndroid.isGrayscaleEnabled(resolve);
|
||||
} else {
|
||||
reject(null);
|
||||
}
|
||||
});
|
||||
return Promise.resolve(false);
|
||||
} else {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (NativeAccessibilityManagerIOS != null) {
|
||||
|
||||
Vendored
+1
@@ -31,6 +31,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = {
|
||||
pagingEnabled: true,
|
||||
persistentScrollbar: true,
|
||||
horizontal: true,
|
||||
enableSyncOnScroll: true,
|
||||
scrollEnabled: true,
|
||||
scrollEventThrottle: true,
|
||||
scrollPerfTag: true,
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
import type {
|
||||
TScrollViewNativeComponentInstance,
|
||||
TScrollViewNativeImperativeHandle,
|
||||
} from '../../../src/private/components/useSyncOnScroll';
|
||||
import type {HostInstance} from '../../Renderer/shims/ReactNativeTypes';
|
||||
import type {EdgeInsetsProp} from '../../StyleSheet/EdgeInsetsPropType';
|
||||
import type {PointProp} from '../../StyleSheet/PointPropType';
|
||||
@@ -42,6 +46,7 @@ import StyleSheet from '../../StyleSheet/StyleSheet';
|
||||
import Dimensions from '../../Utilities/Dimensions';
|
||||
import dismissKeyboard from '../../Utilities/dismissKeyboard';
|
||||
import Platform from '../../Utilities/Platform';
|
||||
import EventEmitter from '../../vendor/emitter/EventEmitter';
|
||||
import Keyboard from '../Keyboard/Keyboard';
|
||||
import TextInputState from '../TextInput/TextInputState';
|
||||
import processDecelerationRate from './processDecelerationRate';
|
||||
@@ -147,7 +152,7 @@ export type DecelerationRateType = 'fast' | 'normal' | number;
|
||||
export type ScrollResponderType = ScrollViewImperativeMethods;
|
||||
|
||||
type PublicScrollViewInstance = $ReadOnly<{|
|
||||
...HostInstance,
|
||||
...$Exact<TScrollViewNativeComponentInstance>,
|
||||
...ScrollViewImperativeMethods,
|
||||
|}>;
|
||||
|
||||
@@ -738,6 +743,10 @@ class ScrollView extends React.Component<Props, State> {
|
||||
_subscriptionKeyboardDidShow: ?EventSubscription = null;
|
||||
_subscriptionKeyboardDidHide: ?EventSubscription = null;
|
||||
|
||||
#onScrollEmitter: ?EventEmitter<{
|
||||
scroll: [{x: number, y: number}],
|
||||
}> = null;
|
||||
|
||||
state: State = {
|
||||
layoutHeight: null,
|
||||
};
|
||||
@@ -808,6 +817,8 @@ class ScrollView extends React.Component<Props, State> {
|
||||
if (this._scrollAnimatedValueAttachment) {
|
||||
this._scrollAnimatedValueAttachment.detach();
|
||||
}
|
||||
|
||||
this.#onScrollEmitter?.removeAllListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -833,8 +844,9 @@ class ScrollView extends React.Component<Props, State> {
|
||||
return this._innerView.nativeInstance;
|
||||
};
|
||||
|
||||
getNativeScrollRef: () => HostInstance | null = () => {
|
||||
return this._scrollView.nativeInstance;
|
||||
getNativeScrollRef: () => TScrollViewNativeComponentInstance | null = () => {
|
||||
const {nativeInstance} = this._scrollView;
|
||||
return nativeInstance == null ? null : nativeInstance.componentRef.current;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -925,6 +937,20 @@ class ScrollView extends React.Component<Props, State> {
|
||||
Commands.flashScrollIndicators(component);
|
||||
};
|
||||
|
||||
_subscribeToOnScroll: (
|
||||
callback: ({x: number, y: number}) => void,
|
||||
) => EventSubscription = callback => {
|
||||
let onScrollEmitter = this.#onScrollEmitter;
|
||||
if (onScrollEmitter == null) {
|
||||
onScrollEmitter = new EventEmitter();
|
||||
this.#onScrollEmitter = onScrollEmitter;
|
||||
// This is the first subscription, so make sure the native component is
|
||||
// also configured to output synchronous scroll events.
|
||||
this._scrollView.nativeInstance?.unstable_setEnableSyncOnScroll(true);
|
||||
}
|
||||
return onScrollEmitter.addListener('scroll', callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* This method should be used as the callback to onFocus in a TextInputs'
|
||||
* parent view. Note that any module using this mixin needs to return
|
||||
@@ -1128,6 +1154,11 @@ class ScrollView extends React.Component<Props, State> {
|
||||
_handleScroll = (e: ScrollEvent) => {
|
||||
this._observedScrollSinceBecomingResponder = true;
|
||||
this.props.onScroll && this.props.onScroll(e);
|
||||
|
||||
this.#onScrollEmitter?.emit('scroll', {
|
||||
x: e.nativeEvent.contentOffset.x,
|
||||
y: e.nativeEvent.contentOffset.y,
|
||||
});
|
||||
};
|
||||
|
||||
_handleLayout = (e: LayoutEvent) => {
|
||||
@@ -1150,36 +1181,45 @@ class ScrollView extends React.Component<Props, State> {
|
||||
(instance: InnerViewInstance): InnerViewInstance => instance,
|
||||
);
|
||||
|
||||
_scrollView: RefForwarder<HostInstance, PublicScrollViewInstance | null> =
|
||||
createRefForwarder(nativeInstance => {
|
||||
// This is a hack. Ideally we would forwardRef to the underlying
|
||||
// host component. However, since ScrollView has it's own methods that can be
|
||||
// called as well, if we used the standard forwardRef then these
|
||||
// methods wouldn't be accessible and thus be a breaking change.
|
||||
//
|
||||
// Therefore we edit ref to include ScrollView's public methods so that
|
||||
// they are callable from the ref.
|
||||
_scrollView: RefForwarder<
|
||||
TScrollViewNativeImperativeHandle,
|
||||
PublicScrollViewInstance | null,
|
||||
> = createRefForwarder(nativeImperativeHandle => {
|
||||
const nativeInstance = nativeImperativeHandle.componentRef.current;
|
||||
if (nativeInstance == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// $FlowFixMe[prop-missing] - Known issue with appending custom methods.
|
||||
const publicInstance: PublicScrollViewInstance = Object.assign(
|
||||
nativeInstance,
|
||||
{
|
||||
getScrollResponder: this.getScrollResponder,
|
||||
getScrollableNode: this.getScrollableNode,
|
||||
getInnerViewNode: this.getInnerViewNode,
|
||||
getInnerViewRef: this.getInnerViewRef,
|
||||
getNativeScrollRef: this.getNativeScrollRef,
|
||||
scrollTo: this.scrollTo,
|
||||
scrollToEnd: this.scrollToEnd,
|
||||
flashScrollIndicators: this.flashScrollIndicators,
|
||||
scrollResponderZoomTo: this.scrollResponderZoomTo,
|
||||
scrollResponderScrollNativeHandleToKeyboard:
|
||||
this.scrollResponderScrollNativeHandleToKeyboard,
|
||||
},
|
||||
);
|
||||
// This is a hack. Ideally we would forwardRef to the underlying
|
||||
// host component. However, since ScrollView has it's own methods that can be
|
||||
// called as well, if we used the standard forwardRef then these
|
||||
// methods wouldn't be accessible and thus be a breaking change.
|
||||
//
|
||||
// Therefore we edit ref to include ScrollView's public methods so that
|
||||
// they are callable from the ref.
|
||||
|
||||
return publicInstance;
|
||||
});
|
||||
// $FlowFixMe[prop-missing] - Known issue with appending custom methods.
|
||||
const publicInstance: PublicScrollViewInstance = Object.assign(
|
||||
nativeInstance,
|
||||
{
|
||||
getScrollResponder: this.getScrollResponder,
|
||||
getScrollableNode: this.getScrollableNode,
|
||||
getInnerViewNode: this.getInnerViewNode,
|
||||
getInnerViewRef: this.getInnerViewRef,
|
||||
getNativeScrollRef: this.getNativeScrollRef,
|
||||
scrollTo: this.scrollTo,
|
||||
scrollToEnd: this.scrollToEnd,
|
||||
flashScrollIndicators: this.flashScrollIndicators,
|
||||
scrollResponderZoomTo: this.scrollResponderZoomTo,
|
||||
// TODO: Replace unstable_subscribeToOnScroll once scrollView.addEventListener('scroll', (e: ScrollEvent) => {}, {passive: false});
|
||||
unstable_subscribeToOnScroll: this._subscribeToOnScroll,
|
||||
scrollResponderScrollNativeHandleToKeyboard:
|
||||
this.scrollResponderScrollNativeHandleToKeyboard,
|
||||
},
|
||||
);
|
||||
|
||||
return publicInstance;
|
||||
});
|
||||
|
||||
/**
|
||||
* Warning, this may be called several times for a single keyboard opening.
|
||||
@@ -1789,9 +1829,8 @@ class ScrollView extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
const refreshControl = this.props.refreshControl;
|
||||
const scrollViewRef = this._scrollView.getForwardingRef(
|
||||
this.props.scrollViewRef,
|
||||
);
|
||||
const scrollViewRef: React.RefSetter<TScrollViewNativeImperativeHandle | null> =
|
||||
this._scrollView.getForwardingRef(this.props.scrollViewRef);
|
||||
|
||||
if (refreshControl) {
|
||||
if (Platform.OS === 'ios') {
|
||||
|
||||
+2
@@ -45,6 +45,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig =
|
||||
diff: require('../../Utilities/differ/pointsDiffer'),
|
||||
},
|
||||
decelerationRate: true,
|
||||
enableSyncOnScroll: true, // Fabric only.
|
||||
disableIntervalMomentum: true,
|
||||
maintainVisibleContentPosition: true,
|
||||
pagingEnabled: true,
|
||||
@@ -134,6 +135,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig =
|
||||
contentInsetAdjustmentBehavior: true,
|
||||
decelerationRate: true,
|
||||
endDraggingSensitivityMultiplier: true,
|
||||
enableSyncOnScroll: true, // Fabric only.
|
||||
directionalLockEnabled: true,
|
||||
disableIntervalMomentum: true,
|
||||
indicatorStyle: true,
|
||||
|
||||
+1
@@ -301,6 +301,7 @@ const ScrollViewStickyHeaderWithForwardedRef: component(
|
||||
const styles = StyleSheet.create({
|
||||
header: {
|
||||
zIndex: 10,
|
||||
position: 'relative',
|
||||
},
|
||||
fill: {
|
||||
flex: 1,
|
||||
|
||||
-1
@@ -121,7 +121,6 @@ const RCTTextInputViewConfig = {
|
||||
},
|
||||
editable: true,
|
||||
inputAccessoryViewID: true,
|
||||
inputAccessoryViewButtonLabel: true,
|
||||
caretHidden: true,
|
||||
enablesReturnKeyAutomatically: true,
|
||||
placeholderTextColor: {
|
||||
|
||||
@@ -266,12 +266,6 @@ type IOSProps = $ReadOnly<{|
|
||||
*/
|
||||
inputAccessoryViewID?: ?string,
|
||||
|
||||
/**
|
||||
* An optional label that overrides the default input accessory view button label.
|
||||
* @platform ios
|
||||
*/
|
||||
inputAccessoryViewButtonLabel?: ?string,
|
||||
|
||||
/**
|
||||
* Determines the color of the keyboard.
|
||||
* @platform ios
|
||||
|
||||
@@ -310,12 +310,6 @@ type IOSProps = $ReadOnly<{|
|
||||
*/
|
||||
inputAccessoryViewID?: ?string,
|
||||
|
||||
/**
|
||||
* An optional label that overrides the default input accessory view button label.
|
||||
* @platform ios
|
||||
*/
|
||||
inputAccessoryViewButtonLabel?: ?string,
|
||||
|
||||
/**
|
||||
* Determines the color of the keyboard.
|
||||
* @platform ios
|
||||
@@ -1539,7 +1533,7 @@ function InternalTextInput(props: Props): React.Node {
|
||||
|
||||
// TextInput handles onBlur and onFocus events
|
||||
// so omitting onBlur and onFocus pressability handlers here.
|
||||
const {onBlur, onFocus, ...eventHandlers} = usePressability(config);
|
||||
const {onBlur, onFocus, ...eventHandlers} = usePressability(config) || {};
|
||||
|
||||
let _accessibilityState;
|
||||
if (
|
||||
|
||||
+2
-1
@@ -195,7 +195,8 @@ module.exports = function TouchableWithoutFeedback(props: Props): React.Node {
|
||||
|
||||
// BACKWARD-COMPATIBILITY: Focus and blur events were never supported before
|
||||
// adopting `Pressability`, so preserve that behavior.
|
||||
const {onBlur, onFocus, ...eventHandlersWithoutBlurAndFocus} = eventHandlers;
|
||||
const {onBlur, onFocus, ...eventHandlersWithoutBlurAndFocus} =
|
||||
eventHandlers || {};
|
||||
|
||||
const elementProps: {[string]: mixed, ...} = {
|
||||
...eventHandlersWithoutBlurAndFocus,
|
||||
|
||||
@@ -211,11 +211,4 @@ export interface ViewProps
|
||||
* Used to reference react managed views from native code.
|
||||
*/
|
||||
nativeID?: string | undefined;
|
||||
|
||||
/**
|
||||
* Contols whether this view, and its transitive children, are laid in a way
|
||||
* consistent with web browsers ('strict'), or consistent with existing
|
||||
* React Native code which may rely on incorrect behavior ('classic').
|
||||
*/
|
||||
experimental_layoutConformance?: 'strict' | 'classic' | undefined;
|
||||
}
|
||||
|
||||
@@ -177,7 +177,10 @@ function reactConsoleErrorHandler(...args) {
|
||||
if (!console.reportErrorsAsExceptions) {
|
||||
return;
|
||||
}
|
||||
if (inExceptionHandler || global.RN$inExceptionHandler?.()) {
|
||||
if (
|
||||
inExceptionHandler ||
|
||||
(global.RN$inExceptionHandler && global.RN$inExceptionHandler())
|
||||
) {
|
||||
// The fundamental trick here is that are multiple entry point to logging errors:
|
||||
// (see D19743075 for more background)
|
||||
//
|
||||
|
||||
+18
-20
@@ -10,26 +10,24 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
if (global.RN$useAlwaysAvailableJSErrorHandling !== true) {
|
||||
/**
|
||||
* Sets up the console and exception handling (redbox) for React Native.
|
||||
* You can use this module directly, or just require InitializeCore.
|
||||
*/
|
||||
const ExceptionsManager = require('./ExceptionsManager');
|
||||
ExceptionsManager.installConsoleErrorReporter();
|
||||
/**
|
||||
* Sets up the console and exception handling (redbox) for React Native.
|
||||
* You can use this module directly, or just require InitializeCore.
|
||||
*/
|
||||
const ExceptionsManager = require('./ExceptionsManager');
|
||||
ExceptionsManager.installConsoleErrorReporter();
|
||||
|
||||
// Set up error handler
|
||||
if (!global.__fbDisableExceptionsManager) {
|
||||
const handleError = (e: mixed, isFatal: boolean) => {
|
||||
try {
|
||||
ExceptionsManager.handleException(e, isFatal);
|
||||
} catch (ee) {
|
||||
console.log('Failed to print error: ', ee.message);
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
// Set up error handler
|
||||
if (!global.__fbDisableExceptionsManager) {
|
||||
const handleError = (e: mixed, isFatal: boolean) => {
|
||||
try {
|
||||
ExceptionsManager.handleException(e, isFatal);
|
||||
} catch (ee) {
|
||||
console.log('Failed to print error: ', ee.message);
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
const ErrorUtils = require('../vendor/core/ErrorUtils');
|
||||
ErrorUtils.setGlobalHandler(handleError);
|
||||
}
|
||||
const ErrorUtils = require('../vendor/core/ErrorUtils');
|
||||
ErrorUtils.setGlobalHandler(handleError);
|
||||
}
|
||||
|
||||
+12
-4
@@ -26,10 +26,18 @@ const isEventLoopEnabled = (() => {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
ReactNativeFeatureFlags.enableBridgelessArchitecture() &&
|
||||
!ReactNativeFeatureFlags.disableEventLoopOnBridgeless()
|
||||
);
|
||||
if (NativeReactNativeFeatureFlags.disableEventLoopOnBridgeless == null) {
|
||||
// Flags not unified yet
|
||||
return (
|
||||
ReactNativeFeatureFlags.useModernRuntimeScheduler() &&
|
||||
ReactNativeFeatureFlags.enableMicrotasks()
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
ReactNativeFeatureFlags.enableBridgelessArchitecture() &&
|
||||
!ReactNativeFeatureFlags.disableEventLoopOnBridgeless()
|
||||
);
|
||||
}
|
||||
})();
|
||||
|
||||
// In bridgeless mode, timers are host functions installed from cpp.
|
||||
|
||||
@@ -200,8 +200,6 @@ export interface ImagePropsBase
|
||||
* 'center': Scale the image down so that it is completely visible,
|
||||
* if bigger than the area of the view.
|
||||
* The image will not be scaled up.
|
||||
*
|
||||
* 'none': Do not resize the image. The image will be displayed at its intrinsic size.
|
||||
*/
|
||||
resizeMode?: ImageResizeMode | undefined;
|
||||
|
||||
|
||||
+1
-2
@@ -19,7 +19,6 @@ import type {
|
||||
} from '../StyleSheet/StyleSheet';
|
||||
import type {LayoutEvent, SyntheticEvent} from '../Types/CoreEventTypes';
|
||||
import typeof Image from './Image';
|
||||
import type {ImageResizeMode} from './ImageResizeMode';
|
||||
import type {ImageSource} from './ImageSource';
|
||||
import type {ElementRef, Node, RefSetter} from 'react';
|
||||
|
||||
@@ -235,7 +234,7 @@ export type ImageProps = $ReadOnly<{|
|
||||
*
|
||||
* See https://reactnative.dev/docs/image#resizemode
|
||||
*/
|
||||
resizeMode?: ?ImageResizeMode,
|
||||
resizeMode?: ?('cover' | 'contain' | 'stretch' | 'repeat' | 'center'),
|
||||
|
||||
/**
|
||||
* A unique identifier for this element to be used in UI Automation
|
||||
|
||||
@@ -12,8 +12,7 @@ export type ImageResizeMode =
|
||||
| 'contain'
|
||||
| 'stretch'
|
||||
| 'repeat'
|
||||
| 'center'
|
||||
| 'none';
|
||||
| 'center';
|
||||
|
||||
/**
|
||||
* @see ImageResizeMode.js
|
||||
@@ -47,10 +46,4 @@ export interface ImageResizeModeStatic {
|
||||
* image will keep it's size and aspect ratio.
|
||||
*/
|
||||
repeat: ImageResizeMode;
|
||||
|
||||
/**
|
||||
* none - The image will be displayed at its intrinsic size, which means the
|
||||
* image will not be scaled up or down.
|
||||
*/
|
||||
none: ImageResizeMode;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,4 @@ export type ImageResizeMode =
|
||||
|
||||
// Resize by stretching it to fill the entire frame of the view without
|
||||
// clipping. This may change the aspect ratio of the image, distorting it.
|
||||
| 'stretch'
|
||||
|
||||
// The image will not be resized at all.
|
||||
| 'none';
|
||||
| 'stretch';
|
||||
|
||||
@@ -50,6 +50,8 @@ export interface ImageURISource {
|
||||
* its age or expiration date. If there is no existing data in the cache corresponding
|
||||
* to a URL load request, no attempt is made to load the data from the originating source,
|
||||
* and the load is considered to have failed.
|
||||
*
|
||||
* @platform ios (for `force-cache`)
|
||||
*/
|
||||
cache?: 'default' | 'reload' | 'force-cache' | 'only-if-cached' | undefined;
|
||||
/**
|
||||
|
||||
@@ -65,6 +65,8 @@ export interface ImageURISource {
|
||||
* its age or expiration date. If there is no existing data in the cache corresponding
|
||||
* to a URL load request, no attempt is made to load the data from the originating source,
|
||||
* and the load is considered to have failed.
|
||||
*
|
||||
* @platform ios (for `force-cache`)
|
||||
*/
|
||||
+cache?: ?('default' | 'reload' | 'force-cache' | 'only-if-cached');
|
||||
|
||||
|
||||
+3
-6
@@ -8,18 +8,15 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {ImageResizeMode} from './ImageResizeMode';
|
||||
type ResizeMode = 'cover' | 'contain' | 'stretch' | 'repeat' | 'center';
|
||||
|
||||
const objectFitMap: {[string]: ImageResizeMode} = {
|
||||
const objectFitMap: {[string]: ResizeMode} = {
|
||||
contain: 'contain',
|
||||
cover: 'cover',
|
||||
fill: 'stretch',
|
||||
'scale-down': 'contain',
|
||||
none: 'none',
|
||||
};
|
||||
|
||||
export function convertObjectFitToResizeMode(
|
||||
objectFit: ?string,
|
||||
): ?ImageResizeMode {
|
||||
export function convertObjectFitToResizeMode(objectFit: ?string): ?ResizeMode {
|
||||
return objectFit != null ? objectFitMap[objectFit] : undefined;
|
||||
}
|
||||
|
||||
@@ -477,7 +477,10 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image, CGSize size, CGFloat scal
|
||||
|
||||
// Add missing png extension
|
||||
if (request.URL.fileURL && request.URL.pathExtension.length == 0) {
|
||||
mutableRequest.URL = [request.URL URLByAppendingPathExtension:@"png"];
|
||||
NSURL *pngRequestURL = [request.URL URLByAppendingPathExtension:@"png"];
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:pngRequestURL.path]) {
|
||||
mutableRequest.URL = pngRequestURL;
|
||||
}
|
||||
}
|
||||
if (_redirectDelegate != nil) {
|
||||
mutableRequest.URL = [_redirectDelegate redirectAssetsURL:mutableRequest.URL];
|
||||
|
||||
@@ -85,7 +85,6 @@ CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize, CGFloat destScale, RCTR
|
||||
switch (resizeMode) {
|
||||
case RCTResizeModeStretch:
|
||||
case RCTResizeModeRepeat:
|
||||
case RCTResizeModeNone:
|
||||
|
||||
return (CGRect){CGPointZero, RCTCeilSize(destSize, destScale)};
|
||||
|
||||
@@ -250,7 +249,6 @@ BOOL RCTUpscalingRequired(
|
||||
|
||||
case RCTResizeModeRepeat:
|
||||
case RCTResizeModeCenter:
|
||||
case RCTResizeModeNone:
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ typedef NS_ENUM(NSInteger, RCTResizeMode) {
|
||||
RCTResizeModeStretch = UIViewContentModeScaleToFill,
|
||||
RCTResizeModeCenter = UIViewContentModeCenter,
|
||||
RCTResizeModeRepeat = -1, // Use negative values to avoid conflicts with iOS enum values.
|
||||
RCTResizeModeNone = UIViewContentModeTopLeft,
|
||||
};
|
||||
|
||||
static inline RCTResizeMode RCTResizeModeFromUIViewContentMode(UIViewContentMode mode)
|
||||
@@ -31,14 +30,12 @@ static inline RCTResizeMode RCTResizeModeFromUIViewContentMode(UIViewContentMode
|
||||
case UIViewContentModeCenter:
|
||||
return RCTResizeModeCenter;
|
||||
break;
|
||||
case UIViewContentModeTopLeft:
|
||||
return RCTResizeModeNone;
|
||||
break;
|
||||
case UIViewContentModeRedraw:
|
||||
case UIViewContentModeTop:
|
||||
case UIViewContentModeBottom:
|
||||
case UIViewContentModeLeft:
|
||||
case UIViewContentModeRight:
|
||||
case UIViewContentModeTopLeft:
|
||||
case UIViewContentModeTopRight:
|
||||
case UIViewContentModeBottomLeft:
|
||||
case UIViewContentModeBottomRight:
|
||||
|
||||
@@ -17,7 +17,6 @@ RCT_ENUM_CONVERTER(
|
||||
@"stretch" : @(RCTResizeModeStretch),
|
||||
@"center" : @(RCTResizeModeCenter),
|
||||
@"repeat" : @(RCTResizeModeRepeat),
|
||||
@"none" : @(RCTResizeModeNone),
|
||||
}),
|
||||
RCTResizeModeStretch,
|
||||
integerValue)
|
||||
|
||||
@@ -53,7 +53,7 @@ Pod::Spec.new do |s|
|
||||
s.dependency "React-Core/RCTImageHeaders"
|
||||
s.dependency "React-RCTNetwork"
|
||||
|
||||
add_dependency(s, "React-RCTFBReactNativeSpec")
|
||||
add_dependency(s, "ReactCodegen")
|
||||
add_dependency(s, "ReactCommon", :subspec => "turbomodule/core", :additional_framework_paths => ["react/nativemodule/core"])
|
||||
add_dependency(s, "React-NativeModulesApple")
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
import type {Task} from './TaskQueue';
|
||||
|
||||
import * as ReactNativeFeatureFlags from '../../src/private/featureflags/ReactNativeFeatureFlags';
|
||||
import EventEmitter from '../vendor/emitter/EventEmitter';
|
||||
|
||||
const BatchedBridge = require('../BatchedBridge/BatchedBridge');
|
||||
@@ -209,8 +208,4 @@ function _processUpdate() {
|
||||
_deleteInteractionSet.clear();
|
||||
}
|
||||
|
||||
module.exports = (
|
||||
ReactNativeFeatureFlags.disableInteractionManager()
|
||||
? require('./InteractionManagerStub')
|
||||
: InteractionManager
|
||||
) as typeof InteractionManager;
|
||||
module.exports = InteractionManager;
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {EventSubscription} from '../vendor/emitter/EventEmitter';
|
||||
|
||||
const invariant = require('invariant');
|
||||
|
||||
export type Handle = number;
|
||||
|
||||
type Task =
|
||||
| {
|
||||
name: string,
|
||||
run: () => void,
|
||||
}
|
||||
| {
|
||||
name: string,
|
||||
gen: () => Promise<void>,
|
||||
}
|
||||
| (() => void);
|
||||
|
||||
/**
|
||||
* InteractionManager allows long-running work to be scheduled after any
|
||||
* interactions/animations have completed. In particular, this allows JavaScript
|
||||
* animations to run smoothly.
|
||||
*
|
||||
* Applications can schedule tasks to run after interactions with the following:
|
||||
*
|
||||
* ```
|
||||
* InteractionManager.runAfterInteractions(() => {
|
||||
* // ...long-running synchronous task...
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Compare this to other scheduling alternatives:
|
||||
*
|
||||
* - requestAnimationFrame(): for code that animates a view over time.
|
||||
* - setImmediate/setTimeout(): run code later, note this may delay animations.
|
||||
* - runAfterInteractions(): run code later, without delaying active animations.
|
||||
*
|
||||
* The touch handling system considers one or more active touches to be an
|
||||
* 'interaction' and will delay `runAfterInteractions()` callbacks until all
|
||||
* touches have ended or been cancelled.
|
||||
*
|
||||
* InteractionManager also allows applications to register animations by
|
||||
* creating an interaction 'handle' on animation start, and clearing it upon
|
||||
* completion:
|
||||
*
|
||||
* ```
|
||||
* var handle = InteractionManager.createInteractionHandle();
|
||||
* // run animation... (`runAfterInteractions` tasks are queued)
|
||||
* // later, on animation completion:
|
||||
* InteractionManager.clearInteractionHandle(handle);
|
||||
* // queued tasks run if all handles were cleared
|
||||
* ```
|
||||
*
|
||||
* `runAfterInteractions` takes either a plain callback function, or a
|
||||
* `PromiseTask` object with a `gen` method that returns a `Promise`. If a
|
||||
* `PromiseTask` is supplied, then it is fully resolved (including asynchronous
|
||||
* dependencies that also schedule more tasks via `runAfterInteractions`) before
|
||||
* starting on the next task that might have been queued up synchronously
|
||||
* earlier.
|
||||
*
|
||||
* By default, queued tasks are executed together in a loop in one
|
||||
* `setImmediate` batch. If `setDeadline` is called with a positive number, then
|
||||
* tasks will only be executed until the deadline (in terms of js event loop run
|
||||
* time) approaches, at which point execution will yield via setTimeout,
|
||||
* allowing events such as touches to start interactions and block queued tasks
|
||||
* from executing, making apps more responsive.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
const InteractionManagerStub = {
|
||||
Events: {
|
||||
interactionStart: 'interactionStart',
|
||||
interactionComplete: 'interactionComplete',
|
||||
},
|
||||
|
||||
/**
|
||||
* Schedule a function to run after all interactions have completed. Returns a cancellable
|
||||
* "promise".
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
runAfterInteractions(task: ?Task): {
|
||||
then: <U>(
|
||||
onFulfill?: ?(void) => ?(Promise<U> | U),
|
||||
onReject?: ?(error: mixed) => ?(Promise<U> | U),
|
||||
) => Promise<U>,
|
||||
cancel: () => void,
|
||||
...
|
||||
} {
|
||||
let immediateID: ?$FlowIssue;
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
immediateID = setImmediate(() => {
|
||||
if (typeof task === 'object' && task !== null) {
|
||||
if (typeof task.gen === 'function') {
|
||||
task.gen().then(resolve, reject);
|
||||
} else if (typeof task.run === 'function') {
|
||||
try {
|
||||
task.run();
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
} else {
|
||||
reject(new TypeError(`Task "${task.name}" missing gen or run.`));
|
||||
}
|
||||
} else if (typeof task === 'function') {
|
||||
try {
|
||||
task();
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
} else {
|
||||
reject(new TypeError('Invalid task of type: ' + typeof task));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
||||
then: promise.then.bind(promise),
|
||||
cancel() {
|
||||
clearImmediate(immediateID);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify manager that an interaction has started.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
createInteractionHandle(): Handle {
|
||||
return -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify manager that an interaction has completed.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
clearInteractionHandle(handle: Handle) {
|
||||
invariant(!!handle, 'InteractionManager: Must provide a handle to clear.');
|
||||
},
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
addListener(): EventSubscription {
|
||||
return {
|
||||
remove() {},
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* A positive number will use setTimeout to schedule any tasks after the
|
||||
* eventLoopRunningTime hits the deadline value, otherwise all tasks will be
|
||||
* executed in one setImmediate batch (default).
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
setDeadline(deadline: number) {
|
||||
// Do nothing.
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = InteractionManagerStub;
|
||||
@@ -50,7 +50,7 @@ Pod::Spec.new do |s|
|
||||
s.dependency "ReactCommon/turbomodule/core", version
|
||||
s.dependency "React-jsi", version
|
||||
|
||||
add_dependency(s, "React-RCTFBReactNativeSpec")
|
||||
add_dependency(s, "ReactCodegen", :additional_framework_paths => ["build/generated/ios"])
|
||||
add_dependency(s, "ReactCommon", :subspec => "turbomodule/core", :additional_framework_paths => ["react/nativemodule/core"])
|
||||
add_dependency(s, "React-NativeModulesApple", :additional_framework_paths => ["build/generated/ios"])
|
||||
end
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ if (__DEV__) {
|
||||
if (global.RN$registerExceptionListener != null) {
|
||||
global.RN$registerExceptionListener(
|
||||
(error: ExtendedExceptionData & {preventDefault: () => mixed}) => {
|
||||
if (global.RN$isRuntimeReady?.() || !error.isFatal) {
|
||||
if (!error.isFatal) {
|
||||
error.preventDefault();
|
||||
addException(error);
|
||||
}
|
||||
|
||||
+9
-15
@@ -80,24 +80,21 @@ describe('LogBox', () => {
|
||||
expect(mockWarn).not.toBeCalled();
|
||||
expect(console.error).toBeCalledTimes(1);
|
||||
expect(console.error.mock.calls[0]).toEqual([
|
||||
expect.stringMatching(
|
||||
'Each child in a list should have a unique "key" prop',
|
||||
),
|
||||
expect.stringMatching('Check the render method of `DoesNotUseKey`'),
|
||||
'Warning: Each child in a list should have a unique "key" prop.%s%s See https://reactjs.org/link/warning-keys for more information.%s',
|
||||
'\n\nCheck the render method of `DoesNotUseKey`.',
|
||||
'',
|
||||
expect.stringMatching('at DoesNotUseKey'),
|
||||
]);
|
||||
expect(spy).toHaveBeenCalledWith({
|
||||
level: 'error',
|
||||
category: expect.stringContaining(
|
||||
'Each child in a list should have a unique',
|
||||
'Warning: Each child in a list should have a unique',
|
||||
),
|
||||
componentStack: expect.anything(),
|
||||
componentStackType: 'stack',
|
||||
message: {
|
||||
content: expect.stringContaining(
|
||||
'Each child in a list should have a unique "key" prop',
|
||||
),
|
||||
content:
|
||||
'Warning: Each child in a list should have a unique "key" prop.\n\nCheck the render method of `DoesNotUseKey`. See https://reactjs.org/link/warning-keys for more information.',
|
||||
substitutions: [
|
||||
{length: 45, offset: 62},
|
||||
{length: 0, offset: 107},
|
||||
@@ -109,7 +106,7 @@ describe('LogBox', () => {
|
||||
// We also interpolate the string before passing to the underlying console method.
|
||||
expect(mockError.mock.calls[0]).toEqual([
|
||||
expect.stringMatching(
|
||||
'Each child in a list should have a unique "key" prop',
|
||||
'Warning: Each child in a list should have a unique "key" prop.\n\nCheck the render method of `DoesNotUseKey`. See https://reactjs.org/link/warning-keys for more information.\n at ',
|
||||
),
|
||||
]);
|
||||
});
|
||||
@@ -137,9 +134,7 @@ describe('LogBox', () => {
|
||||
expect(mockWarn).not.toBeCalled();
|
||||
expect(console.error).toBeCalledTimes(1);
|
||||
expect(console.error.mock.calls[0]).toEqual([
|
||||
expect.stringMatching(
|
||||
'Invalid prop `%s` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.%s',
|
||||
),
|
||||
'Warning: Invalid prop `%s` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.%s',
|
||||
'invalid',
|
||||
expect.stringMatching('at FragmentWithProp'),
|
||||
]);
|
||||
@@ -149,9 +144,8 @@ describe('LogBox', () => {
|
||||
componentStack: expect.anything(),
|
||||
componentStackType: expect.stringMatching(/(stack|legacy)/),
|
||||
message: {
|
||||
content: expect.stringMatching(
|
||||
'Invalid prop `invalid` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.',
|
||||
),
|
||||
content:
|
||||
'Warning: Invalid prop `invalid` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.',
|
||||
substitutions: [{length: 7, offset: 23}],
|
||||
},
|
||||
});
|
||||
|
||||
@@ -101,11 +101,6 @@ export interface ModalPropsAndroid {
|
||||
* Determines whether your modal should go under the system statusbar.
|
||||
*/
|
||||
statusBarTranslucent?: boolean | undefined;
|
||||
|
||||
/**
|
||||
* Determines whether your modal should go under the system navigationbar.
|
||||
*/
|
||||
navigationBarTranslucent?: boolean | undefined;
|
||||
}
|
||||
|
||||
export type ModalProps = ModalBaseProps &
|
||||
|
||||
-17
@@ -95,14 +95,6 @@ export type Props = $ReadOnly<{|
|
||||
*/
|
||||
statusBarTranslucent?: ?boolean,
|
||||
|
||||
/**
|
||||
* The `navigationBarTranslucent` prop determines whether your modal should go under
|
||||
* the system navigationbar.
|
||||
*
|
||||
* See https://reactnative.dev/docs/modal.html#navigationbartranslucent-android
|
||||
*/
|
||||
navigationBarTranslucent?: ?boolean,
|
||||
|
||||
/**
|
||||
* The `hardwareAccelerated` prop controls whether to force hardware
|
||||
* acceleration for the underlying window.
|
||||
@@ -184,14 +176,6 @@ function confirmProps(props: Props) {
|
||||
`Modal with '${props.presentationStyle}' presentation style and 'transparent' value is not supported.`,
|
||||
);
|
||||
}
|
||||
if (
|
||||
props.navigationBarTranslucent === true &&
|
||||
props.statusBarTranslucent !== true
|
||||
) {
|
||||
console.warn(
|
||||
'Modal with translucent navigation bar and without translucent status bar is not supported.',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +301,6 @@ class Modal extends React.Component<Props, State> {
|
||||
onDismiss={onDismiss}
|
||||
visible={this.props.visible}
|
||||
statusBarTranslucent={this.props.statusBarTranslucent}
|
||||
navigationBarTranslucent={this.props.navigationBarTranslucent}
|
||||
identifier={this._identifier}
|
||||
style={styles.modal}
|
||||
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
||||
|
||||
@@ -50,7 +50,7 @@ Pod::Spec.new do |s|
|
||||
s.dependency "React-jsi"
|
||||
s.dependency "React-Core/RCTAnimationHeaders"
|
||||
|
||||
add_dependency(s, "React-RCTFBReactNativeSpec")
|
||||
add_dependency(s, "ReactCodegen", :additional_framework_paths => ["build/generated/ios"])
|
||||
add_dependency(s, "ReactCommon", :subspec => "turbomodule/core", :additional_framework_paths => ["react/nativemodule/core"])
|
||||
add_dependency(s, "React-NativeModulesApple")
|
||||
end
|
||||
|
||||
@@ -50,7 +50,7 @@ Pod::Spec.new do |s|
|
||||
s.dependency "React-jsi"
|
||||
s.dependency "React-Core/RCTNetworkHeaders"
|
||||
|
||||
add_dependency(s, "React-RCTFBReactNativeSpec")
|
||||
add_dependency(s, "ReactCodegen", :additional_framework_paths => ["build/generated/ios"])
|
||||
add_dependency(s, "ReactCommon", :subspec => "turbomodule/core", :additional_framework_paths => ["react/nativemodule/core"])
|
||||
add_dependency(s, "React-NativeModulesApple", :additional_framework_paths => ["build/generated/ios"])
|
||||
end
|
||||
|
||||
+2
-49
@@ -66,58 +66,11 @@ export interface PermissionsAndroidStatic {
|
||||
/**
|
||||
* A list of permission results that are returned
|
||||
*/
|
||||
RESULTS: {
|
||||
[key in 'GRANTED' | 'DENIED' | 'NEVER_ASK_AGAIN']: PermissionStatus;
|
||||
};
|
||||
RESULTS: {[key: string]: PermissionStatus};
|
||||
/**
|
||||
* A list of specified "dangerous" permissions that require prompting the user
|
||||
*/
|
||||
PERMISSIONS: {
|
||||
[key in
|
||||
| 'READ_CALENDAR'
|
||||
| 'WRITE_CALENDAR'
|
||||
| 'CAMERA'
|
||||
| 'READ_CONTACTS'
|
||||
| 'WRITE_CONTACTS'
|
||||
| 'GET_ACCOUNTS'
|
||||
| 'ACCESS_FINE_LOCATION'
|
||||
| 'ACCESS_COARSE_LOCATION'
|
||||
| 'ACCESS_BACKGROUND_LOCATION'
|
||||
| 'RECORD_AUDIO'
|
||||
| 'READ_PHONE_STATE'
|
||||
| 'CALL_PHONE'
|
||||
| 'READ_CALL_LOG'
|
||||
| 'WRITE_CALL_LOG'
|
||||
| 'ADD_VOICEMAIL'
|
||||
| 'READ_VOICEMAIL'
|
||||
| 'WRITE_VOICEMAIL'
|
||||
| 'USE_SIP'
|
||||
| 'PROCESS_OUTGOING_CALLS'
|
||||
| 'BODY_SENSORS'
|
||||
| 'BODY_SENSORS_BACKGROUND'
|
||||
| 'SEND_SMS'
|
||||
| 'RECEIVE_SMS'
|
||||
| 'READ_SMS'
|
||||
| 'RECEIVE_WAP_PUSH'
|
||||
| 'RECEIVE_MMS'
|
||||
| 'READ_EXTERNAL_STORAGE'
|
||||
| 'READ_MEDIA_IMAGES'
|
||||
| 'READ_MEDIA_VIDEO'
|
||||
| 'READ_MEDIA_AUDIO'
|
||||
| 'READ_MEDIA_VISUAL_USER_SELECTED'
|
||||
| 'WRITE_EXTERNAL_STORAGE'
|
||||
| 'BLUETOOTH_CONNECT'
|
||||
| 'BLUETOOTH_SCAN'
|
||||
| 'BLUETOOTH_ADVERTISE'
|
||||
| 'ACCESS_MEDIA_LOCATION'
|
||||
| 'ACCEPT_HANDOVER'
|
||||
| 'ACTIVITY_RECOGNITION'
|
||||
| 'ANSWER_PHONE_CALLS'
|
||||
| 'READ_PHONE_NUMBERS'
|
||||
| 'UWB_RANGING'
|
||||
| 'POST_NOTIFICATIONS'
|
||||
| 'NEARBY_WIFI_DEVICES']: Permission;
|
||||
};
|
||||
PERMISSIONS: {[key: string]: Permission};
|
||||
new (): PermissionsAndroidStatic;
|
||||
/**
|
||||
* @deprecated Use check instead
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user