mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8dd8ec7cb0 | ||
|
|
e857d7066b | ||
|
|
769e35ba5f | ||
|
|
35aeb8c027 | ||
|
|
8fdecf3010 | ||
|
|
ff9855cc3b | ||
|
|
8a43321271 | ||
|
|
db1d60fa95 | ||
|
|
93c83181fb | ||
|
|
9837d2480c | ||
|
|
b68966ec7b | ||
|
|
99bc31cfa6 | ||
|
|
c36c481016 | ||
|
|
13f4fa0245 | ||
|
|
9792f2c9d7 | ||
|
|
53cec2dc1f | ||
|
|
b4f3d4b92e | ||
|
|
e741488659 | ||
|
|
bf4ee6f5c1 | ||
|
|
cecba01b71 | ||
|
|
06fffc2042 | ||
|
|
5ecc87bf3e | ||
|
|
7082c3e449 | ||
|
|
39ce412b25 | ||
|
|
00c7cf3d68 | ||
|
|
a916dd6632 | ||
|
|
eb73dbe24e | ||
|
|
bcc9fcf1c7 | ||
|
|
3e937eac2b | ||
|
|
0d05051f3c | ||
|
|
54471963e0 | ||
|
|
1b8f7e7a36 | ||
|
|
46500b3e36 | ||
|
|
ed40f382e8 | ||
|
|
8d61a4e5f9 | ||
|
|
55332afb29 | ||
|
|
d014fc7153 | ||
|
|
29496ede07 | ||
|
|
f4508a6765 | ||
|
|
53e32a47e4 | ||
|
|
41742b3fe3 | ||
|
|
5be47faff7 | ||
|
|
ea460d6d3e | ||
|
|
edb749f283 |
@@ -0,0 +1,47 @@
|
||||
environment:
|
||||
ANDROID_HOME: "C:\\android-sdk-windows"
|
||||
ANDROID_NDK: "C:\\android-sdk-windows\\android-ndk-r17c"
|
||||
ANDROID_BUILD_VERSION: 28
|
||||
ANDROID_TOOLS_VERSION: 28.0.3
|
||||
|
||||
GRADLE_OPTS: -Dorg.gradle.daemon=false
|
||||
|
||||
SDK_TOOLS_URL: https://dl.google.com/android/repository/sdk-tools-windows-3859397.zip
|
||||
NDK_TOOLS_URL: https://dl.google.com/android/repository/android-ndk-r17c-windows-x86_64.zip
|
||||
|
||||
matrix:
|
||||
- nodejs_version: 8
|
||||
- nodejs_version: 10
|
||||
|
||||
install:
|
||||
# Install Android SDK Tools
|
||||
- mkdir "%ANDROID_HOME%"
|
||||
- appveyor DownloadFile "%SDK_TOOLS_URL%" -FileName "%TMP%/sdk-tools.zip"
|
||||
- 7z x "%TMP%/sdk-tools.zip" -o"%ANDROID_HOME%" > nul
|
||||
- set PATH=%PATH%;"%ANDROID_HOME%\tools\bin"
|
||||
|
||||
- yes 2> nul | sdkmanager --licenses > nul
|
||||
- yes 2> nul | sdkmanager "system-images;android-19;google_apis;armeabi-v7a"
|
||||
- yes 2> nul | sdkmanager "platforms;android-%ANDROID_BUILD_VERSION%"
|
||||
- yes 2> nul | sdkmanager "build-tools;%ANDROID_TOOLS_VERSION%"
|
||||
- yes 2> nul | sdkmanager "add-ons;addon-google_apis-google-23"
|
||||
- yes 2> nul | sdkmanager "extras;android;m2repository"
|
||||
|
||||
- appveyor DownloadFile "%NDK_TOOLS_URL%" -FileName "%TMP%/ndk.zip"
|
||||
- 7z x "%TMP%/ndk.zip" -o"%ANDROID_HOME%" > nul
|
||||
|
||||
- ps: Install-Product node $env:nodejs_version x64
|
||||
- npx envinfo@latest
|
||||
- appveyor-retry yarn install
|
||||
|
||||
build_script:
|
||||
- yarn run flow-check-android
|
||||
- yarn run flow-check-ios
|
||||
- yarn run test
|
||||
- gradlew.bat RNTester:android:app:assembleRelease
|
||||
|
||||
cache:
|
||||
- node_modules
|
||||
- "%LOCALAPPDATA%/Yarn"
|
||||
- "%USERPROFILE%/.gradle/caches"
|
||||
- "%USERPROFILE%/.gradle/wrapper"
|
||||
+3
-4
@@ -1,14 +1,13 @@
|
||||
|
||||
[android]
|
||||
target = android-29
|
||||
target = android-28
|
||||
|
||||
[download]
|
||||
max_number_of_retries = 3
|
||||
|
||||
[maven_repositories]
|
||||
central = https://repo1.maven.org/maven2
|
||||
google = https://maven.google.com/
|
||||
jcenter = https://jcenter.bintray.com/
|
||||
google = https://dl.google.com/dl/android/maven2/
|
||||
|
||||
[alias]
|
||||
rntester = //packages/rn-tester/android/app:app
|
||||
rntester = //RNTester/android/app:app
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# and build a Android application that can be used to run the
|
||||
# tests specified in the scripts/ directory.
|
||||
#
|
||||
FROM reactnativecommunity/react-native-android:2.1
|
||||
FROM reactnativecommunity/react-native-android
|
||||
|
||||
LABEL Description="React Native Android Test Image"
|
||||
LABEL maintainer="Héctor Ramos <hector@fb.com>"
|
||||
@@ -25,13 +25,11 @@ ENV JAVA_TOOL_OPTIONS="-Dfile.encoding=UTF8"
|
||||
|
||||
ADD .buckconfig /app/.buckconfig
|
||||
ADD .buckjavaargs /app/.buckjavaargs
|
||||
ADD Libraries /app/Libraries
|
||||
ADD tools /app/tools
|
||||
ADD ReactAndroid /app/ReactAndroid
|
||||
ADD ReactCommon /app/ReactCommon
|
||||
ADD React /app/React
|
||||
ADD keystores /app/keystores
|
||||
ADD packages/react-native-codegen /app/packages/react-native-codegen
|
||||
ADD tools /app/tools
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -51,3 +49,4 @@ RUN yarn
|
||||
RUN ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog
|
||||
|
||||
RUN ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=1
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) Facebook, Inc. and its affiliates.
|
||||
#
|
||||
# This source code is licensed under the MIT license found in the
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
#
|
||||
|
||||
# for buck gen
|
||||
mount -o remount,exec /dev/shm
|
||||
@@ -10,7 +12,7 @@ mount -o remount,exec /dev/shm
|
||||
AVD_UUID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1)
|
||||
|
||||
# create virtual device
|
||||
echo no | android create avd -n "$AVD_UUID" -f -t android-21 --abi default/armeabi-v7a
|
||||
echo no | android create avd -n "$AVD_UUID" -f -t android-19 --abi default/armeabi-v7a
|
||||
|
||||
# emulator setup
|
||||
emulator64-arm -avd $AVD_UUID -no-skin -no-audio -no-window -no-boot-anim &
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) Facebook, Inc. and its affiliates.
|
||||
#
|
||||
# This source code is licensed under the MIT license found in the
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
#
|
||||
|
||||
# set default environment variables
|
||||
UNIT_TESTS_BUILD_THREADS="${UNIT_TESTS_BUILD_THREADS:-1}"
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) Facebook, Inc. and its affiliates.
|
||||
#
|
||||
# This source code is licensed under the MIT license found in the
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
#
|
||||
|
||||
set -ex
|
||||
|
||||
@@ -67,6 +69,11 @@ while :; do
|
||||
shift
|
||||
;;
|
||||
|
||||
--tvos)
|
||||
RUN_IOS=1
|
||||
shift
|
||||
;;
|
||||
|
||||
*)
|
||||
break
|
||||
esac
|
||||
@@ -109,7 +116,7 @@ function e2e_suite() {
|
||||
|
||||
# create virtual device
|
||||
if ! android list avd | grep "$AVD_UUID" > /dev/null; then
|
||||
echo no | android create avd -n "$AVD_UUID" -f -t android-21 --abi default/armeabi-v7a
|
||||
echo no | android create avd -n "$AVD_UUID" -f -t android-19 --abi default/armeabi-v7a
|
||||
fi
|
||||
|
||||
# newline at end of adb devices call and first line is headers
|
||||
@@ -194,7 +201,7 @@ function e2e_suite() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "Starting Metro"
|
||||
echo "Starting packager server"
|
||||
npm start >> /dev/null &
|
||||
SERVER_PID=$!
|
||||
sleep 15
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) Facebook, Inc. and its affiliates.
|
||||
#
|
||||
# This source code is licensed under the MIT license found in the
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
#
|
||||
|
||||
# shellcheck disable=SC1117
|
||||
# Python script to run instrumentation tests, copied from https://github.com/circleci/circle-dummy-android
|
||||
|
||||
+514
-668
File diff suppressed because it is too large
Load Diff
+1
-5
@@ -1,4 +1,4 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
# EditorConfig is awesome: http://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
@@ -15,7 +15,3 @@ indent_size = 4
|
||||
|
||||
[BUCK]
|
||||
indent_size = 4
|
||||
|
||||
# Windows files
|
||||
[*.bat]
|
||||
end_of_line = crlf
|
||||
|
||||
+8
-7
@@ -1,10 +1,11 @@
|
||||
**/main.js
|
||||
# node_modules ignored by default
|
||||
|
||||
**/staticBundle.js
|
||||
bots/node_modules
|
||||
docs/generatedComponentApiDocs.js
|
||||
flow/
|
||||
Libraries/Renderer/*
|
||||
**/main.js
|
||||
Libraries/vendor/**/*
|
||||
node_modules/
|
||||
Libraries/Renderer/*
|
||||
packages/*/node_modules
|
||||
packages/react-native-codegen/lib
|
||||
pr-inactivity-bookmarklet.js
|
||||
question-bookmarklet.js
|
||||
flow/
|
||||
bots/node_modules
|
||||
@@ -5,29 +5,14 @@
|
||||
"./packages/eslint-config-react-native-community/index.js"
|
||||
],
|
||||
|
||||
"plugins": [
|
||||
"@react-native/eslint-plugin-codegen"
|
||||
],
|
||||
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"Libraries/**/*.js",
|
||||
],
|
||||
"rules": {
|
||||
"@react-native-community/no-haste-imports": 2,
|
||||
"@react-native-community/error-subclass-name": 2,
|
||||
"@react-native-community/platform-colors": 2,
|
||||
"@react-native/codegen/react-native-modules": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"**/__fixtures__/**/*.js",
|
||||
"**/__mocks__/**/*.js",
|
||||
"**/__tests__/**/*.js",
|
||||
"jest/**/*.js",
|
||||
"packages/rn-tester/**/*.js",
|
||||
"RNTester/**/*.js",
|
||||
],
|
||||
"globals": {
|
||||
// Expose some Jest globals for test helpers
|
||||
@@ -45,8 +30,8 @@
|
||||
],
|
||||
"env": {
|
||||
"jasmine": true,
|
||||
"jest": true
|
||||
}
|
||||
}
|
||||
]
|
||||
"jest": true,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
+45
-12
@@ -11,43 +11,74 @@
|
||||
; Ignore "BUCK" generated dirs
|
||||
<PROJECT_ROOT>/\.buckd/
|
||||
|
||||
; Ignore unexpected extra "@providesModule"
|
||||
.*/node_modules/.*/node_modules/fbjs/.*
|
||||
|
||||
; Ignore duplicate module providers
|
||||
; For RN Apps installed via npm, "Libraries" folder is inside
|
||||
; "node_modules/react-native" but in the source repo it is in the root
|
||||
.*/Libraries/react-native/React.js
|
||||
|
||||
; Ignore polyfills
|
||||
.*/Libraries/polyfills/.*
|
||||
|
||||
; These should not be required directly
|
||||
; require from fbjs/lib instead: require('fbjs/lib/warning')
|
||||
.*/node_modules/warning/.*
|
||||
|
||||
; Flow doesn't support platforms
|
||||
.*/Libraries/Utilities/LoadingView.js
|
||||
.*/Libraries/Utilities/HMRLoadingView.js
|
||||
|
||||
[untyped]
|
||||
.*/node_modules/@react-native-community/cli/.*/.*
|
||||
|
||||
[include]
|
||||
|
||||
[declarations]
|
||||
.*/node_modules/.*
|
||||
|
||||
[libs]
|
||||
interface.js
|
||||
Libraries/react-native/react-native-interface.js
|
||||
flow/
|
||||
|
||||
[options]
|
||||
emoji=true
|
||||
|
||||
exact_by_default=true
|
||||
esproposal.optional_chaining=enable
|
||||
esproposal.nullish_coalescing=enable
|
||||
|
||||
module.file_ext=.js
|
||||
module.file_ext=.json
|
||||
module.file_ext=.ios.js
|
||||
|
||||
module.system=haste
|
||||
module.system.haste.use_name_reducers=true
|
||||
# keep the following in sync with server/haste/hasteImpl.js
|
||||
# get basename
|
||||
module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1'
|
||||
# strip .js or .js.flow suffix
|
||||
module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1'
|
||||
# strip .ios suffix
|
||||
module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1'
|
||||
module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
|
||||
module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
|
||||
module.system.haste.paths.blacklist=.*/__tests__/.*
|
||||
module.system.haste.paths.blacklist=.*/__mocks__/.*
|
||||
module.system.haste.paths.whitelist=<PROJECT_ROOT>/Libraries/.*
|
||||
module.system.haste.paths.whitelist=<PROJECT_ROOT>/RNTester/.*
|
||||
module.system.haste.paths.whitelist=<PROJECT_ROOT>/IntegrationTests/.*
|
||||
module.system.haste.paths.blacklist=<PROJECT_ROOT>/Libraries/react-native/react-native-implementation.js
|
||||
module.system.haste.paths.blacklist=<PROJECT_ROOT>/Libraries/Animated/src/polyfills/.*
|
||||
|
||||
munge_underscores=true
|
||||
|
||||
module.name_mapper='^react-native$' -> '<PROJECT_ROOT>/index.js'
|
||||
module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/\1'
|
||||
module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/Libraries/Image/RelativeImageStub'
|
||||
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
|
||||
|
||||
suppress_type=$FlowIssue
|
||||
suppress_type=$FlowFixMe
|
||||
suppress_type=$FlowFixMeProps
|
||||
suppress_type=$FlowFixMeState
|
||||
suppress_type=$FlowFixMeEmpty
|
||||
|
||||
experimental.abstract_locations=true
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
|
||||
|
||||
[lints]
|
||||
sketchy-null-number=warn
|
||||
@@ -57,8 +88,10 @@ untyped-type-import=warn
|
||||
nonstrict-import=warn
|
||||
deprecated-type=warn
|
||||
unsafe-getters-setters=warn
|
||||
inexact-spread=warn
|
||||
unnecessary-invariant=warn
|
||||
signature-verification-failure=warn
|
||||
deprecated-utility=error
|
||||
|
||||
[strict]
|
||||
deprecated-type
|
||||
@@ -70,4 +103,4 @@ untyped-import
|
||||
untyped-type-import
|
||||
|
||||
[version]
|
||||
^0.137.0
|
||||
^0.98.0
|
||||
|
||||
+45
-12
@@ -11,43 +11,74 @@
|
||||
; Ignore "BUCK" generated dirs
|
||||
<PROJECT_ROOT>/\.buckd/
|
||||
|
||||
; Ignore unexpected extra "@providesModule"
|
||||
.*/node_modules/.*/node_modules/fbjs/.*
|
||||
|
||||
; Ignore duplicate module providers
|
||||
; For RN Apps installed via npm, "Libraries" folder is inside
|
||||
; "node_modules/react-native" but in the source repo it is in the root
|
||||
.*/Libraries/react-native/React.js
|
||||
|
||||
; Ignore polyfills
|
||||
.*/Libraries/polyfills/.*
|
||||
|
||||
; These should not be required directly
|
||||
; require from fbjs/lib instead: require('fbjs/lib/warning')
|
||||
.*/node_modules/warning/.*
|
||||
|
||||
; Flow doesn't support platforms
|
||||
.*/Libraries/Utilities/LoadingView.js
|
||||
.*/Libraries/Utilities/HMRLoadingView.js
|
||||
|
||||
[untyped]
|
||||
.*/node_modules/@react-native-community/cli/.*/.*
|
||||
|
||||
[include]
|
||||
|
||||
[declarations]
|
||||
.*/node_modules/.*
|
||||
|
||||
[libs]
|
||||
interface.js
|
||||
Libraries/react-native/react-native-interface.js
|
||||
flow/
|
||||
|
||||
[options]
|
||||
emoji=true
|
||||
|
||||
exact_by_default=true
|
||||
esproposal.optional_chaining=enable
|
||||
esproposal.nullish_coalescing=enable
|
||||
|
||||
module.file_ext=.js
|
||||
module.file_ext=.json
|
||||
module.file_ext=.android.js
|
||||
|
||||
module.system=haste
|
||||
module.system.haste.use_name_reducers=true
|
||||
# keep the following in sync with server/haste/hasteImpl.js
|
||||
# get basename
|
||||
module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1'
|
||||
# strip .js or .js.flow suffix
|
||||
module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1'
|
||||
# strip .android suffix
|
||||
module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
|
||||
module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1'
|
||||
module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
|
||||
module.system.haste.paths.blacklist=.*/__tests__/.*
|
||||
module.system.haste.paths.blacklist=.*/__mocks__/.*
|
||||
module.system.haste.paths.whitelist=<PROJECT_ROOT>/Libraries/.*
|
||||
module.system.haste.paths.whitelist=<PROJECT_ROOT>/RNTester/.*
|
||||
module.system.haste.paths.whitelist=<PROJECT_ROOT>/IntegrationTests/.*
|
||||
module.system.haste.paths.blacklist=<PROJECT_ROOT>/Libraries/react-native/react-native-implementation.js
|
||||
module.system.haste.paths.blacklist=<PROJECT_ROOT>/Libraries/Animated/src/polyfills/.*
|
||||
|
||||
munge_underscores=true
|
||||
|
||||
module.name_mapper='^react-native$' -> '<PROJECT_ROOT>/index.js'
|
||||
module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/\1'
|
||||
module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/Libraries/Image/RelativeImageStub'
|
||||
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
|
||||
|
||||
suppress_type=$FlowIssue
|
||||
suppress_type=$FlowFixMe
|
||||
suppress_type=$FlowFixMeProps
|
||||
suppress_type=$FlowFixMeState
|
||||
suppress_type=$FlowFixMeEmpty
|
||||
|
||||
experimental.abstract_locations=true
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_android\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_android\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
|
||||
|
||||
[lints]
|
||||
sketchy-null-number=warn
|
||||
@@ -57,8 +88,10 @@ untyped-type-import=warn
|
||||
nonstrict-import=warn
|
||||
deprecated-type=warn
|
||||
unsafe-getters-setters=warn
|
||||
inexact-spread=warn
|
||||
unnecessary-invariant=warn
|
||||
signature-verification-failure=warn
|
||||
deprecated-utility=error
|
||||
|
||||
[strict]
|
||||
deprecated-type
|
||||
@@ -70,4 +103,4 @@ untyped-import
|
||||
untyped-type-import
|
||||
|
||||
[version]
|
||||
^0.137.0
|
||||
^0.98.0
|
||||
|
||||
+6
-3
@@ -1,3 +1,6 @@
|
||||
# Windows files should use crlf line endings
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
*.bat text eol=crlf
|
||||
# Force LF line endings for Bash scripts. On Windows the rest of the source
|
||||
# files will typically have CR+LF endings (Git default on Windows), but Bash
|
||||
# scripts need to have LF endings to work (under Cygwin), thus override to force
|
||||
# that.
|
||||
gradlew text eol=lf
|
||||
*.sh text eol=lf
|
||||
|
||||
+1
-4
@@ -29,12 +29,9 @@ Libraries/NativeAnimation/* @janicduplessis
|
||||
Libraries/Image/* @shergin
|
||||
Libraries/Text/* @shergin
|
||||
|
||||
# Modifications to package.json typically require
|
||||
# Modifications to package.json typically require
|
||||
# additional effort from a Facebook employee to land
|
||||
/package.json @hramos @cpojer
|
||||
|
||||
# These should not be modified through a GitHub PR
|
||||
LICENSE* @hramos @cpojer @yungsters
|
||||
|
||||
# The eslint-config-react-native-community package requires manual publishing after merging
|
||||
/packages/eslint-config-react-native-community/* @matt-oakes
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
✋ To keep the backlog clean and actionable, issues will be
|
||||
🚫 closed if they do not follow one of the issue templates:
|
||||
👉 https://github.com/facebook/react-native/issues/new/choose
|
||||
👉 Please follow one of these issue templates:
|
||||
- https://github.com/facebook/react-native/issues/new/choose
|
||||
|
||||
Note: to keep the backlog clean and actionable, issues may be immediately closed if they do not follow one of the above issue templates.
|
||||
|
||||
@@ -2,29 +2,39 @@
|
||||
name: "🐛 Bug Report"
|
||||
about: Report a reproducible bug or regression in React Native.
|
||||
title: ''
|
||||
labels: 'Needs: Triage :mag:'
|
||||
labels: 'Bug'
|
||||
|
||||
---
|
||||
|
||||
Please provide all the information requested. Issues that do not follow this format are likely to stall.
|
||||
<!--
|
||||
Please provide a clear and concise description of what the bug is.
|
||||
Include screenshots if needed.
|
||||
Please test using the latest React Native release to make sure your issue has not already been fixed: http://facebook.github.io/react-native/docs/upgrading.html
|
||||
-->
|
||||
|
||||
## Description
|
||||
Please provide a clear and concise description of what the bug is. Include screenshots if needed.
|
||||
Please test using the latest React Native release to make sure your issue has not already been fixed: https://reactnative.dev/docs/upgrading.html
|
||||
|
||||
## React Native version:
|
||||
Run `react-native info` in your terminal and copy the results here.
|
||||
React Native version:
|
||||
<!--
|
||||
Run `react-native info` in your terminal and copy the results here.
|
||||
-->
|
||||
|
||||
## Steps To Reproduce
|
||||
Provide a detailed list of steps that reproduce the issue.
|
||||
|
||||
1.
|
||||
2.
|
||||
|
||||
## Expected Results
|
||||
Describe what you expected to happen.
|
||||
<!--
|
||||
Issues without reproduction steps or code are likely to stall.
|
||||
-->
|
||||
|
||||
Describe what you expected to happen:
|
||||
|
||||
|
||||
Snack, code example, or link to a repository:
|
||||
|
||||
|
||||
<!--
|
||||
Please provide a Snack (https://snack.expo.io/), a link to a repository on GitHub, or
|
||||
provide a minimal code example that reproduces the problem.
|
||||
Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve.
|
||||
-->
|
||||
|
||||
## Snack, code example, screenshot, or link to a repository:
|
||||
Please provide a Snack (https://snack.expo.io/), a link to a repository on GitHub, or provide a minimal code example that reproduces the problem.
|
||||
You may provide a screenshot of the application if you think it is relevant to your bug report.
|
||||
Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: 📃 Documentation Issue
|
||||
url: https://github.com/facebook/react-native-website/issues
|
||||
about: Please report documentation issues in the React Native website repository.
|
||||
- name: ⤴️ Upgrade Issue
|
||||
url: https://github.com/react-native-community/upgrade-support
|
||||
about: Need help upgrading to a newer React Native version? Visit the Upgrade Support repository.
|
||||
- name: 🤔 Questions and Help
|
||||
url: https://reactnative.dev/help
|
||||
about: Looking for help with your app? Please refer to the React Native community's support resources.
|
||||
- name: 🚀 Discussions and Proposals
|
||||
url: https://github.com/react-native-community/discussions-and-proposals
|
||||
about: Discuss the future of React Native in the React Native community's discussions and proposals repository.
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: "📃 Documentation Issue"
|
||||
about: Documentation issues are handled in https://github.com/facebook/react-native-website.
|
||||
title: 'Docs:'
|
||||
labels: 'Type: Docs'
|
||||
|
||||
---
|
||||
|
||||
🚨 Please do not open a documentation issue in the core React Native repository. 🚨
|
||||
|
||||
The React Native website is hosted on a separate repository. You may let the
|
||||
team know about any issues with the documentation by opening an issue there:
|
||||
- https://github.com/facebook/react-native-website
|
||||
- https://github.com/facebook/react-native-website/issues
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
name: "🤔 Questions and Help"
|
||||
about: The issue tracker is not for questions. Please ask questions on https://stackoverflow.com/questions/tagged/react-native.
|
||||
title: 'Question: '
|
||||
labels: 'Type: Question'
|
||||
|
||||
---
|
||||
|
||||
🚨 The issue tracker is not for questions. 🚨
|
||||
|
||||
As it happens, support requests that are created as issues are likely to be closed. We want to make sure you are able to find the help you seek. Please take a look at the following resources.
|
||||
|
||||
## Coding Questions
|
||||
|
||||
### https://stackoverflow.com/questions/tagged/react-native
|
||||
|
||||
If you have a coding question related to React Native, it might be better suited for Stack Overflow. It's a great place to browse through frequent questions about using React Native, as well as ask for help with specific questions.
|
||||
|
||||
|
||||
## Talk to other React Native developers
|
||||
|
||||
### https://www.reactiflux.com/
|
||||
|
||||
Reactiflux is an active community of React and React Native developers. If you are looking for immediate assistance or have a general question about React Native, the #react-native channel is a good place to start.
|
||||
|
||||
If you want to participate in casual discussions about the use of React Native, consider participating in one of the following forums:
|
||||
- Discord Community: https://discord.gg/0ZcbPKXt5bZjGY5n
|
||||
- Spectrum Chat: https://spectrum.chat/react-native
|
||||
- Facebook Group: https://www.facebook.com/groups/react.native.community
|
||||
|
||||
If you'd like to discuss topics related to the future of React Native, or would like to propose a new feature or change before sending a pull request, please check out the discussions and proposals repo:
|
||||
- https://github.com/react-native-community/discussions-and-proposals
|
||||
|
||||
> For a full list of community resources, check out React Native's Community page at https://facebook.github.io/react-native/help.
|
||||
@@ -6,12 +6,10 @@
|
||||
|
||||
## Changelog
|
||||
|
||||
<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
|
||||
https://github.com/facebook/react-native/wiki/Changelog
|
||||
-->
|
||||
<!-- Help reviewers and the release process by writing your own changelog entry. See https://github.com/facebook/react-native/wiki/Changelog for an example. -->
|
||||
|
||||
[CATEGORY] [TYPE] - Message
|
||||
|
||||
## Test Plan
|
||||
|
||||
<!-- Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes the user interface. -->
|
||||
<!-- Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes UI. -->
|
||||
|
||||
+1
-1
@@ -32,4 +32,4 @@ If you want to participate in casual discussions about the use of React Native,
|
||||
- [React Native Community Facebook Group](https://www.facebook.com/groups/react.native.community)
|
||||
|
||||
|
||||
> For a full list of community resources, check out [React Native's Community page](https://reactnative.dev/help).
|
||||
> For a full list of community resources, check out [React Native's Community page](https://facebook.github.io/react-native/help).
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
# Configuration for Label Actions - https://github.com/marketplace/actions/label-actions
|
||||
|
||||
"Type: Invalid":
|
||||
close: true
|
||||
"Type: Question":
|
||||
comment: >
|
||||
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/).
|
||||
close: true
|
||||
"Type: Docs":
|
||||
comment: >
|
||||
Please report documentation issues in the [`react-native-website`](https://github.com/facebook/react-native-website/issues) repository.
|
||||
close: true
|
||||
"Type: Upgrade Issue":
|
||||
comment: >
|
||||
Do you need help upgrading to a newer React Native version? Visit the [Upgrade Support repository](https://github.com/react-native-community/upgrade-support) or use the [upgrade helper](https://react-native-community.github.io/upgrade-helper/) to see the changes that need to be made to upgrade your app.
|
||||
close: true
|
||||
"Resolution: For Stack Overflow":
|
||||
comment: >
|
||||
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.
|
||||
close: true
|
||||
"Needs: Issue Template":
|
||||
comment: >
|
||||
<table><tbody><tr><th width="50">:warning:</th><th width="100%">
|
||||
Missing Required Fields
|
||||
</th></tr><tr><td>:information_source:</td><td>
|
||||
It looks like your issue may be missing some necessary information. GitHub provides an example template whenever a <a href="https://github.com/facebook/react-native/issues/new?template=bug_report.md">new issue is created</a>. 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.
|
||||
</td></tr></tbody></table>
|
||||
labels:
|
||||
- "Needs: Author Feedback"
|
||||
"Needs: Environment Info":
|
||||
comment: >
|
||||
<table><tbody><tr><th width="50">:warning:</th><th width="100%">
|
||||
Missing Environment Information
|
||||
</th></tr><tr><td>:information_source:</td><td>
|
||||
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.
|
||||
</td></tr></tbody></table>
|
||||
labels:
|
||||
- "Needs: Author Feedback"
|
||||
"Needs: Verify on Latest Version":
|
||||
comment: >
|
||||
<table><tbody><tr><th width="50">:warning:</th><th width="100%">
|
||||
Using Old Version
|
||||
</th></tr><tr><td>:information_source:</td><td>
|
||||
It looks like you are using an older version of React Native. Please <a href="https://reactnative.dev/docs/upgrading">upgrade</a> to the latest version, and verify if the issue persists. If it does not, 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 current release.
|
||||
</td></tr></tbody></table>
|
||||
labels:
|
||||
- "Needs: Author Feedback"
|
||||
"Needs: Repro":
|
||||
comment: >
|
||||
<table><tbody><tr><th width="50">:warning:</th><th width="100%">
|
||||
Missing Reproducible Example
|
||||
</th></tr><tr><td>:information_source:</td><td>
|
||||
It looks like your issue is missing a reproducible example. Please provide a <a href="https://snack.expo.io">Snack</a> or a repository that demonstrates the issue you are reporting in a <a href="https://stackoverflow.com/help/minimal-reproducible-example">minimal, complete, and reproducible</a> manner.
|
||||
</td></tr></tbody></table>
|
||||
labels:
|
||||
- "Needs: Author Feedback"
|
||||
@@ -1,21 +0,0 @@
|
||||
name: Issue Needs Attention
|
||||
# This workflow is triggered on issue comments.
|
||||
on:
|
||||
issue_comment:
|
||||
types: created
|
||||
|
||||
jobs:
|
||||
applyNeedsAttentionLabel:
|
||||
name: Apply Needs Attention Label
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Apply Needs Attention Label
|
||||
uses: hramos/needs-attention@v1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
response-required-label: "Needs: Author Feedback"
|
||||
needs-attention-label: "Needs: Attention"
|
||||
id: needs-attention
|
||||
- name: Result
|
||||
run: echo '${{ steps.needs-attention.outputs.result }}'
|
||||
@@ -1,16 +0,0 @@
|
||||
name: Label Actions
|
||||
# This workflow is triggered when a label is added to an issue.
|
||||
on:
|
||||
issues:
|
||||
types: labeled
|
||||
|
||||
jobs:
|
||||
processLabelAction:
|
||||
name: Process Label Action
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Process Label Action
|
||||
uses: hramos/label-actions@v1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
+7
-43
@@ -23,31 +23,19 @@ project.xcworkspace
|
||||
|
||||
# Gradle
|
||||
/build/
|
||||
/packages/react-native-codegen/android/build/
|
||||
/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/build
|
||||
/packages/rn-tester/android/app/.cxx/
|
||||
/packages/rn-tester/android/app/build/
|
||||
/packages/rn-tester/android/app/gradle/
|
||||
/packages/rn-tester/android/app/gradlew
|
||||
/packages/rn-tester/android/app/gradlew.bat
|
||||
/RNTester/android/app/build/
|
||||
/RNTester/android/app/gradle/
|
||||
/RNTester/android/app/gradlew
|
||||
/RNTester/android/app/gradlew.bat
|
||||
/ReactAndroid/build/
|
||||
/ReactAndroid/gradle/
|
||||
/ReactAndroid/gradlew
|
||||
/ReactAndroid/gradlew.bat
|
||||
|
||||
# Buck
|
||||
.buckd
|
||||
buck-out
|
||||
/.lsp.buckd
|
||||
/.lsp-buck-out
|
||||
/ReactAndroid/src/main/jni/prebuilt/lib/
|
||||
/ReactAndroid/src/main/jni/prebuilt/lib/armeabi-v7a/
|
||||
/ReactAndroid/src/main/jni/prebuilt/lib/x86/
|
||||
/ReactAndroid/src/main/gen
|
||||
|
||||
# Android Studio
|
||||
.project
|
||||
.settings
|
||||
.classpath
|
||||
|
||||
# Watchman
|
||||
.watchmanconfig
|
||||
|
||||
@@ -80,32 +68,8 @@ package-lock.json
|
||||
|
||||
# ReactCommon subdir shouldn't have Xcode project
|
||||
/ReactCommon/**/*.xcodeproj
|
||||
/packages/rn-tester/build
|
||||
/packages/rn-tester/android/app/build/*
|
||||
|
||||
# Libs that shouldn't have Xcode project
|
||||
/Libraries/FBLazyVector/**/*.xcodeproj
|
||||
/Libraries/RCTRequired/**/*.xcodeproj
|
||||
/React/CoreModules/**/*.xcodeproj
|
||||
/React/FBReactNativeSpec/**/*.xcodeproj
|
||||
/packages/react-native-codegen/**/*.xcodeproj
|
||||
RNTester/build
|
||||
|
||||
# CocoaPods
|
||||
/template/ios/Pods/
|
||||
/template/ios/Podfile.lock
|
||||
/packages/rn-tester/Gemfile.lock
|
||||
|
||||
# Ignore RNTester specific Pods, but keep the __offline_mirrors__ here.
|
||||
/packages/rn-tester/Pods/*
|
||||
!/packages/rn-tester/Pods/__offline_mirrors__
|
||||
|
||||
# react-native-codegen
|
||||
/packages/react-native-codegen/lib
|
||||
/ReactCommon/react/renderer/components/rncore/
|
||||
|
||||
# Visual studio
|
||||
.vscode
|
||||
.vs
|
||||
|
||||
# Android memory profiler files
|
||||
*.hprof
|
||||
|
||||
+1
-2
@@ -3,6 +3,5 @@
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": false,
|
||||
"jsxBracketSameLine": true,
|
||||
"arrowParens": "avoid"
|
||||
"jsxBracketSameLine": true
|
||||
}
|
||||
|
||||
+3
-75
@@ -1,77 +1,5 @@
|
||||
# Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to make participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all project spaces, and it also applies when
|
||||
an individual is representing the project or its community in public spaces.
|
||||
Examples of representing a project or community include using an official
|
||||
project e-mail address, posting via an official social media account, or acting
|
||||
as an appointed representative at an online or offline event. Representation of
|
||||
a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at <opensource-conduct@fb.com>. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
|
||||
Facebook has adopted a Code of Conduct that we expect project participants to adhere to.
|
||||
Please read the [full text](https://code.fb.com/codeofconduct/)
|
||||
so that you can understand what actions will and will not be tolerated.
|
||||
|
||||
+15
-19
@@ -8,9 +8,9 @@ The [Open Source Guides](https://opensource.guide/) website has a collection of
|
||||
* [Building Welcoming Communities](https://opensource.guide/building-community/)
|
||||
|
||||
|
||||
### [Code of Conduct](https://github.com/facebook/react/blob/master/CODE_OF_CONDUCT.md)
|
||||
### [Code of Conduct](https://code.fb.com/codeofconduct/)
|
||||
|
||||
As a reminder, all contributors are expected to adhere to the [Code of Conduct](https://github.com/facebook/react/blob/master/CODE_OF_CONDUCT.md).
|
||||
As a reminder, all contributors are expected to adhere to the [Code of Conduct](https://code.facebook.com/codeofconduct).
|
||||
|
||||
## Ways to Contribute
|
||||
|
||||
@@ -18,7 +18,7 @@ If you are eager to start contributing code right away, we have a list of [good
|
||||
|
||||
There are other ways you can contribute without writing a single line of code. Here are a few things you can do to help out:
|
||||
|
||||
1. **Replying and handling open issues.** We get a lot of issues every day, and some of them may lack necessary information. You can help out by guiding people through the process of filling out the issue template, asking for clarifying information, or pointing them to existing issues that match their description of the problem. We cover more about this process in the [Issue Triage wiki](https://github.com/facebook/react-native/wiki/Issues#triage).
|
||||
1. **Replying and handling open issues.** We get a lot of issues every day, and some of them may lack necessary information. You can help out by guiding people through the process of filling out the issue template, asking for clarifying information, or pointing them to existing issues that match their description of the problem. We'll cover more about this process later, in [Handling Issues](http://github.com/facebook/react-native/wiki/Handling-Issues).
|
||||
2. **Reviewing pull requests for the docs.** Reviewing [documentation updates](https://github.com/facebook/react-native-website/pulls) can be as simple as checking for spelling and grammar. If you encounter situations that can be explained better in the docs, click **Edit** at the top of most docs pages to get started with your own contribution.
|
||||
3. **Help people write test plans.** Some pull requests sent to the main repository may lack a proper test plan. These help reviewers understand how the change was tested, and can speed up the time it takes for a contribution to be accepted.
|
||||
|
||||
@@ -30,7 +30,6 @@ We use GitHub issues and pull requests to keep track of bug reports and contribu
|
||||
|
||||
You can learn more about the contribution process in the following documents:
|
||||
|
||||
* [Issues](https://github.com/facebook/react-native/wiki/Issues)
|
||||
* [Pull Requests](https://github.com/facebook/react-native/wiki/Pull-Requests)
|
||||
|
||||
We also have a thriving community of contributors who would be happy to help you get set up. You can reach out to us through [@ReactNative](http://twitter.com/reactnative) (the React Native team) and [@ReactNativeComm](http://twitter.com/reactnativecomm) (the React Native Community organization).
|
||||
@@ -48,9 +47,9 @@ There are a few other repositories you might want to familiarize yourself with:
|
||||
|
||||
Browsing through these repositories should provide some insight into how the React Native open source project is managed.
|
||||
|
||||
## GitHub Issues
|
||||
## Handling Issues
|
||||
|
||||
We use GitHub issues to track bugs exclusively. We have documented our issue handling processes in the [Issues wiki](https://github.com/facebook/react-native/wiki/Issues).
|
||||
We use GitHub issues to track bugs exclusively. You can report an issue by filing a [Bug Report](https://github.com/facebook/react-native/issues/new/choose). Watch this space for more details on how to get involved and triage issues.
|
||||
|
||||
### Security Bugs
|
||||
|
||||
@@ -58,7 +57,7 @@ Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe
|
||||
|
||||
## Helping with Documentation
|
||||
|
||||
The React Native documentation is hosted as part of the React Native website repository at https://github.com/facebook/react-native-website. The website itself is located at <https://reactnative.dev/> and it is built using [Docusaurus](https://docusaurus.io/). If there's anything you'd like to change in the docs, you can get started by clicking on the "Edit" button located on the upper right of most pages in the website.
|
||||
The React Native documentation is hosted as part of the React Native website repository at https://github.com/facebook/react-native-website. The website itself is located at <https://facebook.github.io/react-native> and it is built using [Docusaurus](https://docusaurus.io/). If there's anything you'd like to change in the docs, you can get started by clicking on the "Edit" button located on the upper right of most pages in the website.
|
||||
|
||||
If you are adding new functionality or introducing a change in behavior, we will ask you to update the documentation to reflect your changes.
|
||||
|
||||
@@ -72,21 +71,18 @@ We recommend referring to the [CONTRIBUTING](https://github.com/facebook/react-n
|
||||
|
||||
## Contributing Code
|
||||
|
||||
Code-level contributions to React Native generally come in the form of [pull requests](https://help.github.com/en/articles/about-pull-requests). These are done by forking the repo and making changes locally. Directly in the repo, there is the [`rn-tester` app](/packages/rn-tester) that you can install on your device (or simulators) and use to test the changes you're making to React Native sources.
|
||||
|
||||
The process of proposing a change to React Native can be summarized as follows:
|
||||
Code-level contributions to React Native generally come in the form of [pull requests](https://help.github.com/en/articles/about-pull-requests). The process of proposing a change to React Native can be summarized as follows:
|
||||
|
||||
1. Fork the React Native repository and create your branch from `master`.
|
||||
2. Make the desired changes to React Native sources. Use the `packages/rn-tester` app to test them out.
|
||||
3. If you've added code that should be tested, add tests.
|
||||
4. If you've changed APIs, update the documentation, which lives in [another repo](https://github.com/facebook/react-native-website/).
|
||||
5. Ensure the test suite passes, either locally or on CI once you opened a pull request.
|
||||
6. Make sure your code lints (for example via `yarn lint --fix`).
|
||||
7. Push the changes to your fork.
|
||||
8. Create a pull request to the React Native repository.
|
||||
9. Review and address comments on your pull request.
|
||||
2. If you've added code that should be tested, add tests.
|
||||
3. If you've changed APIs, update the documentation.
|
||||
4. Ensure the test suite passes, either locally or on CI once you opened a pull request.
|
||||
5. Make sure your code lints (for example via `yarn lint --fix`).
|
||||
6. Push the changes to your fork.
|
||||
7. Create a pull request to the React Native repository.
|
||||
8. Review and address comments on your pull request.
|
||||
1. A bot may comment with suggestions. Generally we ask you to resolve these first before a maintainer will review your code.
|
||||
10. If you haven't already, please complete the [Contributor License Agreement](https://github.com/facebook/react-native/wiki/Contributor-License-Agreement) ("CLA"). **[Complete your CLA here.](https://code.facebook.com/cla)**
|
||||
9. If you haven't already, complete the Contributor License Agreement ("CLA").
|
||||
|
||||
If all goes well, your pull request will be merged. If it is not merged, maintainers will do their best to explain the reason why.
|
||||
|
||||
|
||||
+4
-5
@@ -10,15 +10,14 @@ There are three types of stakeholders:
|
||||
|
||||
## Partners
|
||||
|
||||
Partners are companies that are significantly invested in React Native and have been for years. Informed by their use of React Native, they push for improvements of the core and/or the ecosystem around it. Partners think of React Native as a product: they understand the trade offs that the project makes as well as future plans and goals. Together we shape the vision for React Native to make it the best way to build applications.
|
||||
Partners are companies that are significantly invested in React Native and have been for years. Informed by their use of React Native, they push for improvements of the core and/or the ecosystem around it. Facebook's partners think of React Native as a product: they understand the trade offs that the project makes as well as future plans and goals. Together we shape the vision for React Native to make it the best way to build applications.
|
||||
|
||||
React Native's current set of partners include Callstack, Expo, Facebook, Infinite Red, Microsoft and Software Mansion. Many engineers from these companies are core contributors, and their partner responsibilities also include:
|
||||
Our current set of partners include Callstack, Expo, Infinite Red, Microsoft and Software Mansion. Many engineers from these companies are core contributors, and their partner responsibilities also include:
|
||||
|
||||
* **[Callstack](https://callstack.com/):** Manages releases, maintains the [React Native CLI](https://github.com/react-native-community/react-native-cli) and organizes [React Native EU](https://react-native.eu/)
|
||||
* **[Expo](https://expo.io/):** Builds [expo](https://github.com/expo/expo) on top of React Native to simplify app development
|
||||
* **[Facebook](https://opensource.facebook.com):** Oversees the React Native product and maintains the [React Native core repo](https://reactnative.dev/)
|
||||
* **[Infinite Red](https://infinite.red/):** Maintains the [ignite cli/boilerplate](https://github.com/infinitered/ignite), organizes [Chain React Conf](https://cr.infinite.red/)
|
||||
* **[Microsoft](http://aka.ms/reactnative):** Develops [React Native Windows](https://github.com/Microsoft/react-native-windows) and [React Native macOS](https://github.com/microsoft/react-native-macos) for building apps that target Windows and macOS
|
||||
* **[Infinite Red](https://infinite.red/):** Maintains the [ignite cli/boilerplate](https://github.com/infinitered/ignite), organizes [Chain React Conf](https://infinite.red/ChainReactConf)
|
||||
* **[Microsoft](https://www.microsoft.com/en-gb/):** Develops [React Native Windows](https://github.com/Microsoft/react-native-windows) for the Universal Windows Platform (UWP)
|
||||
* **[Software Mansion](https://swmansion.com/):** Maintain core infrastructure including JSC, Animated, and other popular third-party plugins.
|
||||
|
||||
In terms of open source work, pull requests from partners are commonly prioritized. When you are contributing to React Native, you'll most likely meet somebody who works at one of the partner companies and who is a core contributor:
|
||||
|
||||
@@ -10,21 +10,15 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import invariant from 'invariant';
|
||||
import NativeAccessibilityManager from 'react-native/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager';
|
||||
import {DeviceEventEmitter, NativeModules, View} from 'react-native';
|
||||
import * as React from 'react';
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const {View} = ReactNative;
|
||||
const RCTDeviceEventEmitter = require('react-native/Libraries/EventEmitter/RCTDeviceEventEmitter');
|
||||
const {TestModule, AccessibilityManager} = ReactNative.NativeModules;
|
||||
|
||||
const {TestModule} = NativeModules;
|
||||
|
||||
class AccessibilityManagerTest extends React.Component<{...}> {
|
||||
class AccessibilityManagerTest extends React.Component<{}> {
|
||||
componentDidMount() {
|
||||
invariant(
|
||||
NativeAccessibilityManager,
|
||||
"NativeAccessibilityManager doesn't exist",
|
||||
);
|
||||
|
||||
NativeAccessibilityManager.setAccessibilityContentSizeMultipliers({
|
||||
AccessibilityManager.setAccessibilityContentSizeMultipliers({
|
||||
extraSmall: 1.0,
|
||||
small: 2.0,
|
||||
medium: 3.0,
|
||||
@@ -38,7 +32,7 @@ class AccessibilityManagerTest extends React.Component<{...}> {
|
||||
accessibilityExtraExtraLarge: 11.0,
|
||||
accessibilityExtraExtraExtraLarge: 12.0,
|
||||
});
|
||||
DeviceEventEmitter.addListener('didUpdateDimensions', update => {
|
||||
RCTDeviceEventEmitter.addListener('didUpdateDimensions', update => {
|
||||
TestModule.markTestPassed(update.window.fontScale === 4.0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,19 +19,14 @@ const deepDiffer = require('react-native/Libraries/Utilities/differ/deepDiffer')
|
||||
|
||||
const TEST_PAYLOAD = {foo: 'bar'};
|
||||
|
||||
type AppEvent = {
|
||||
data: Object,
|
||||
ts: number,
|
||||
...
|
||||
};
|
||||
type AppEvent = {data: Object, ts: number};
|
||||
type State = {
|
||||
sent: 'none' | AppEvent,
|
||||
received: 'none' | AppEvent,
|
||||
elapsed?: string,
|
||||
...
|
||||
};
|
||||
|
||||
class AppEventsTest extends React.Component<{...}, State> {
|
||||
class AppEventsTest extends React.Component<{}, State> {
|
||||
state: State = {sent: 'none', received: 'none'};
|
||||
|
||||
componentDidMount() {
|
||||
@@ -41,7 +36,7 @@ class AppEventsTest extends React.Component<{...}, State> {
|
||||
this.setState({sent: event});
|
||||
}
|
||||
|
||||
receiveEvent: (event: any) => void = (event: any) => {
|
||||
receiveEvent = (event: any) => {
|
||||
if (deepDiffer(event.data, TEST_PAYLOAD)) {
|
||||
throw new Error('Received wrong event: ' + JSON.stringify(event));
|
||||
}
|
||||
@@ -51,7 +46,7 @@ class AppEventsTest extends React.Component<{...}, State> {
|
||||
});
|
||||
};
|
||||
|
||||
render(): React.Node {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>{JSON.stringify(this.state, null, ' ')}</Text>
|
||||
|
||||
@@ -152,10 +152,7 @@ function testMerge() {
|
||||
}
|
||||
|
||||
function testOptimizedMultiGet() {
|
||||
let batch = [
|
||||
[KEY_1, VAL_1],
|
||||
[KEY_2, VAL_2],
|
||||
];
|
||||
let batch = [[KEY_1, VAL_1], [KEY_2, VAL_2]];
|
||||
let keys = batch.map(([key, value]) => key);
|
||||
AsyncStorage.multiSet(batch, err1 => {
|
||||
// yes, twice on purpose
|
||||
@@ -174,8 +171,8 @@ function testOptimizedMultiGet() {
|
||||
});
|
||||
}
|
||||
|
||||
class AsyncStorageTest extends React.Component<{...}, $FlowFixMeState> {
|
||||
state: any | {|done: boolean, messages: string|} = {
|
||||
class AsyncStorageTest extends React.Component<{}, $FlowFixMeState> {
|
||||
state = {
|
||||
messages: 'Initializing...',
|
||||
done: false,
|
||||
};
|
||||
@@ -192,7 +189,7 @@ class AsyncStorageTest extends React.Component<{...}, $FlowFixMeState> {
|
||||
AsyncStorage.clear(testSetAndGet);
|
||||
}
|
||||
|
||||
render(): React.Node {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {ExtendedError} from 'react-native/Libraries/Core/Devtools/parseErrorStack';
|
||||
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const parseErrorStack = require('react-native/Libraries/Core/Devtools/parseErrorStack');
|
||||
const {View} = ReactNative;
|
||||
|
||||
const {TestModule} = ReactNative.NativeModules;
|
||||
|
||||
class GlobalEvalWithSourceUrlTest extends React.Component<{...}> {
|
||||
componentDidMount() {
|
||||
if (typeof global.globalEvalWithSourceUrl !== 'function') {
|
||||
throw new Error(
|
||||
'Expected to find globalEvalWithSourceUrl function on global object but found ' +
|
||||
typeof global.globalEvalWithSourceUrl,
|
||||
);
|
||||
}
|
||||
const value = global.globalEvalWithSourceUrl('42');
|
||||
if (value !== 42) {
|
||||
throw new Error(
|
||||
'Expected globalEvalWithSourceUrl(expression) to return a value',
|
||||
);
|
||||
}
|
||||
let syntaxError: ?ExtendedError;
|
||||
try {
|
||||
global.globalEvalWithSourceUrl('{');
|
||||
} catch (e) {
|
||||
syntaxError = e;
|
||||
}
|
||||
if (!syntaxError) {
|
||||
throw new Error(
|
||||
'Expected globalEvalWithSourceUrl to throw on a syntax error',
|
||||
);
|
||||
}
|
||||
// Hermes throws an Error instead of a SyntaxError
|
||||
// https://github.com/facebook/hermes/issues/400
|
||||
if (
|
||||
syntaxError.jsEngine !== 'hermes' &&
|
||||
!(syntaxError instanceof SyntaxError)
|
||||
) {
|
||||
throw new Error(
|
||||
'Expected globalEvalWithSourceUrl to throw SyntaxError on a syntax error',
|
||||
);
|
||||
}
|
||||
const url = 'http://example.com/foo.js';
|
||||
let error;
|
||||
try {
|
||||
global.globalEvalWithSourceUrl('throw new Error()', url);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
if (!error) {
|
||||
throw new Error(
|
||||
'Expected globalEvalWithSourceUrl to throw an Error object',
|
||||
);
|
||||
}
|
||||
const parsedStack = parseErrorStack(error?.stack);
|
||||
if (parsedStack[0].file !== url) {
|
||||
throw new Error(
|
||||
`Expected first eval stack frame to be in ${url} but found ${String(
|
||||
parsedStack[0].file,
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
TestModule.markTestCompleted();
|
||||
}
|
||||
|
||||
render(): React.Node {
|
||||
return <View />;
|
||||
}
|
||||
}
|
||||
|
||||
GlobalEvalWithSourceUrlTest.displayName = 'GlobalEvalWithSourceUrlTest';
|
||||
|
||||
module.exports = GlobalEvalWithSourceUrlTest;
|
||||
@@ -27,19 +27,18 @@ const {TestModule} = ReactNative.NativeModules;
|
||||
|
||||
const TESTS = ['only-if-cached', 'default', 'reload', 'force-cache'];
|
||||
|
||||
type Props = {...};
|
||||
type Props = {};
|
||||
type State = {
|
||||
'only-if-cached'?: boolean,
|
||||
default?: boolean,
|
||||
reload?: boolean,
|
||||
'force-cache'?: boolean,
|
||||
...
|
||||
};
|
||||
|
||||
class ImageCachePolicyTest extends React.Component<Props, $FlowFixMeState> {
|
||||
state: $FlowFixMe | {...} = {};
|
||||
state = {};
|
||||
|
||||
shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
|
||||
shouldComponentUpdate(nextProps: Props, nextState: State) {
|
||||
const results: Array<?boolean> = TESTS.map(x => nextState[x]);
|
||||
|
||||
if (!results.includes(undefined)) {
|
||||
@@ -57,14 +56,14 @@ class ImageCachePolicyTest extends React.Component<Props, $FlowFixMeState> {
|
||||
this.setState({[name]: pass});
|
||||
}
|
||||
|
||||
render(): React.Node {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>Hello</Text>
|
||||
<Image
|
||||
source={{
|
||||
uri:
|
||||
'https://raw.githubusercontent.com/facebook/react-native/master/Libraries/NewAppScreen/components/logo.png?cacheBust=notinCache' +
|
||||
'https://facebook.github.io/react-native/img/favicon.png?cacheBust=notinCache' +
|
||||
Date.now(),
|
||||
cache: 'only-if-cached',
|
||||
}}
|
||||
@@ -75,7 +74,7 @@ class ImageCachePolicyTest extends React.Component<Props, $FlowFixMeState> {
|
||||
<Image
|
||||
source={{
|
||||
uri:
|
||||
'https://raw.githubusercontent.com/facebook/react-native/master/Libraries/NewAppScreen/components/logo.png?cacheBust=notinCache' +
|
||||
'https://facebook.github.io/react-native/img/favicon.png?cacheBust=notinCache' +
|
||||
Date.now(),
|
||||
cache: 'default',
|
||||
}}
|
||||
@@ -86,7 +85,7 @@ class ImageCachePolicyTest extends React.Component<Props, $FlowFixMeState> {
|
||||
<Image
|
||||
source={{
|
||||
uri:
|
||||
'https://raw.githubusercontent.com/facebook/react-native/master/Libraries/NewAppScreen/components/logo.png?cacheBust=notinCache' +
|
||||
'https://facebook.github.io/react-native/img/favicon.png?cacheBust=notinCache' +
|
||||
Date.now(),
|
||||
cache: 'reload',
|
||||
}}
|
||||
@@ -97,7 +96,7 @@ class ImageCachePolicyTest extends React.Component<Props, $FlowFixMeState> {
|
||||
<Image
|
||||
source={{
|
||||
uri:
|
||||
'https://raw.githubusercontent.com/facebook/react-native/master/Libraries/NewAppScreen/components/logo.png?cacheBust=notinCache' +
|
||||
'https://facebook.github.io/react-native/img/favicon.png?cacheBust=notinCache' +
|
||||
Date.now(),
|
||||
cache: 'force-cache',
|
||||
}}
|
||||
|
||||
@@ -15,18 +15,18 @@ const ReactNative = require('react-native');
|
||||
const {Image} = ReactNative;
|
||||
const {TestModule} = ReactNative.NativeModules;
|
||||
|
||||
class ImageSnapshotTest extends React.Component<{...}> {
|
||||
class ImageSnapshotTest extends React.Component<{}> {
|
||||
componentDidMount() {
|
||||
if (!TestModule.verifySnapshot) {
|
||||
throw new Error('TestModule.verifySnapshot not defined.');
|
||||
}
|
||||
}
|
||||
|
||||
done: (success: boolean) => void = (success: boolean) => {
|
||||
done = (success: boolean) => {
|
||||
TestModule.markTestPassed(success);
|
||||
};
|
||||
|
||||
render(): React.Node {
|
||||
render() {
|
||||
return (
|
||||
<Image
|
||||
source={require('./blue_square.png')}
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const requestAnimationFrame = require('fbjs/lib/requestAnimationFrame');
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
|
||||
const {Text, View, StyleSheet} = ReactNative;
|
||||
const {TestModule} = ReactNative.NativeModules;
|
||||
|
||||
@@ -26,7 +26,7 @@ type State = {|
|
||||
|};
|
||||
|
||||
class IntegrationTestHarnessTest extends React.Component<Props, State> {
|
||||
state: State = {
|
||||
state = {
|
||||
done: false,
|
||||
};
|
||||
|
||||
@@ -38,7 +38,7 @@ class IntegrationTestHarnessTest extends React.Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
runTest: () => void = () => {
|
||||
runTest = () => {
|
||||
if (this.props.shouldThrow) {
|
||||
throw new Error('Throwing error because shouldThrow');
|
||||
}
|
||||
@@ -52,7 +52,7 @@ class IntegrationTestHarnessTest extends React.Component<Props, State> {
|
||||
});
|
||||
};
|
||||
|
||||
render(): React.Node {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>
|
||||
|
||||
@@ -36,7 +36,6 @@ const TESTS = [
|
||||
require('./SyncMethodTest'),
|
||||
require('./WebSocketTest'),
|
||||
require('./AccessibilityManagerTest'),
|
||||
require('./GlobalEvalWithSourceUrlTest'),
|
||||
];
|
||||
|
||||
TESTS.forEach(
|
||||
@@ -51,7 +50,7 @@ require('./LoggingTestModule');
|
||||
|
||||
type Test = any;
|
||||
|
||||
class IntegrationTestsApp extends React.Component<{...}, $FlowFixMeState> {
|
||||
class IntegrationTestsApp extends React.Component<{}, $FlowFixMeState> {
|
||||
state = {
|
||||
test: (null: ?Test),
|
||||
};
|
||||
@@ -79,9 +78,6 @@ class IntegrationTestsApp extends React.Component<{...}, $FlowFixMeState> {
|
||||
{TESTS.map(test => [
|
||||
<TouchableOpacity
|
||||
onPress={() => this.setState({test})}
|
||||
/* $FlowFixMe(>=0.115.0 site=react_native_fb) This comment
|
||||
* suppresses an error found when Flow v0.115 was deployed. To
|
||||
* see the error, delete this comment and run Flow. */
|
||||
style={styles.row}>
|
||||
<Text style={styles.testName}>{test.displayName}</Text>
|
||||
</TouchableOpacity>,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
@@ -38,7 +38,6 @@ type State = {
|
||||
viewLayout?: Layout,
|
||||
viewStyle?: ViewStyleProp,
|
||||
containerStyle?: ViewStyleProp,
|
||||
...
|
||||
};
|
||||
|
||||
class LayoutEventsTest extends React.Component<Props, State> {
|
||||
@@ -59,7 +58,7 @@ class LayoutEventsTest extends React.Component<Props, State> {
|
||||
this.setState({viewStyle: {margin: 60}});
|
||||
}
|
||||
|
||||
addWrapText: () => void = () => {
|
||||
addWrapText = () => {
|
||||
debug('addWrapText invoked');
|
||||
this.setState(
|
||||
{extraText: ' And a bunch more text to wrap around a few lines.'},
|
||||
@@ -67,14 +66,14 @@ class LayoutEventsTest extends React.Component<Props, State> {
|
||||
);
|
||||
};
|
||||
|
||||
changeContainer: () => void = () => {
|
||||
changeContainer = () => {
|
||||
debug('changeContainer invoked');
|
||||
this.setState({containerStyle: {width: 280}}, () =>
|
||||
this.checkLayout(TestModule.markTestCompleted),
|
||||
);
|
||||
};
|
||||
|
||||
checkLayout: (next?: ?() => void) => void = (next?: ?() => void) => {
|
||||
checkLayout = (next?: ?() => void) => {
|
||||
const view = this._view;
|
||||
const txt = this._txt;
|
||||
const img = this._img;
|
||||
@@ -118,22 +117,22 @@ class LayoutEventsTest extends React.Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
onViewLayout: (e: LayoutEvent) => void = (e: LayoutEvent) => {
|
||||
onViewLayout = (e: LayoutEvent) => {
|
||||
debug('received view layout event\n', e.nativeEvent);
|
||||
this.setState({viewLayout: e.nativeEvent.layout}, this.checkLayout);
|
||||
};
|
||||
|
||||
onTextLayout: (e: LayoutEvent) => void = (e: LayoutEvent) => {
|
||||
onTextLayout = (e: LayoutEvent) => {
|
||||
debug('received text layout event\n', e.nativeEvent);
|
||||
this.setState({textLayout: e.nativeEvent.layout}, this.checkLayout);
|
||||
};
|
||||
|
||||
onImageLayout: (e: LayoutEvent) => void = (e: LayoutEvent) => {
|
||||
onImageLayout = (e: LayoutEvent) => {
|
||||
debug('received image layout event\n', e.nativeEvent);
|
||||
this.setState({imageLayout: e.nativeEvent.layout}, this.checkLayout);
|
||||
};
|
||||
|
||||
render(): React.Node {
|
||||
render() {
|
||||
const viewStyle = [styles.view, this.state.viewStyle];
|
||||
const textLayout = this.state.textLayout || {width: '?', height: '?'};
|
||||
const imageLayout = this.state.imageLayout || {x: '?', y: '?'};
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
const BatchedBridge = require('react-native/Libraries/BatchedBridge/BatchedBridge');
|
||||
|
||||
const warning = require('fbjs/lib/warning');
|
||||
const invariant = require('invariant');
|
||||
|
||||
const LoggingTestModule = {
|
||||
@@ -23,7 +24,7 @@ const LoggingTestModule = {
|
||||
}, timeout_ms);
|
||||
},
|
||||
warning: function(str) {
|
||||
console.warn(str);
|
||||
warning(false, str);
|
||||
},
|
||||
invariant: function(str) {
|
||||
invariant(false, str);
|
||||
|
||||
@@ -15,11 +15,11 @@ const ReactNative = require('react-native');
|
||||
const {View} = ReactNative;
|
||||
const {TestModule} = ReactNative.NativeModules;
|
||||
|
||||
class PromiseTest extends React.Component<{...}> {
|
||||
shouldResolve: boolean = false;
|
||||
shouldReject: boolean = false;
|
||||
shouldSucceedAsync: boolean = false;
|
||||
shouldThrowAsync: boolean = false;
|
||||
class PromiseTest extends React.Component<{}> {
|
||||
shouldResolve = false;
|
||||
shouldReject = false;
|
||||
shouldSucceedAsync = false;
|
||||
shouldThrowAsync = false;
|
||||
|
||||
componentDidMount() {
|
||||
Promise.all([
|
||||
@@ -37,19 +37,19 @@ class PromiseTest extends React.Component<{...}> {
|
||||
);
|
||||
}
|
||||
|
||||
testShouldResolve: () => any = () => {
|
||||
testShouldResolve = () => {
|
||||
return TestModule.shouldResolve()
|
||||
.then(() => (this.shouldResolve = true))
|
||||
.catch(() => (this.shouldResolve = false));
|
||||
};
|
||||
|
||||
testShouldReject: () => any = () => {
|
||||
testShouldReject = () => {
|
||||
return TestModule.shouldReject()
|
||||
.then(() => (this.shouldReject = false))
|
||||
.catch(() => (this.shouldReject = true));
|
||||
};
|
||||
|
||||
testShouldSucceedAsync: () => Promise<any> = async (): Promise<any> => {
|
||||
testShouldSucceedAsync = async (): Promise<any> => {
|
||||
try {
|
||||
await TestModule.shouldResolve();
|
||||
this.shouldSucceedAsync = true;
|
||||
@@ -58,7 +58,7 @@ class PromiseTest extends React.Component<{...}> {
|
||||
}
|
||||
};
|
||||
|
||||
testShouldThrowAsync: () => Promise<any> = async (): Promise<any> => {
|
||||
testShouldThrowAsync = async (): Promise<any> => {
|
||||
try {
|
||||
await TestModule.shouldReject();
|
||||
this.shouldThrowAsync = false;
|
||||
|
||||
@@ -5,19 +5,19 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const RCTNativeAppEventEmitter = require('react-native/Libraries/EventEmitter/RCTNativeAppEventEmitter');
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const RCTNativeAppEventEmitter = require('react-native/Libraries/EventEmitter/RCTNativeAppEventEmitter');
|
||||
|
||||
const {View} = ReactNative;
|
||||
|
||||
const {TestModule} = ReactNative.NativeModules;
|
||||
import {type EventSubscription} from 'react-native/Libraries/vendor/emitter/EventEmitter';
|
||||
import type EmitterSubscription from 'react-native/Libraries/vendor/emitter/EmitterSubscription';
|
||||
|
||||
const reactViewWidth = 101;
|
||||
const reactViewHeight = 102;
|
||||
@@ -33,9 +33,9 @@ type State = {|
|
||||
|
||||
class ReactContentSizeUpdateTest extends React.Component<Props, State> {
|
||||
_timeoutID: ?TimeoutID = null;
|
||||
_subscription: ?EventSubscription = null;
|
||||
_subscription: ?EmitterSubscription = null;
|
||||
|
||||
state: State = {
|
||||
state = {
|
||||
height: reactViewHeight,
|
||||
width: reactViewWidth,
|
||||
};
|
||||
@@ -70,9 +70,7 @@ class ReactContentSizeUpdateTest extends React.Component<Props, State> {
|
||||
});
|
||||
}
|
||||
|
||||
rootViewDidChangeIntrinsicSize: (intrinsicSize: State) => void = (
|
||||
intrinsicSize: State,
|
||||
) => {
|
||||
rootViewDidChangeIntrinsicSize = (intrinsicSize: State) => {
|
||||
if (
|
||||
intrinsicSize.height === newReactViewHeight &&
|
||||
intrinsicSize.width === newReactViewWidth
|
||||
@@ -81,7 +79,7 @@ class ReactContentSizeUpdateTest extends React.Component<Props, State> {
|
||||
}
|
||||
};
|
||||
|
||||
render(): React.Node {
|
||||
render() {
|
||||
return (
|
||||
<View style={{height: this.state.height, width: this.state.width}} />
|
||||
);
|
||||
|
||||
@@ -5,18 +5,19 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const requestAnimationFrame = require('fbjs/lib/requestAnimationFrame');
|
||||
|
||||
const {StyleSheet, View} = ReactNative;
|
||||
const {TestModule} = ReactNative.NativeModules;
|
||||
|
||||
class SimpleSnapshotTest extends React.Component<{...}> {
|
||||
class SimpleSnapshotTest extends React.Component<{}> {
|
||||
componentDidMount() {
|
||||
if (!TestModule.verifySnapshot) {
|
||||
throw new Error('TestModule.verifySnapshot not defined.');
|
||||
@@ -24,11 +25,11 @@ class SimpleSnapshotTest extends React.Component<{...}> {
|
||||
requestAnimationFrame(() => TestModule.verifySnapshot(this.done));
|
||||
}
|
||||
|
||||
done: (success: boolean) => void = (success: boolean) => {
|
||||
done = (success: boolean) => {
|
||||
TestModule.markTestPassed(success);
|
||||
};
|
||||
|
||||
render(): React.Node {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.box1} />
|
||||
|
||||
@@ -5,18 +5,18 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const RCTNativeAppEventEmitter = require('react-native/Libraries/EventEmitter/RCTNativeAppEventEmitter');
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const RCTNativeAppEventEmitter = require('react-native/Libraries/EventEmitter/RCTNativeAppEventEmitter');
|
||||
const {View} = ReactNative;
|
||||
|
||||
const {TestModule} = ReactNative.NativeModules;
|
||||
import {type EventSubscription} from 'react-native/Libraries/vendor/emitter/EventEmitter';
|
||||
import type EmitterSubscription from 'react-native/Libraries/vendor/emitter/EmitterSubscription';
|
||||
|
||||
const reactViewWidth = 111;
|
||||
const reactViewHeight = 222;
|
||||
@@ -31,7 +31,7 @@ type Props = $ReadOnly<{|
|
||||
|}>;
|
||||
|
||||
class SizeFlexibilityUpdateTest extends React.Component<Props> {
|
||||
_subscription: ?EventSubscription = null;
|
||||
_subscription: ?EmitterSubscription = null;
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this._subscription = RCTNativeAppEventEmitter.addListener(
|
||||
@@ -46,16 +46,15 @@ class SizeFlexibilityUpdateTest extends React.Component<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
markPassed: () => void = () => {
|
||||
markPassed = () => {
|
||||
TestModule.markTestPassed(true);
|
||||
finalState = true;
|
||||
};
|
||||
|
||||
rootViewDidChangeIntrinsicSize: (intrinsicSize: {
|
||||
height: number,
|
||||
rootViewDidChangeIntrinsicSize = (intrinsicSize: {
|
||||
width: number,
|
||||
...
|
||||
}) => void = (intrinsicSize: {width: number, height: number, ...}) => {
|
||||
height: number,
|
||||
}) => {
|
||||
if (finalState) {
|
||||
// If a test reaches its final state, it is not expected to do anything more
|
||||
TestModule.markTestPassed(false);
|
||||
@@ -100,7 +99,7 @@ class SizeFlexibilityUpdateTest extends React.Component<Props> {
|
||||
}
|
||||
};
|
||||
|
||||
render(): React.Node {
|
||||
render() {
|
||||
return <View style={{height: reactViewHeight, width: reactViewWidth}} />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ const {View} = ReactNative;
|
||||
|
||||
const {TestModule, RNTesterTestModule} = ReactNative.NativeModules;
|
||||
|
||||
class SyncMethodTest extends React.Component<{...}> {
|
||||
class SyncMethodTest extends React.Component<{}> {
|
||||
componentDidMount() {
|
||||
if (
|
||||
RNTesterTestModule.echoString('test string value') !== 'test string value'
|
||||
|
||||
@@ -33,7 +33,7 @@ class TimersTest extends React.Component<Props, State> {
|
||||
_immediateIDs: Set<ImmediateID> = new Set();
|
||||
_animationFrameIDs: Set<AnimationFrameID> = new Set();
|
||||
|
||||
state: State = {
|
||||
state = {
|
||||
count: 0,
|
||||
done: false,
|
||||
};
|
||||
@@ -228,7 +228,7 @@ class TimersTest extends React.Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
render(): React.Node {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>
|
||||
|
||||
@@ -28,10 +28,9 @@ type State = {
|
||||
lastMessage: ?string | ?ArrayBuffer,
|
||||
testMessage: string,
|
||||
testExpectedResponse: string,
|
||||
...
|
||||
};
|
||||
|
||||
class WebSocketTest extends React.Component<{...}, State> {
|
||||
class WebSocketTest extends React.Component<{}, State> {
|
||||
state: State = {
|
||||
url: DEFAULT_WS_URL,
|
||||
fetchStatus: null,
|
||||
@@ -114,7 +113,7 @@ class WebSocketTest extends React.Component<{...}, State> {
|
||||
this.testConnect();
|
||||
}
|
||||
|
||||
testConnect: () => void = () => {
|
||||
testConnect = () => {
|
||||
this._connect();
|
||||
this._waitFor(this._socketIsConnected, 5, connectSucceeded => {
|
||||
if (!connectSucceeded) {
|
||||
@@ -125,7 +124,7 @@ class WebSocketTest extends React.Component<{...}, State> {
|
||||
});
|
||||
};
|
||||
|
||||
testSendAndReceive: () => void = () => {
|
||||
testSendAndReceive = () => {
|
||||
this._sendTestMessage();
|
||||
this._waitFor(this._receivedTestExpectedResponse, 5, messageReceived => {
|
||||
if (!messageReceived) {
|
||||
@@ -136,7 +135,7 @@ class WebSocketTest extends React.Component<{...}, State> {
|
||||
});
|
||||
};
|
||||
|
||||
testDisconnect: () => void = () => {
|
||||
testDisconnect = () => {
|
||||
this._disconnect();
|
||||
this._waitFor(this._socketIsDisconnected, 5, disconnectSucceeded => {
|
||||
TestModule.markTestPassed(disconnectSucceeded);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
@@ -8,7 +9,6 @@
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env node */
|
||||
|
||||
@@ -0,0 +1,514 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
0CF68B051AF0549300FF9E5C /* ARTGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68ADE1AF0549300FF9E5C /* ARTGroup.m */; };
|
||||
0CF68B061AF0549300FF9E5C /* ARTNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE01AF0549300FF9E5C /* ARTNode.m */; };
|
||||
0CF68B071AF0549300FF9E5C /* ARTRenderable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE21AF0549300FF9E5C /* ARTRenderable.m */; };
|
||||
0CF68B081AF0549300FF9E5C /* ARTShape.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE41AF0549300FF9E5C /* ARTShape.m */; };
|
||||
0CF68B091AF0549300FF9E5C /* ARTSurfaceView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE61AF0549300FF9E5C /* ARTSurfaceView.m */; };
|
||||
0CF68B0A1AF0549300FF9E5C /* ARTText.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE81AF0549300FF9E5C /* ARTText.m */; };
|
||||
0CF68B0B1AF0549300FF9E5C /* ARTBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AEC1AF0549300FF9E5C /* ARTBrush.m */; };
|
||||
0CF68B0C1AF0549300FF9E5C /* ARTLinearGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AEE1AF0549300FF9E5C /* ARTLinearGradient.m */; };
|
||||
0CF68B0D1AF0549300FF9E5C /* ARTPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF01AF0549300FF9E5C /* ARTPattern.m */; };
|
||||
0CF68B0E1AF0549300FF9E5C /* ARTRadialGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF21AF0549300FF9E5C /* ARTRadialGradient.m */; };
|
||||
0CF68B0F1AF0549300FF9E5C /* ARTSolidColor.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF41AF0549300FF9E5C /* ARTSolidColor.m */; };
|
||||
0CF68B101AF0549300FF9E5C /* RCTConvert+ART.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF71AF0549300FF9E5C /* RCTConvert+ART.m */; };
|
||||
0CF68B111AF0549300FF9E5C /* ARTGroupManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AFA1AF0549300FF9E5C /* ARTGroupManager.m */; };
|
||||
0CF68B121AF0549300FF9E5C /* ARTNodeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AFC1AF0549300FF9E5C /* ARTNodeManager.m */; };
|
||||
0CF68B131AF0549300FF9E5C /* ARTRenderableManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AFE1AF0549300FF9E5C /* ARTRenderableManager.m */; };
|
||||
0CF68B141AF0549300FF9E5C /* ARTShapeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68B001AF0549300FF9E5C /* ARTShapeManager.m */; };
|
||||
0CF68B151AF0549300FF9E5C /* ARTSurfaceViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68B021AF0549300FF9E5C /* ARTSurfaceViewManager.m */; };
|
||||
0CF68B161AF0549300FF9E5C /* ARTTextManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68B041AF0549300FF9E5C /* ARTTextManager.m */; };
|
||||
325CF7AD1E5F2ABA00AC9606 /* ARTBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AEC1AF0549300FF9E5C /* ARTBrush.m */; };
|
||||
325CF7AE1E5F2ABA00AC9606 /* ARTLinearGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AEE1AF0549300FF9E5C /* ARTLinearGradient.m */; };
|
||||
325CF7AF1E5F2ABA00AC9606 /* ARTPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF01AF0549300FF9E5C /* ARTPattern.m */; };
|
||||
325CF7B01E5F2ABA00AC9606 /* ARTRadialGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF21AF0549300FF9E5C /* ARTRadialGradient.m */; };
|
||||
325CF7B11E5F2ABA00AC9606 /* ARTSolidColor.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF41AF0549300FF9E5C /* ARTSolidColor.m */; };
|
||||
325CF7B21E5F2ABA00AC9606 /* ARTGroupManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AFA1AF0549300FF9E5C /* ARTGroupManager.m */; };
|
||||
325CF7B31E5F2ABA00AC9606 /* ARTNodeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AFC1AF0549300FF9E5C /* ARTNodeManager.m */; };
|
||||
325CF7B41E5F2ABA00AC9606 /* ARTRenderableManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AFE1AF0549300FF9E5C /* ARTRenderableManager.m */; };
|
||||
325CF7B51E5F2ABA00AC9606 /* ARTShapeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68B001AF0549300FF9E5C /* ARTShapeManager.m */; };
|
||||
325CF7B61E5F2ABA00AC9606 /* ARTSurfaceViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68B021AF0549300FF9E5C /* ARTSurfaceViewManager.m */; };
|
||||
325CF7B71E5F2ABA00AC9606 /* ARTTextManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68B041AF0549300FF9E5C /* ARTTextManager.m */; };
|
||||
325CF7B81E5F2ABA00AC9606 /* ARTGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68ADE1AF0549300FF9E5C /* ARTGroup.m */; };
|
||||
325CF7B91E5F2ABA00AC9606 /* ARTNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE01AF0549300FF9E5C /* ARTNode.m */; };
|
||||
325CF7BA1E5F2ABA00AC9606 /* ARTRenderable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE21AF0549300FF9E5C /* ARTRenderable.m */; };
|
||||
325CF7BB1E5F2ABA00AC9606 /* ARTShape.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE41AF0549300FF9E5C /* ARTShape.m */; };
|
||||
325CF7BC1E5F2ABA00AC9606 /* ARTSurfaceView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE61AF0549300FF9E5C /* ARTSurfaceView.m */; };
|
||||
325CF7BD1E5F2ABA00AC9606 /* ARTText.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE81AF0549300FF9E5C /* ARTText.m */; };
|
||||
325CF7BE1E5F2ABA00AC9606 /* RCTConvert+ART.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF71AF0549300FF9E5C /* RCTConvert+ART.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
0CF68ABF1AF0540F00FF9E5C /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "include/$(PRODUCT_NAME)";
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
323A12851E5F266B004975B8 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "include/$(PRODUCT_NAME)";
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0CF68AC11AF0540F00FF9E5C /* libART.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libART.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0CF68ADB1AF0549300FF9E5C /* ARTCGFloatArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTCGFloatArray.h; sourceTree = "<group>"; };
|
||||
0CF68ADC1AF0549300FF9E5C /* ARTContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTContainer.h; sourceTree = "<group>"; };
|
||||
0CF68ADD1AF0549300FF9E5C /* ARTGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTGroup.h; sourceTree = "<group>"; };
|
||||
0CF68ADE1AF0549300FF9E5C /* ARTGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTGroup.m; sourceTree = "<group>"; };
|
||||
0CF68ADF1AF0549300FF9E5C /* ARTNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTNode.h; sourceTree = "<group>"; };
|
||||
0CF68AE01AF0549300FF9E5C /* ARTNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTNode.m; sourceTree = "<group>"; };
|
||||
0CF68AE11AF0549300FF9E5C /* ARTRenderable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTRenderable.h; sourceTree = "<group>"; };
|
||||
0CF68AE21AF0549300FF9E5C /* ARTRenderable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTRenderable.m; sourceTree = "<group>"; };
|
||||
0CF68AE31AF0549300FF9E5C /* ARTShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTShape.h; sourceTree = "<group>"; };
|
||||
0CF68AE41AF0549300FF9E5C /* ARTShape.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTShape.m; sourceTree = "<group>"; };
|
||||
0CF68AE51AF0549300FF9E5C /* ARTSurfaceView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTSurfaceView.h; sourceTree = "<group>"; };
|
||||
0CF68AE61AF0549300FF9E5C /* ARTSurfaceView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTSurfaceView.m; sourceTree = "<group>"; };
|
||||
0CF68AE71AF0549300FF9E5C /* ARTText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTText.h; sourceTree = "<group>"; };
|
||||
0CF68AE81AF0549300FF9E5C /* ARTText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTText.m; sourceTree = "<group>"; };
|
||||
0CF68AE91AF0549300FF9E5C /* ARTTextFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTTextFrame.h; sourceTree = "<group>"; };
|
||||
0CF68AEB1AF0549300FF9E5C /* ARTBrush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTBrush.h; sourceTree = "<group>"; };
|
||||
0CF68AEC1AF0549300FF9E5C /* ARTBrush.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTBrush.m; sourceTree = "<group>"; };
|
||||
0CF68AED1AF0549300FF9E5C /* ARTLinearGradient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTLinearGradient.h; sourceTree = "<group>"; };
|
||||
0CF68AEE1AF0549300FF9E5C /* ARTLinearGradient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTLinearGradient.m; sourceTree = "<group>"; };
|
||||
0CF68AEF1AF0549300FF9E5C /* ARTPattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTPattern.h; sourceTree = "<group>"; };
|
||||
0CF68AF01AF0549300FF9E5C /* ARTPattern.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTPattern.m; sourceTree = "<group>"; };
|
||||
0CF68AF11AF0549300FF9E5C /* ARTRadialGradient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTRadialGradient.h; sourceTree = "<group>"; };
|
||||
0CF68AF21AF0549300FF9E5C /* ARTRadialGradient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTRadialGradient.m; sourceTree = "<group>"; };
|
||||
0CF68AF31AF0549300FF9E5C /* ARTSolidColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTSolidColor.h; sourceTree = "<group>"; };
|
||||
0CF68AF41AF0549300FF9E5C /* ARTSolidColor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTSolidColor.m; sourceTree = "<group>"; };
|
||||
0CF68AF61AF0549300FF9E5C /* RCTConvert+ART.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+ART.h"; sourceTree = "<group>"; };
|
||||
0CF68AF71AF0549300FF9E5C /* RCTConvert+ART.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+ART.m"; sourceTree = "<group>"; };
|
||||
0CF68AF91AF0549300FF9E5C /* ARTGroupManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTGroupManager.h; sourceTree = "<group>"; };
|
||||
0CF68AFA1AF0549300FF9E5C /* ARTGroupManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTGroupManager.m; sourceTree = "<group>"; };
|
||||
0CF68AFB1AF0549300FF9E5C /* ARTNodeManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTNodeManager.h; sourceTree = "<group>"; };
|
||||
0CF68AFC1AF0549300FF9E5C /* ARTNodeManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTNodeManager.m; sourceTree = "<group>"; };
|
||||
0CF68AFD1AF0549300FF9E5C /* ARTRenderableManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTRenderableManager.h; sourceTree = "<group>"; };
|
||||
0CF68AFE1AF0549300FF9E5C /* ARTRenderableManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTRenderableManager.m; sourceTree = "<group>"; };
|
||||
0CF68AFF1AF0549300FF9E5C /* ARTShapeManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTShapeManager.h; sourceTree = "<group>"; };
|
||||
0CF68B001AF0549300FF9E5C /* ARTShapeManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTShapeManager.m; sourceTree = "<group>"; };
|
||||
0CF68B011AF0549300FF9E5C /* ARTSurfaceViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTSurfaceViewManager.h; sourceTree = "<group>"; };
|
||||
0CF68B021AF0549300FF9E5C /* ARTSurfaceViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTSurfaceViewManager.m; sourceTree = "<group>"; };
|
||||
0CF68B031AF0549300FF9E5C /* ARTTextManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTTextManager.h; sourceTree = "<group>"; };
|
||||
0CF68B041AF0549300FF9E5C /* ARTTextManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTTextManager.m; sourceTree = "<group>"; };
|
||||
323A12871E5F266B004975B8 /* libART-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libART-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
0CF68ABE1AF0540F00FF9E5C /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
323A12841E5F266B004975B8 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
0CF68AB81AF0540F00FF9E5C = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0CF68AEA1AF0549300FF9E5C /* Brushes */,
|
||||
0CF68AF81AF0549300FF9E5C /* ViewManagers */,
|
||||
0CF68ADB1AF0549300FF9E5C /* ARTCGFloatArray.h */,
|
||||
0CF68ADC1AF0549300FF9E5C /* ARTContainer.h */,
|
||||
0CF68ADD1AF0549300FF9E5C /* ARTGroup.h */,
|
||||
0CF68ADE1AF0549300FF9E5C /* ARTGroup.m */,
|
||||
0CF68ADF1AF0549300FF9E5C /* ARTNode.h */,
|
||||
0CF68AE01AF0549300FF9E5C /* ARTNode.m */,
|
||||
0CF68AE11AF0549300FF9E5C /* ARTRenderable.h */,
|
||||
0CF68AE21AF0549300FF9E5C /* ARTRenderable.m */,
|
||||
0CF68AE31AF0549300FF9E5C /* ARTShape.h */,
|
||||
0CF68AE41AF0549300FF9E5C /* ARTShape.m */,
|
||||
0CF68AE51AF0549300FF9E5C /* ARTSurfaceView.h */,
|
||||
0CF68AE61AF0549300FF9E5C /* ARTSurfaceView.m */,
|
||||
0CF68AE71AF0549300FF9E5C /* ARTText.h */,
|
||||
0CF68AE81AF0549300FF9E5C /* ARTText.m */,
|
||||
0CF68AE91AF0549300FF9E5C /* ARTTextFrame.h */,
|
||||
0CF68AF61AF0549300FF9E5C /* RCTConvert+ART.h */,
|
||||
0CF68AF71AF0549300FF9E5C /* RCTConvert+ART.m */,
|
||||
0CF68AC21AF0540F00FF9E5C /* Products */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
sourceTree = "<group>";
|
||||
tabWidth = 2;
|
||||
usesTabs = 0;
|
||||
};
|
||||
0CF68AC21AF0540F00FF9E5C /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0CF68AC11AF0540F00FF9E5C /* libART.a */,
|
||||
323A12871E5F266B004975B8 /* libART-tvOS.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0CF68AEA1AF0549300FF9E5C /* Brushes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0CF68AEB1AF0549300FF9E5C /* ARTBrush.h */,
|
||||
0CF68AEC1AF0549300FF9E5C /* ARTBrush.m */,
|
||||
0CF68AED1AF0549300FF9E5C /* ARTLinearGradient.h */,
|
||||
0CF68AEE1AF0549300FF9E5C /* ARTLinearGradient.m */,
|
||||
0CF68AEF1AF0549300FF9E5C /* ARTPattern.h */,
|
||||
0CF68AF01AF0549300FF9E5C /* ARTPattern.m */,
|
||||
0CF68AF11AF0549300FF9E5C /* ARTRadialGradient.h */,
|
||||
0CF68AF21AF0549300FF9E5C /* ARTRadialGradient.m */,
|
||||
0CF68AF31AF0549300FF9E5C /* ARTSolidColor.h */,
|
||||
0CF68AF41AF0549300FF9E5C /* ARTSolidColor.m */,
|
||||
);
|
||||
path = Brushes;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0CF68AF81AF0549300FF9E5C /* ViewManagers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0CF68AF91AF0549300FF9E5C /* ARTGroupManager.h */,
|
||||
0CF68AFA1AF0549300FF9E5C /* ARTGroupManager.m */,
|
||||
0CF68AFB1AF0549300FF9E5C /* ARTNodeManager.h */,
|
||||
0CF68AFC1AF0549300FF9E5C /* ARTNodeManager.m */,
|
||||
0CF68AFD1AF0549300FF9E5C /* ARTRenderableManager.h */,
|
||||
0CF68AFE1AF0549300FF9E5C /* ARTRenderableManager.m */,
|
||||
0CF68AFF1AF0549300FF9E5C /* ARTShapeManager.h */,
|
||||
0CF68B001AF0549300FF9E5C /* ARTShapeManager.m */,
|
||||
0CF68B011AF0549300FF9E5C /* ARTSurfaceViewManager.h */,
|
||||
0CF68B021AF0549300FF9E5C /* ARTSurfaceViewManager.m */,
|
||||
0CF68B031AF0549300FF9E5C /* ARTTextManager.h */,
|
||||
0CF68B041AF0549300FF9E5C /* ARTTextManager.m */,
|
||||
);
|
||||
path = ViewManagers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
0CF68AC01AF0540F00FF9E5C /* ART */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 0CF68AD51AF0540F00FF9E5C /* Build configuration list for PBXNativeTarget "ART" */;
|
||||
buildPhases = (
|
||||
0CF68ABD1AF0540F00FF9E5C /* Sources */,
|
||||
0CF68ABE1AF0540F00FF9E5C /* Frameworks */,
|
||||
0CF68ABF1AF0540F00FF9E5C /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = ART;
|
||||
productName = ART;
|
||||
productReference = 0CF68AC11AF0540F00FF9E5C /* libART.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
323A12861E5F266B004975B8 /* ART-tvOS */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 323A128D1E5F266B004975B8 /* Build configuration list for PBXNativeTarget "ART-tvOS" */;
|
||||
buildPhases = (
|
||||
323A12831E5F266B004975B8 /* Sources */,
|
||||
323A12841E5F266B004975B8 /* Frameworks */,
|
||||
323A12851E5F266B004975B8 /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "ART-tvOS";
|
||||
productName = "ART-tvOS";
|
||||
productReference = 323A12871E5F266B004975B8 /* libART-tvOS.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
0CF68AB91AF0540F00FF9E5C /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0940;
|
||||
TargetAttributes = {
|
||||
0CF68AC01AF0540F00FF9E5C = {
|
||||
CreatedOnToolsVersion = 6.2;
|
||||
};
|
||||
323A12861E5F266B004975B8 = {
|
||||
CreatedOnToolsVersion = 6.2;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 0CF68ABC1AF0540F00FF9E5C /* Build configuration list for PBXProject "ART" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = 0CF68AB81AF0540F00FF9E5C;
|
||||
productRefGroup = 0CF68AC21AF0540F00FF9E5C /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
0CF68AC01AF0540F00FF9E5C /* ART */,
|
||||
323A12861E5F266B004975B8 /* ART-tvOS */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
0CF68ABD1AF0540F00FF9E5C /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0CF68B161AF0549300FF9E5C /* ARTTextManager.m in Sources */,
|
||||
0CF68B111AF0549300FF9E5C /* ARTGroupManager.m in Sources */,
|
||||
0CF68B0D1AF0549300FF9E5C /* ARTPattern.m in Sources */,
|
||||
0CF68B0A1AF0549300FF9E5C /* ARTText.m in Sources */,
|
||||
0CF68B121AF0549300FF9E5C /* ARTNodeManager.m in Sources */,
|
||||
0CF68B051AF0549300FF9E5C /* ARTGroup.m in Sources */,
|
||||
0CF68B131AF0549300FF9E5C /* ARTRenderableManager.m in Sources */,
|
||||
0CF68B091AF0549300FF9E5C /* ARTSurfaceView.m in Sources */,
|
||||
0CF68B0E1AF0549300FF9E5C /* ARTRadialGradient.m in Sources */,
|
||||
0CF68B151AF0549300FF9E5C /* ARTSurfaceViewManager.m in Sources */,
|
||||
0CF68B081AF0549300FF9E5C /* ARTShape.m in Sources */,
|
||||
0CF68B071AF0549300FF9E5C /* ARTRenderable.m in Sources */,
|
||||
0CF68B101AF0549300FF9E5C /* RCTConvert+ART.m in Sources */,
|
||||
0CF68B061AF0549300FF9E5C /* ARTNode.m in Sources */,
|
||||
0CF68B0F1AF0549300FF9E5C /* ARTSolidColor.m in Sources */,
|
||||
0CF68B0C1AF0549300FF9E5C /* ARTLinearGradient.m in Sources */,
|
||||
0CF68B0B1AF0549300FF9E5C /* ARTBrush.m in Sources */,
|
||||
0CF68B141AF0549300FF9E5C /* ARTShapeManager.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
323A12831E5F266B004975B8 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
325CF7B71E5F2ABA00AC9606 /* ARTTextManager.m in Sources */,
|
||||
325CF7B21E5F2ABA00AC9606 /* ARTGroupManager.m in Sources */,
|
||||
325CF7AF1E5F2ABA00AC9606 /* ARTPattern.m in Sources */,
|
||||
325CF7BD1E5F2ABA00AC9606 /* ARTText.m in Sources */,
|
||||
325CF7B31E5F2ABA00AC9606 /* ARTNodeManager.m in Sources */,
|
||||
325CF7B81E5F2ABA00AC9606 /* ARTGroup.m in Sources */,
|
||||
325CF7B41E5F2ABA00AC9606 /* ARTRenderableManager.m in Sources */,
|
||||
325CF7BC1E5F2ABA00AC9606 /* ARTSurfaceView.m in Sources */,
|
||||
325CF7B01E5F2ABA00AC9606 /* ARTRadialGradient.m in Sources */,
|
||||
325CF7B61E5F2ABA00AC9606 /* ARTSurfaceViewManager.m in Sources */,
|
||||
325CF7BB1E5F2ABA00AC9606 /* ARTShape.m in Sources */,
|
||||
325CF7BA1E5F2ABA00AC9606 /* ARTRenderable.m in Sources */,
|
||||
325CF7BE1E5F2ABA00AC9606 /* RCTConvert+ART.m in Sources */,
|
||||
325CF7B91E5F2ABA00AC9606 /* ARTNode.m in Sources */,
|
||||
325CF7B11E5F2ABA00AC9606 /* ARTSolidColor.m in Sources */,
|
||||
325CF7AE1E5F2ABA00AC9606 /* ARTLinearGradient.m in Sources */,
|
||||
325CF7AD1E5F2ABA00AC9606 /* ARTBrush.m in Sources */,
|
||||
325CF7B51E5F2ABA00AC9606 /* ARTShapeManager.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
0CF68AD31AF0540F00FF9E5C /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
0CF68AD41AF0540F00FF9E5C /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
0CF68AD61AF0540F00FF9E5C /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
0CF68AD71AF0540F00FF9E5C /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
323A128E1E5F266B004975B8 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
SKIP_INSTALL = YES;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.2;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
323A128F1E5F266B004975B8 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
SKIP_INSTALL = YES;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.2;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
0CF68ABC1AF0540F00FF9E5C /* Build configuration list for PBXProject "ART" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
0CF68AD31AF0540F00FF9E5C /* Debug */,
|
||||
0CF68AD41AF0540F00FF9E5C /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
0CF68AD51AF0540F00FF9E5C /* Build configuration list for PBXNativeTarget "ART" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
0CF68AD61AF0540F00FF9E5C /* Debug */,
|
||||
0CF68AD71AF0540F00FF9E5C /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
323A128D1E5F266B004975B8 /* Build configuration list for PBXNativeTarget "ART-tvOS" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
323A128E1E5F266B004975B8 /* Debug */,
|
||||
323A128F1E5F266B004975B8 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 0CF68AB91AF0540F00FF9E5C /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
// A little helper to make sure we have the right memory allocation ready for use.
|
||||
// We assume that we will only this in one place so no reference counting is necessary.
|
||||
// Needs to be freed when deallocated.
|
||||
|
||||
// This is fragile since this relies on these values not getting reused. Consider
|
||||
// wrapping these in an Obj-C class or some ARC hackery to get refcounting.
|
||||
|
||||
typedef struct {
|
||||
size_t count;
|
||||
CGFloat *array;
|
||||
} ARTCGFloatArray;
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its 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 ARTContainer <NSObject>
|
||||
|
||||
// This is used as a hook for child to mark it's parent as dirty.
|
||||
// This bubbles up to the root which gets marked as dirty.
|
||||
- (void)invalidate;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its 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>
|
||||
|
||||
#import "ARTContainer.h"
|
||||
#import "ARTNode.h"
|
||||
|
||||
@interface ARTGroup : ARTNode <ARTContainer>
|
||||
|
||||
@property (nonatomic, assign) CGRect clipping;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTGroup.h"
|
||||
|
||||
@implementation ARTGroup
|
||||
|
||||
- (void)renderLayerTo:(CGContextRef)context
|
||||
{
|
||||
|
||||
if (!CGRectIsEmpty(self.clipping)) {
|
||||
CGContextClipToRect(context, self.clipping);
|
||||
}
|
||||
|
||||
for (ARTNode *node in self.subviews) {
|
||||
[node renderTo:context];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <React/UIView+React.h>
|
||||
|
||||
/**
|
||||
* ART nodes are implemented as empty UIViews but this is just an implementation detail to fit
|
||||
* into the existing view management. They should also be shadow views and painted on a background
|
||||
* thread.
|
||||
*/
|
||||
|
||||
@interface ARTNode : UIView
|
||||
|
||||
@property (nonatomic, assign) CGFloat opacity;
|
||||
|
||||
- (void)invalidate;
|
||||
- (void)renderTo:(CGContextRef)context;
|
||||
|
||||
/**
|
||||
* renderTo will take opacity into account and draw renderLayerTo off-screen if there is opacity
|
||||
* specified, then composite that onto the context. renderLayerTo always draws at opacity=1.
|
||||
* @abstract
|
||||
*/
|
||||
- (void)renderLayerTo:(CGContextRef)context;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTNode.h"
|
||||
|
||||
#import "ARTContainer.h"
|
||||
|
||||
@implementation ARTNode
|
||||
|
||||
- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex
|
||||
{
|
||||
[super insertReactSubview:subview atIndex:atIndex];
|
||||
[self insertSubview:subview atIndex:atIndex];
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (void)removeReactSubview:(UIView *)subview
|
||||
{
|
||||
[super removeReactSubview:subview];
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (void)didUpdateReactSubviews
|
||||
{
|
||||
// Do nothing, as subviews are inserted by insertReactSubview:
|
||||
}
|
||||
|
||||
- (void)setOpacity:(CGFloat)opacity
|
||||
{
|
||||
[self invalidate];
|
||||
_opacity = opacity;
|
||||
}
|
||||
|
||||
- (void)setTransform:(CGAffineTransform)transform
|
||||
{
|
||||
[self invalidate];
|
||||
super.transform = transform;
|
||||
}
|
||||
|
||||
- (void)invalidate
|
||||
{
|
||||
id<ARTContainer> container = (id<ARTContainer>)self.superview;
|
||||
[container invalidate];
|
||||
}
|
||||
|
||||
- (void)renderTo:(CGContextRef)context
|
||||
{
|
||||
if (self.opacity <= 0) {
|
||||
// Nothing to paint
|
||||
return;
|
||||
}
|
||||
if (self.opacity >= 1) {
|
||||
// Just paint at full opacity
|
||||
CGContextSaveGState(context);
|
||||
CGContextConcatCTM(context, self.transform);
|
||||
CGContextSetAlpha(context, 1);
|
||||
[self renderLayerTo:context];
|
||||
CGContextRestoreGState(context);
|
||||
return;
|
||||
}
|
||||
// This needs to be painted on a layer before being composited.
|
||||
CGContextSaveGState(context);
|
||||
CGContextConcatCTM(context, self.transform);
|
||||
CGContextSetAlpha(context, self.opacity);
|
||||
CGContextBeginTransparencyLayer(context, NULL);
|
||||
[self renderLayerTo:context];
|
||||
CGContextEndTransparencyLayer(context);
|
||||
CGContextRestoreGState(context);
|
||||
}
|
||||
|
||||
- (void)renderLayerTo:(CGContextRef)context
|
||||
{
|
||||
// abstract
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its 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>
|
||||
|
||||
#import "ARTBrush.h"
|
||||
#import "ARTCGFloatArray.h"
|
||||
#import "ARTNode.h"
|
||||
|
||||
@interface ARTRenderable : ARTNode
|
||||
|
||||
@property (nonatomic, strong) ARTBrush *fill;
|
||||
@property (nonatomic, assign) CGColorRef stroke;
|
||||
@property (nonatomic, assign) CGFloat strokeWidth;
|
||||
@property (nonatomic, assign) CGLineCap strokeCap;
|
||||
@property (nonatomic, assign) CGLineJoin strokeJoin;
|
||||
@property (nonatomic, assign) ARTCGFloatArray strokeDash;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTRenderable.h"
|
||||
|
||||
@implementation ARTRenderable
|
||||
|
||||
- (void)setFill:(ARTBrush *)fill
|
||||
{
|
||||
[self invalidate];
|
||||
_fill = fill;
|
||||
}
|
||||
|
||||
- (void)setStroke:(CGColorRef)stroke
|
||||
{
|
||||
if (stroke == _stroke) {
|
||||
return;
|
||||
}
|
||||
[self invalidate];
|
||||
CGColorRelease(_stroke);
|
||||
_stroke = CGColorRetain(stroke);
|
||||
}
|
||||
|
||||
- (void)setStrokeWidth:(CGFloat)strokeWidth
|
||||
{
|
||||
[self invalidate];
|
||||
_strokeWidth = strokeWidth;
|
||||
}
|
||||
|
||||
- (void)setStrokeCap:(CGLineCap)strokeCap
|
||||
{
|
||||
[self invalidate];
|
||||
_strokeCap = strokeCap;
|
||||
}
|
||||
|
||||
- (void)setStrokeJoin:(CGLineJoin)strokeJoin
|
||||
{
|
||||
[self invalidate];
|
||||
_strokeJoin = strokeJoin;
|
||||
}
|
||||
|
||||
- (void)setStrokeDash:(ARTCGFloatArray)strokeDash
|
||||
{
|
||||
if (strokeDash.array == _strokeDash.array) {
|
||||
return;
|
||||
}
|
||||
if (_strokeDash.array) {
|
||||
free(_strokeDash.array);
|
||||
}
|
||||
[self invalidate];
|
||||
_strokeDash = strokeDash;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
CGColorRelease(_stroke);
|
||||
if (_strokeDash.array) {
|
||||
free(_strokeDash.array);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)renderTo:(CGContextRef)context
|
||||
{
|
||||
if (self.opacity <= 0 || self.opacity >= 1 || (self.fill && self.stroke)) {
|
||||
// If we have both fill and stroke, we will need to paint this using normal compositing
|
||||
[super renderTo: context];
|
||||
return;
|
||||
}
|
||||
// This is a terminal with only one painting. Therefore we don't need to paint this
|
||||
// off-screen. We can just composite it straight onto the buffer.
|
||||
CGContextSaveGState(context);
|
||||
CGContextConcatCTM(context, self.transform);
|
||||
CGContextSetAlpha(context, self.opacity);
|
||||
[self renderLayerTo:context];
|
||||
CGContextRestoreGState(context);
|
||||
}
|
||||
|
||||
- (void)renderLayerTo:(CGContextRef)context
|
||||
{
|
||||
// abstract
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its 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';
|
||||
|
||||
// TODO: Move this into an ART mode called "serialized" or something
|
||||
|
||||
const Class = require('art/core/class.js');
|
||||
const Path = require('art/core/path.js');
|
||||
|
||||
const MOVE_TO = 0;
|
||||
const CLOSE = 1;
|
||||
const LINE_TO = 2;
|
||||
const CURVE_TO = 3;
|
||||
const ARC = 4;
|
||||
|
||||
const SerializablePath = Class(Path, {
|
||||
initialize: function(path) {
|
||||
this.reset();
|
||||
if (path instanceof SerializablePath) {
|
||||
this.path = path.path.slice(0);
|
||||
} else if (path) {
|
||||
if (path.applyToPath) {
|
||||
path.applyToPath(this);
|
||||
} else {
|
||||
this.push(path);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onReset: function() {
|
||||
this.path = [];
|
||||
},
|
||||
|
||||
onMove: function(sx, sy, x, y) {
|
||||
this.path.push(MOVE_TO, x, y);
|
||||
},
|
||||
|
||||
onLine: function(sx, sy, x, y) {
|
||||
this.path.push(LINE_TO, x, y);
|
||||
},
|
||||
|
||||
onBezierCurve: function(sx, sy, p1x, p1y, p2x, p2y, x, y) {
|
||||
this.path.push(CURVE_TO, p1x, p1y, p2x, p2y, x, y);
|
||||
},
|
||||
|
||||
_arcToBezier: Path.prototype.onArc,
|
||||
|
||||
onArc: function(sx, sy, ex, ey, cx, cy, rx, ry, sa, ea, ccw, rotation) {
|
||||
if (rx !== ry || rotation) {
|
||||
return this._arcToBezier(
|
||||
sx,
|
||||
sy,
|
||||
ex,
|
||||
ey,
|
||||
cx,
|
||||
cy,
|
||||
rx,
|
||||
ry,
|
||||
sa,
|
||||
ea,
|
||||
ccw,
|
||||
rotation,
|
||||
);
|
||||
}
|
||||
this.path.push(ARC, cx, cy, rx, sa, ea, ccw ? 0 : 1);
|
||||
},
|
||||
|
||||
onClose: function() {
|
||||
this.path.push(CLOSE);
|
||||
},
|
||||
|
||||
toJSON: function() {
|
||||
return this.path;
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = SerializablePath;
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its 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>
|
||||
|
||||
#import "ARTRenderable.h"
|
||||
|
||||
@interface ARTShape : ARTRenderable
|
||||
|
||||
@property (nonatomic, assign) CGPathRef d;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTShape.h"
|
||||
|
||||
@implementation ARTShape
|
||||
|
||||
- (void)setD:(CGPathRef)d
|
||||
{
|
||||
if (d == _d) {
|
||||
return;
|
||||
}
|
||||
[self invalidate];
|
||||
CGPathRelease(_d);
|
||||
_d = CGPathRetain(d);
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
CGPathRelease(_d);
|
||||
}
|
||||
|
||||
- (void)renderLayerTo:(CGContextRef)context
|
||||
{
|
||||
if ((!self.fill && !self.stroke) || !self.d) {
|
||||
return;
|
||||
}
|
||||
|
||||
CGPathDrawingMode mode = kCGPathStroke;
|
||||
if (self.fill) {
|
||||
if ([self.fill applyFillColor:context]) {
|
||||
mode = kCGPathFill;
|
||||
} else {
|
||||
CGContextSaveGState(context);
|
||||
CGContextAddPath(context, self.d);
|
||||
CGContextClip(context);
|
||||
[self.fill paint:context];
|
||||
CGContextRestoreGState(context);
|
||||
if (!self.stroke) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (self.stroke) {
|
||||
CGContextSetStrokeColorWithColor(context, self.stroke);
|
||||
CGContextSetLineWidth(context, self.strokeWidth);
|
||||
CGContextSetLineCap(context, self.strokeCap);
|
||||
CGContextSetLineJoin(context, self.strokeJoin);
|
||||
ARTCGFloatArray dash = self.strokeDash;
|
||||
if (dash.count) {
|
||||
CGContextSetLineDash(context, 0, dash.array, dash.count);
|
||||
}
|
||||
if (mode == kCGPathFill) {
|
||||
mode = kCGPathFillStroke;
|
||||
}
|
||||
}
|
||||
|
||||
CGContextAddPath(context, self.d);
|
||||
CGContextDrawPath(context, mode);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "ARTContainer.h"
|
||||
|
||||
@interface ARTSurfaceView : UIView <ARTContainer>
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTSurfaceView.h"
|
||||
|
||||
#import <React/RCTLog.h>
|
||||
|
||||
#import "ARTNode.h"
|
||||
|
||||
@implementation ARTSurfaceView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
self.opaque = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex
|
||||
{
|
||||
[super insertReactSubview:subview atIndex:atIndex];
|
||||
[self insertSubview:subview atIndex:atIndex];
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (void)removeReactSubview:(UIView *)subview
|
||||
{
|
||||
[super removeReactSubview:subview];
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (void)didUpdateReactSubviews
|
||||
{
|
||||
// Do nothing, as subviews are inserted by insertReactSubview:
|
||||
}
|
||||
|
||||
- (void)invalidate
|
||||
{
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)rect
|
||||
{
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
for (ARTNode *node in self.subviews) {
|
||||
[node renderTo:context];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its 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>
|
||||
|
||||
#import "ARTRenderable.h"
|
||||
#import "ARTTextFrame.h"
|
||||
|
||||
@interface ARTText : ARTRenderable
|
||||
|
||||
@property (nonatomic, assign) CTTextAlignment alignment;
|
||||
@property (nonatomic, assign) ARTTextFrame textFrame;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTText.h"
|
||||
|
||||
#import <CoreText/CoreText.h>
|
||||
|
||||
@implementation ARTText
|
||||
|
||||
- (void)setAlignment:(CTTextAlignment)alignment
|
||||
{
|
||||
[self invalidate];
|
||||
_alignment = alignment;
|
||||
}
|
||||
|
||||
static void ARTFreeTextFrame(ARTTextFrame frame)
|
||||
{
|
||||
if (frame.count) {
|
||||
// We must release each line before freeing up this struct
|
||||
for (int i = 0; i < frame.count; i++) {
|
||||
CFRelease(frame.lines[i]);
|
||||
}
|
||||
free(frame.lines);
|
||||
free(frame.widths);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setTextFrame:(ARTTextFrame)frame
|
||||
{
|
||||
if (frame.lines != _textFrame.lines) {
|
||||
ARTFreeTextFrame(_textFrame);
|
||||
}
|
||||
[self invalidate];
|
||||
_textFrame = frame;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
ARTFreeTextFrame(_textFrame);
|
||||
}
|
||||
|
||||
- (void)renderLayerTo:(CGContextRef)context
|
||||
{
|
||||
ARTTextFrame frame = self.textFrame;
|
||||
|
||||
if ((!self.fill && !self.stroke) || !frame.count) {
|
||||
return;
|
||||
}
|
||||
|
||||
// to-do: draw along a path
|
||||
|
||||
CGTextDrawingMode mode = kCGTextStroke;
|
||||
if (self.fill) {
|
||||
if ([self.fill applyFillColor:context]) {
|
||||
mode = kCGTextFill;
|
||||
} else {
|
||||
|
||||
for (int i = 0; i < frame.count; i++) {
|
||||
CGContextSaveGState(context);
|
||||
// Inverse the coordinate space since CoreText assumes a bottom-up coordinate space
|
||||
CGContextScaleCTM(context, 1.0, -1.0);
|
||||
CGContextSetTextDrawingMode(context, kCGTextClip);
|
||||
[self renderLineTo:context atIndex:i];
|
||||
// Inverse the coordinate space back to the original before filling
|
||||
CGContextScaleCTM(context, 1.0, -1.0);
|
||||
[self.fill paint:context];
|
||||
// Restore the state so that the next line can be clipped separately
|
||||
CGContextRestoreGState(context);
|
||||
}
|
||||
|
||||
if (!self.stroke) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (self.stroke) {
|
||||
CGContextSetStrokeColorWithColor(context, self.stroke);
|
||||
CGContextSetLineWidth(context, self.strokeWidth);
|
||||
CGContextSetLineCap(context, self.strokeCap);
|
||||
CGContextSetLineJoin(context, self.strokeJoin);
|
||||
ARTCGFloatArray dash = self.strokeDash;
|
||||
if (dash.count) {
|
||||
CGContextSetLineDash(context, 0, dash.array, dash.count);
|
||||
}
|
||||
if (mode == kCGTextFill) {
|
||||
mode = kCGTextFillStroke;
|
||||
}
|
||||
}
|
||||
|
||||
CGContextSetTextDrawingMode(context, mode);
|
||||
|
||||
// Inverse the coordinate space since CoreText assumes a bottom-up coordinate space
|
||||
CGContextScaleCTM(context, 1.0, -1.0);
|
||||
for (int i = 0; i < frame.count; i++) {
|
||||
[self renderLineTo:context atIndex:i];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)renderLineTo:(CGContextRef)context atIndex:(int)index
|
||||
{
|
||||
ARTTextFrame frame = self.textFrame;
|
||||
CGFloat shift;
|
||||
switch (self.alignment) {
|
||||
case kCTTextAlignmentRight:
|
||||
shift = frame.widths[index];
|
||||
break;
|
||||
case kCTTextAlignmentCenter:
|
||||
shift = (frame.widths[index] / 2);
|
||||
break;
|
||||
default:
|
||||
shift = 0;
|
||||
break;
|
||||
}
|
||||
// We should consider snapping this shift to device pixels to improve rendering quality
|
||||
// when a line has subpixel width.
|
||||
CGContextSetTextPosition(context, -shift, -frame.baseLine - frame.lineHeight * index);
|
||||
CTLineRef line = frame.lines[index];
|
||||
CTLineDraw(line, context);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <CoreText/CoreText.h>
|
||||
|
||||
// A little helper to make sure we have a set of lines including width ready for use.
|
||||
// We assume that we will only this in one place so no reference counting is necessary.
|
||||
// Needs to be freed when deallocated.
|
||||
|
||||
// This is fragile since this relies on these values not getting reused. Consider
|
||||
// wrapping these in an Obj-C class or some ARC hackery to get refcounting.
|
||||
|
||||
typedef struct {
|
||||
size_t count;
|
||||
CGFloat baseLine; // Distance from the origin to the base line of the first line
|
||||
CGFloat lineHeight; // Distance between lines
|
||||
CTLineRef *lines;
|
||||
CGFloat *widths; // Width of each line
|
||||
} ARTTextFrame;
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface ARTBrush : NSObject
|
||||
|
||||
/* @abstract */
|
||||
- (instancetype)initWithArray:(NSArray *)data NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* For certain brushes we can fast path a combined fill and stroke.
|
||||
* For those brushes we override applyFillColor which sets the fill
|
||||
* color to be used by those batch paints. Those return YES.
|
||||
* We can't batch gradient painting in CoreGraphics, so those will
|
||||
* return NO and paint gets called instead.
|
||||
* @abstract
|
||||
*/
|
||||
- (BOOL)applyFillColor:(CGContextRef)context;
|
||||
|
||||
/**
|
||||
* paint fills the context with a brush. The context is assumed to
|
||||
* be clipped.
|
||||
* @abstract
|
||||
*/
|
||||
- (void)paint:(CGContextRef)context;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTBrush.h"
|
||||
|
||||
#import <React/RCTDefines.h>
|
||||
|
||||
@implementation ARTBrush
|
||||
|
||||
- (instancetype)initWithArray:(NSArray *)data
|
||||
{
|
||||
return [super init];
|
||||
}
|
||||
|
||||
RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||
|
||||
- (BOOL)applyFillColor:(CGContextRef)context
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)paint:(CGContextRef)context
|
||||
{
|
||||
// abstract
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTBrush.h"
|
||||
|
||||
@interface ARTLinearGradient : ARTBrush
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTLinearGradient.h"
|
||||
|
||||
#import <React/RCTLog.h>
|
||||
|
||||
#import "RCTConvert+ART.h"
|
||||
|
||||
@implementation ARTLinearGradient
|
||||
{
|
||||
CGGradientRef _gradient;
|
||||
CGPoint _startPoint;
|
||||
CGPoint _endPoint;
|
||||
}
|
||||
|
||||
- (instancetype)initWithArray:(NSArray<NSNumber *> *)array
|
||||
{
|
||||
if ((self = [super initWithArray:array])) {
|
||||
if (array.count < 5) {
|
||||
RCTLogError(@"-[%@ %@] expects 5 elements, received %@",
|
||||
self.class, NSStringFromSelector(_cmd), array);
|
||||
return nil;
|
||||
}
|
||||
_startPoint = [RCTConvert CGPoint:array offset:1];
|
||||
_endPoint = [RCTConvert CGPoint:array offset:3];
|
||||
_gradient = CGGradientRetain([RCTConvert CGGradient:array offset:5]);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
CGGradientRelease(_gradient);
|
||||
}
|
||||
|
||||
- (void)paint:(CGContextRef)context
|
||||
{
|
||||
CGGradientDrawingOptions extendOptions =
|
||||
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
|
||||
CGContextDrawLinearGradient(context, _gradient, _startPoint, _endPoint, extendOptions);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTBrush.h"
|
||||
|
||||
@interface ARTPattern : ARTBrush
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTPattern.h"
|
||||
|
||||
#import <React/RCTLog.h>
|
||||
|
||||
#import "RCTConvert+ART.h"
|
||||
|
||||
@implementation ARTPattern
|
||||
{
|
||||
CGImageRef _image;
|
||||
CGRect _rect;
|
||||
}
|
||||
|
||||
- (instancetype)initWithArray:(NSArray<id /* imagesource + numbers */> *)array
|
||||
{
|
||||
if ((self = [super initWithArray:array])) {
|
||||
if (array.count < 6) {
|
||||
RCTLogError(@"-[%@ %@] expects 6 elements, received %@",
|
||||
self.class, NSStringFromSelector(_cmd), array);
|
||||
return nil;
|
||||
}
|
||||
_image = CGImageRetain([RCTConvert CGImage:array[1]]);
|
||||
_rect = [RCTConvert CGRect:array offset:2];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
CGImageRelease(_image);
|
||||
}
|
||||
|
||||
// Note: This could use applyFillColor with a pattern. This could be more efficient but
|
||||
// to do that, we need to calculate our own user space CTM.
|
||||
|
||||
- (void)paint:(CGContextRef)context
|
||||
{
|
||||
CGContextDrawTiledImage(context, _rect, _image);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTBrush.h"
|
||||
|
||||
@interface ARTRadialGradient : ARTBrush
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTRadialGradient.h"
|
||||
|
||||
#import <React/RCTLog.h>
|
||||
|
||||
#import "RCTConvert+ART.h"
|
||||
|
||||
@implementation ARTRadialGradient
|
||||
{
|
||||
CGGradientRef _gradient;
|
||||
CGPoint _focusPoint;
|
||||
CGPoint _centerPoint;
|
||||
CGFloat _radius;
|
||||
CGFloat _radiusRatio;
|
||||
}
|
||||
|
||||
- (instancetype)initWithArray:(NSArray<NSNumber *> *)array
|
||||
{
|
||||
if ((self = [super initWithArray:array])) {
|
||||
if (array.count < 7) {
|
||||
RCTLogError(@"-[%@ %@] expects 7 elements, received %@",
|
||||
self.class, NSStringFromSelector(_cmd), array);
|
||||
return nil;
|
||||
}
|
||||
_radius = [RCTConvert CGFloat:array[3]];
|
||||
_radiusRatio = [RCTConvert CGFloat:array[4]] / _radius;
|
||||
_focusPoint.x = [RCTConvert CGFloat:array[1]];
|
||||
_focusPoint.y = [RCTConvert CGFloat:array[2]] / _radiusRatio;
|
||||
_centerPoint.x = [RCTConvert CGFloat:array[5]];
|
||||
_centerPoint.y = [RCTConvert CGFloat:array[6]] / _radiusRatio;
|
||||
_gradient = CGGradientRetain([RCTConvert CGGradient:array offset:7]);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
CGGradientRelease(_gradient);
|
||||
}
|
||||
|
||||
- (void)paint:(CGContextRef)context
|
||||
{
|
||||
CGAffineTransform transform = CGAffineTransformMakeScale(1, _radiusRatio);
|
||||
CGContextConcatCTM(context, transform);
|
||||
CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
|
||||
CGContextDrawRadialGradient(context, _gradient, _focusPoint, 0, _centerPoint, _radius, extendOptions);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTBrush.h"
|
||||
|
||||
@interface ARTSolidColor : ARTBrush
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTSolidColor.h"
|
||||
|
||||
#import <React/RCTLog.h>
|
||||
|
||||
#import "RCTConvert+ART.h"
|
||||
|
||||
@implementation ARTSolidColor
|
||||
{
|
||||
CGColorRef _color;
|
||||
}
|
||||
|
||||
- (instancetype)initWithArray:(NSArray<NSNumber *> *)array
|
||||
{
|
||||
if ((self = [super initWithArray:array])) {
|
||||
_color = CGColorRetain([RCTConvert CGColor:array offset:1]);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
CGColorRelease(_color);
|
||||
}
|
||||
|
||||
- (BOOL)applyFillColor:(CGContextRef)context
|
||||
{
|
||||
CGContextSetFillColorWithColor(context, _color);
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
#import <React/RCTConvert.h>
|
||||
|
||||
#import "ARTBrush.h"
|
||||
#import "ARTCGFloatArray.h"
|
||||
#import "ARTTextFrame.h"
|
||||
|
||||
@interface RCTConvert (ART)
|
||||
|
||||
+ (CGPathRef)CGPath:(id)json CF_RETURNS_NOT_RETAINED;
|
||||
+ (CTTextAlignment)CTTextAlignment:(id)json;
|
||||
+ (ARTTextFrame)ARTTextFrame:(id)json;
|
||||
+ (ARTCGFloatArray)ARTCGFloatArray:(id)json;
|
||||
+ (ARTBrush *)ARTBrush:(id)json;
|
||||
|
||||
+ (CGPoint)CGPoint:(id)json offset:(NSUInteger)offset;
|
||||
+ (CGRect)CGRect:(id)json offset:(NSUInteger)offset;
|
||||
+ (CGColorRef)CGColor:(id)json offset:(NSUInteger)offset CF_RETURNS_NOT_RETAINED;
|
||||
+ (CGGradientRef)CGGradient:(id)json offset:(NSUInteger)offset CF_RETURNS_NOT_RETAINED;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "RCTConvert+ART.h"
|
||||
|
||||
#import <React/RCTFont.h>
|
||||
#import <React/RCTLog.h>
|
||||
|
||||
#import "ARTLinearGradient.h"
|
||||
#import "ARTPattern.h"
|
||||
#import "ARTRadialGradient.h"
|
||||
#import "ARTSolidColor.h"
|
||||
|
||||
@implementation RCTConvert (ART)
|
||||
|
||||
+ (CGPathRef)CGPath:(id)json
|
||||
{
|
||||
NSArray *arr = [self NSNumberArray:json];
|
||||
|
||||
NSUInteger count = [arr count];
|
||||
|
||||
#define NEXT_VALUE [self double:arr[i++]]
|
||||
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
CGPathMoveToPoint(path, NULL, 0, 0);
|
||||
|
||||
@try {
|
||||
NSUInteger i = 0;
|
||||
while (i < count) {
|
||||
NSUInteger type = [arr[i++] unsignedIntegerValue];
|
||||
switch (type) {
|
||||
case 0:
|
||||
CGPathMoveToPoint(path, NULL, NEXT_VALUE, NEXT_VALUE);
|
||||
break;
|
||||
case 1:
|
||||
CGPathCloseSubpath(path);
|
||||
break;
|
||||
case 2:
|
||||
CGPathAddLineToPoint(path, NULL, NEXT_VALUE, NEXT_VALUE);
|
||||
break;
|
||||
case 3:
|
||||
CGPathAddCurveToPoint(path, NULL, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE);
|
||||
break;
|
||||
case 4:
|
||||
CGPathAddArc(path, NULL, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE == 0);
|
||||
break;
|
||||
default:
|
||||
RCTLogError(@"Invalid CGPath type %llu at element %llu of %@", (unsigned long long)type, (unsigned long long)i, arr);
|
||||
CGPathRelease(path);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
RCTLogError(@"Invalid CGPath format: %@", arr);
|
||||
CGPathRelease(path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (CGPathRef)CFAutorelease(path);
|
||||
}
|
||||
|
||||
RCT_ENUM_CONVERTER(CTTextAlignment, (@{
|
||||
@"auto": @(kCTTextAlignmentNatural),
|
||||
@"left": @(kCTTextAlignmentLeft),
|
||||
@"center": @(kCTTextAlignmentCenter),
|
||||
@"right": @(kCTTextAlignmentRight),
|
||||
@"justify": @(kCTTextAlignmentJustified),
|
||||
}), kCTTextAlignmentNatural, integerValue)
|
||||
|
||||
// This takes a tuple of text lines and a font to generate a CTLine for each text line.
|
||||
// This prepares everything for rendering a frame of text in ARTText.
|
||||
+ (ARTTextFrame)ARTTextFrame:(id)json
|
||||
{
|
||||
NSDictionary *dict = [self NSDictionary:json];
|
||||
ARTTextFrame frame;
|
||||
frame.count = 0;
|
||||
|
||||
NSArray *lines = [self NSArray:dict[@"lines"]];
|
||||
NSUInteger lineCount = [lines count];
|
||||
if (lineCount == 0) {
|
||||
return frame;
|
||||
}
|
||||
|
||||
CTFontRef font = (__bridge CTFontRef)[self UIFont:dict[@"font"]];
|
||||
if (!font) {
|
||||
return frame;
|
||||
}
|
||||
|
||||
// Create a dictionary for this font
|
||||
CFDictionaryRef attributes = (__bridge CFDictionaryRef)@{
|
||||
(NSString *)kCTFontAttributeName:(__bridge id)font,
|
||||
(NSString *)kCTForegroundColorFromContextAttributeName: @YES
|
||||
};
|
||||
|
||||
// Set up text frame with font metrics
|
||||
CGFloat size = CTFontGetSize(font);
|
||||
frame.count = lineCount;
|
||||
frame.baseLine = size; // estimate base line
|
||||
frame.lineHeight = size * 1.1; // Base on ART canvas line height estimate
|
||||
frame.lines = malloc(sizeof(CTLineRef) * lineCount);
|
||||
frame.widths = malloc(sizeof(CGFloat) * lineCount);
|
||||
|
||||
[lines enumerateObjectsUsingBlock:^(NSString *text, NSUInteger i, BOOL *stop) {
|
||||
|
||||
CFStringRef string = (__bridge CFStringRef)text;
|
||||
CFAttributedStringRef attrString = CFAttributedStringCreate(kCFAllocatorDefault, string, attributes);
|
||||
CTLineRef line = CTLineCreateWithAttributedString(attrString);
|
||||
CFRelease(attrString);
|
||||
|
||||
frame.lines[i] = line;
|
||||
frame.widths[i] = CTLineGetTypographicBounds(line, NULL, NULL, NULL);
|
||||
}];
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
+ (ARTCGFloatArray)ARTCGFloatArray:(id)json
|
||||
{
|
||||
NSArray *arr = [self NSNumberArray:json];
|
||||
NSUInteger count = arr.count;
|
||||
|
||||
ARTCGFloatArray array;
|
||||
array.count = count;
|
||||
array.array = NULL;
|
||||
|
||||
if (count) {
|
||||
// Ideally, these arrays should already use the same memory layout.
|
||||
// In that case we shouldn't need this new malloc.
|
||||
array.array = malloc(sizeof(CGFloat) * count);
|
||||
for (NSUInteger i = 0; i < count; i++) {
|
||||
array.array[i] = [arr[i] doubleValue];
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
+ (ARTBrush *)ARTBrush:(id)json
|
||||
{
|
||||
NSArray *arr = [self NSArray:json];
|
||||
NSUInteger type = [self NSUInteger:arr.firstObject];
|
||||
switch (type) {
|
||||
case 0: // solid color
|
||||
// These are probably expensive allocations since it's often the same value.
|
||||
// We should memoize colors but look ups may be just as expensive.
|
||||
return [[ARTSolidColor alloc] initWithArray:arr];
|
||||
case 1: // linear gradient
|
||||
return [[ARTLinearGradient alloc] initWithArray:arr];
|
||||
case 2: // radial gradient
|
||||
return [[ARTRadialGradient alloc] initWithArray:arr];
|
||||
case 3: // pattern
|
||||
return [[ARTPattern alloc] initWithArray:arr];
|
||||
default:
|
||||
RCTLogError(@"Unknown brush type: %llu", (unsigned long long)type);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
+ (CGPoint)CGPoint:(id)json offset:(NSUInteger)offset
|
||||
{
|
||||
NSArray *arr = [self NSArray:json];
|
||||
if (arr.count < offset + 2) {
|
||||
RCTLogError(@"Too few elements in array (expected at least %llu): %@", (unsigned long long)(2 + offset), arr);
|
||||
return CGPointZero;
|
||||
}
|
||||
return (CGPoint){
|
||||
[self CGFloat:arr[offset]],
|
||||
[self CGFloat:arr[offset + 1]],
|
||||
};
|
||||
}
|
||||
|
||||
+ (CGRect)CGRect:(id)json offset:(NSUInteger)offset
|
||||
{
|
||||
NSArray *arr = [self NSArray:json];
|
||||
if (arr.count < offset + 4) {
|
||||
RCTLogError(@"Too few elements in array (expected at least %llu): %@", (unsigned long long)(4 + offset), arr);
|
||||
return CGRectZero;
|
||||
}
|
||||
return (CGRect){
|
||||
{[self CGFloat:arr[offset]], [self CGFloat:arr[offset + 1]]},
|
||||
{[self CGFloat:arr[offset + 2]], [self CGFloat:arr[offset + 3]]},
|
||||
};
|
||||
}
|
||||
|
||||
+ (CGColorRef)CGColor:(id)json offset:(NSUInteger)offset
|
||||
{
|
||||
NSArray *arr = [self NSArray:json];
|
||||
if (arr.count < offset + 4) {
|
||||
RCTLogError(@"Too few elements in array (expected at least %llu): %@", (unsigned long long)(4 + offset), arr);
|
||||
return NULL;
|
||||
}
|
||||
return [self CGColor:[arr subarrayWithRange:(NSRange){offset, 4}]];
|
||||
}
|
||||
|
||||
+ (CGGradientRef)CGGradient:(id)json offset:(NSUInteger)offset
|
||||
{
|
||||
NSArray *arr = [self NSArray:json];
|
||||
if (arr.count < offset) {
|
||||
RCTLogError(@"Too few elements in array (expected at least %llu): %@", (unsigned long long)offset, arr);
|
||||
return NULL;
|
||||
}
|
||||
arr = [arr subarrayWithRange:(NSRange){offset, arr.count - offset}];
|
||||
ARTCGFloatArray colorsAndOffsets = [self ARTCGFloatArray:arr];
|
||||
size_t stops = colorsAndOffsets.count / 5;
|
||||
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
|
||||
CGGradientRef gradient = CGGradientCreateWithColorComponents(
|
||||
rgb,
|
||||
colorsAndOffsets.array,
|
||||
colorsAndOffsets.array + stops * 4,
|
||||
stops
|
||||
);
|
||||
CGColorSpaceRelease(rgb);
|
||||
free(colorsAndOffsets.array);
|
||||
return (CGGradientRef)CFAutorelease(gradient);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,34 @@
|
||||
# coding: utf-8
|
||||
# Copyright (c) Facebook, Inc. and its affiliates.
|
||||
#
|
||||
# This source code is licensed under the MIT license found in the
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
|
||||
require "json"
|
||||
|
||||
package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json")))
|
||||
version = package['version']
|
||||
|
||||
source = { :git => 'https://github.com/facebook/react-native.git' }
|
||||
if version == '1000.0.0'
|
||||
# This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in.
|
||||
source[:commit] = `git rev-parse HEAD`.strip
|
||||
else
|
||||
source[:tag] = "v#{version}"
|
||||
end
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "React-ART"
|
||||
s.version = version
|
||||
s.summary = "A library for drawing vector graphics."
|
||||
s.homepage = "http://facebook.github.io/react-native/"
|
||||
s.license = package["license"]
|
||||
s.author = "Facebook, Inc. and its affiliates"
|
||||
s.platforms = { :ios => "9.0", :tvos => "9.2" }
|
||||
s.source = source
|
||||
s.source_files = "**/*.{h,m}"
|
||||
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
|
||||
s.header_dir = "React"
|
||||
|
||||
s.dependency "React-Core", version
|
||||
end
|
||||
@@ -0,0 +1,612 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its 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 Color = require('art/core/color');
|
||||
const Path = require('./ARTSerializablePath');
|
||||
const Transform = require('art/core/transform');
|
||||
|
||||
const React = require('react');
|
||||
const PropTypes = require('prop-types');
|
||||
const ReactNativeViewAttributes = require('../Components/View/ReactNativeViewAttributes');
|
||||
|
||||
const createReactNativeComponentClass = require('../Renderer/shims/createReactNativeComponentClass');
|
||||
const merge = require('../vendor/core/merge');
|
||||
const invariant = require('invariant');
|
||||
|
||||
// Diff Helpers
|
||||
|
||||
function arrayDiffer(a, b) {
|
||||
if (a == null || b == null) {
|
||||
return true;
|
||||
}
|
||||
if (a.length !== b.length) {
|
||||
return true;
|
||||
}
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (a[i] !== b[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function fontAndLinesDiffer(a, b) {
|
||||
if (a === b) {
|
||||
return false;
|
||||
}
|
||||
if (a.font !== b.font) {
|
||||
if (a.font === null) {
|
||||
return true;
|
||||
}
|
||||
if (b.font === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
a.font.fontFamily !== b.font.fontFamily ||
|
||||
a.font.fontSize !== b.font.fontSize ||
|
||||
a.font.fontWeight !== b.font.fontWeight ||
|
||||
a.font.fontStyle !== b.font.fontStyle
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return arrayDiffer(a.lines, b.lines);
|
||||
}
|
||||
|
||||
// Native Attributes
|
||||
|
||||
const SurfaceViewAttributes = merge(ReactNativeViewAttributes.UIView, {
|
||||
// This should contain pixel information such as width, height and
|
||||
// resolution to know what kind of buffer needs to be allocated.
|
||||
// Currently we rely on UIViews and style to figure that out.
|
||||
});
|
||||
|
||||
const NodeAttributes = {
|
||||
transform: {diff: arrayDiffer},
|
||||
opacity: true,
|
||||
};
|
||||
|
||||
const GroupAttributes = merge(NodeAttributes, {
|
||||
clipping: {diff: arrayDiffer},
|
||||
});
|
||||
|
||||
const RenderableAttributes = merge(NodeAttributes, {
|
||||
fill: {diff: arrayDiffer},
|
||||
stroke: {diff: arrayDiffer},
|
||||
strokeWidth: true,
|
||||
strokeCap: true,
|
||||
strokeJoin: true,
|
||||
strokeDash: {diff: arrayDiffer},
|
||||
});
|
||||
|
||||
const ShapeAttributes = merge(RenderableAttributes, {
|
||||
d: {diff: arrayDiffer},
|
||||
});
|
||||
|
||||
const TextAttributes = merge(RenderableAttributes, {
|
||||
alignment: true,
|
||||
frame: {diff: fontAndLinesDiffer},
|
||||
path: {diff: arrayDiffer},
|
||||
});
|
||||
|
||||
// Native Components
|
||||
|
||||
const NativeSurfaceView = createReactNativeComponentClass(
|
||||
'ARTSurfaceView',
|
||||
() => ({
|
||||
validAttributes: SurfaceViewAttributes,
|
||||
uiViewClassName: 'ARTSurfaceView',
|
||||
}),
|
||||
);
|
||||
|
||||
const NativeGroup = createReactNativeComponentClass('ARTGroup', () => ({
|
||||
validAttributes: GroupAttributes,
|
||||
uiViewClassName: 'ARTGroup',
|
||||
}));
|
||||
|
||||
const NativeShape = createReactNativeComponentClass('ARTShape', () => ({
|
||||
validAttributes: ShapeAttributes,
|
||||
uiViewClassName: 'ARTShape',
|
||||
}));
|
||||
|
||||
const NativeText = createReactNativeComponentClass('ARTText', () => ({
|
||||
validAttributes: TextAttributes,
|
||||
uiViewClassName: 'ARTText',
|
||||
}));
|
||||
|
||||
// Utilities
|
||||
|
||||
function childrenAsString(children) {
|
||||
if (!children) {
|
||||
return '';
|
||||
}
|
||||
if (typeof children === 'string') {
|
||||
return children;
|
||||
}
|
||||
if (children.length) {
|
||||
return children.join('\n');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// Surface - Root node of all ART
|
||||
|
||||
class Surface extends React.Component {
|
||||
static childContextTypes = {
|
||||
isInSurface: PropTypes.bool,
|
||||
};
|
||||
|
||||
getChildContext() {
|
||||
return {isInSurface: true};
|
||||
}
|
||||
|
||||
render() {
|
||||
const height = extractNumber(this.props.height, 0);
|
||||
const width = extractNumber(this.props.width, 0);
|
||||
|
||||
return (
|
||||
<NativeSurfaceView style={[this.props.style, {height, width}]}>
|
||||
{this.props.children}
|
||||
</NativeSurfaceView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Node Props
|
||||
|
||||
// TODO: The desktop version of ART has title and cursor. We should have
|
||||
// accessibility support here too even though hovering doesn't work.
|
||||
|
||||
function extractNumber(value, defaultValue) {
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return +value;
|
||||
}
|
||||
|
||||
const pooledTransform = new Transform();
|
||||
|
||||
function extractTransform(props) {
|
||||
const scaleX =
|
||||
props.scaleX != null ? props.scaleX : props.scale != null ? props.scale : 1;
|
||||
const scaleY =
|
||||
props.scaleY != null ? props.scaleY : props.scale != null ? props.scale : 1;
|
||||
|
||||
pooledTransform
|
||||
.transformTo(1, 0, 0, 1, 0, 0)
|
||||
.move(props.x || 0, props.y || 0)
|
||||
.rotate(props.rotation || 0, props.originX, props.originY)
|
||||
.scale(scaleX, scaleY, props.originX, props.originY);
|
||||
|
||||
if (props.transform != null) {
|
||||
pooledTransform.transform(props.transform);
|
||||
}
|
||||
|
||||
return [
|
||||
pooledTransform.xx,
|
||||
pooledTransform.yx,
|
||||
pooledTransform.xy,
|
||||
pooledTransform.yy,
|
||||
pooledTransform.x,
|
||||
pooledTransform.y,
|
||||
];
|
||||
}
|
||||
|
||||
function extractOpacity(props) {
|
||||
// TODO: visible === false should also have no hit detection
|
||||
if (props.visible === false) {
|
||||
return 0;
|
||||
}
|
||||
if (props.opacity == null) {
|
||||
return 1;
|
||||
}
|
||||
return +props.opacity;
|
||||
}
|
||||
|
||||
// Groups
|
||||
|
||||
// Note: ART has a notion of width and height on Group but AFAIK it's a noop in
|
||||
// ReactART.
|
||||
|
||||
class Group extends React.Component {
|
||||
static contextTypes = {
|
||||
isInSurface: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
const props = this.props;
|
||||
invariant(
|
||||
this.context.isInSurface,
|
||||
'ART: <Group /> must be a child of a <Surface />',
|
||||
);
|
||||
return (
|
||||
<NativeGroup
|
||||
opacity={extractOpacity(props)}
|
||||
transform={extractTransform(props)}>
|
||||
{this.props.children}
|
||||
</NativeGroup>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ClippingRectangle extends React.Component {
|
||||
render() {
|
||||
const props = this.props;
|
||||
const x = extractNumber(props.x, 0);
|
||||
const y = extractNumber(props.y, 0);
|
||||
const w = extractNumber(props.width, 0);
|
||||
const h = extractNumber(props.height, 0);
|
||||
const clipping = [x, y, w, h];
|
||||
// The current clipping API requires x and y to be ignored in the transform
|
||||
const propsExcludingXAndY = merge(props);
|
||||
delete propsExcludingXAndY.x;
|
||||
delete propsExcludingXAndY.y;
|
||||
return (
|
||||
<NativeGroup
|
||||
clipping={clipping}
|
||||
opacity={extractOpacity(props)}
|
||||
transform={extractTransform(propsExcludingXAndY)}>
|
||||
{this.props.children}
|
||||
</NativeGroup>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Renderables
|
||||
|
||||
const SOLID_COLOR = 0;
|
||||
const LINEAR_GRADIENT = 1;
|
||||
const RADIAL_GRADIENT = 2;
|
||||
const PATTERN = 3;
|
||||
|
||||
function insertColorIntoArray(color, targetArray, atIndex) {
|
||||
const c = new Color(color);
|
||||
targetArray[atIndex + 0] = c.red / 255;
|
||||
targetArray[atIndex + 1] = c.green / 255;
|
||||
targetArray[atIndex + 2] = c.blue / 255;
|
||||
targetArray[atIndex + 3] = c.alpha;
|
||||
}
|
||||
|
||||
function insertColorsIntoArray(stops, targetArray, atIndex) {
|
||||
let i = 0;
|
||||
if ('length' in stops) {
|
||||
while (i < stops.length) {
|
||||
insertColorIntoArray(stops[i], targetArray, atIndex + i * 4);
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
for (const offset in stops) {
|
||||
insertColorIntoArray(stops[offset], targetArray, atIndex + i * 4);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return atIndex + i * 4;
|
||||
}
|
||||
|
||||
function insertOffsetsIntoArray(stops, targetArray, atIndex, multi, reverse) {
|
||||
let offsetNumber;
|
||||
let i = 0;
|
||||
if ('length' in stops) {
|
||||
while (i < stops.length) {
|
||||
offsetNumber = (i / (stops.length - 1)) * multi;
|
||||
targetArray[atIndex + i] = reverse ? 1 - offsetNumber : offsetNumber;
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
for (const offsetString in stops) {
|
||||
offsetNumber = +offsetString * multi;
|
||||
targetArray[atIndex + i] = reverse ? 1 - offsetNumber : offsetNumber;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return atIndex + i;
|
||||
}
|
||||
|
||||
function insertColorStopsIntoArray(stops, targetArray, atIndex) {
|
||||
const lastIndex = insertColorsIntoArray(stops, targetArray, atIndex);
|
||||
insertOffsetsIntoArray(stops, targetArray, lastIndex, 1, false);
|
||||
}
|
||||
|
||||
function insertDoubleColorStopsIntoArray(stops, targetArray, atIndex) {
|
||||
let lastIndex = insertColorsIntoArray(stops, targetArray, atIndex);
|
||||
lastIndex = insertColorsIntoArray(stops, targetArray, lastIndex);
|
||||
lastIndex = insertOffsetsIntoArray(stops, targetArray, lastIndex, 0.5, false);
|
||||
insertOffsetsIntoArray(stops, targetArray, lastIndex, 0.5, true);
|
||||
}
|
||||
|
||||
function applyBoundingBoxToBrushData(brushData, props) {
|
||||
const type = brushData[0];
|
||||
const width = +props.width;
|
||||
const height = +props.height;
|
||||
if (type === LINEAR_GRADIENT) {
|
||||
brushData[1] *= width;
|
||||
brushData[2] *= height;
|
||||
brushData[3] *= width;
|
||||
brushData[4] *= height;
|
||||
} else if (type === RADIAL_GRADIENT) {
|
||||
brushData[1] *= width;
|
||||
brushData[2] *= height;
|
||||
brushData[3] *= width;
|
||||
brushData[4] *= height;
|
||||
brushData[5] *= width;
|
||||
brushData[6] *= height;
|
||||
} else if (type === PATTERN) {
|
||||
// todo
|
||||
}
|
||||
}
|
||||
|
||||
function extractBrush(colorOrBrush, props) {
|
||||
if (colorOrBrush == null) {
|
||||
return null;
|
||||
}
|
||||
if (colorOrBrush._brush) {
|
||||
if (colorOrBrush._bb) {
|
||||
// The legacy API for Gradients allow for the bounding box to be used
|
||||
// as a convenience for specifying gradient positions. This should be
|
||||
// deprecated. It's not properly implemented in canvas mode. ReactART
|
||||
// doesn't handle update to the bounding box correctly. That's why we
|
||||
// mutate this so that if it's reused, we reuse the same resolved box.
|
||||
applyBoundingBoxToBrushData(colorOrBrush._brush, props);
|
||||
colorOrBrush._bb = false;
|
||||
}
|
||||
return colorOrBrush._brush;
|
||||
}
|
||||
const c = new Color(colorOrBrush);
|
||||
return [SOLID_COLOR, c.red / 255, c.green / 255, c.blue / 255, c.alpha];
|
||||
}
|
||||
|
||||
function extractColor(color) {
|
||||
if (color == null) {
|
||||
return null;
|
||||
}
|
||||
const c = new Color(color);
|
||||
return [c.red / 255, c.green / 255, c.blue / 255, c.alpha];
|
||||
}
|
||||
|
||||
function extractStrokeCap(strokeCap) {
|
||||
switch (strokeCap) {
|
||||
case 'butt':
|
||||
return 0;
|
||||
case 'square':
|
||||
return 2;
|
||||
default:
|
||||
return 1; // round
|
||||
}
|
||||
}
|
||||
|
||||
function extractStrokeJoin(strokeJoin) {
|
||||
switch (strokeJoin) {
|
||||
case 'miter':
|
||||
return 0;
|
||||
case 'bevel':
|
||||
return 2;
|
||||
default:
|
||||
return 1; // round
|
||||
}
|
||||
}
|
||||
|
||||
// Shape
|
||||
|
||||
// Note: ART has a notion of width and height on Shape but AFAIK it's a noop in
|
||||
// ReactART.
|
||||
|
||||
export type ShapeProps = {|
|
||||
fill?: mixed,
|
||||
stroke?: mixed,
|
||||
strokeCap?: mixed,
|
||||
strokeDash?: mixed,
|
||||
strokeJoin?: mixed,
|
||||
strokeWidth?: mixed,
|
||||
x?: number,
|
||||
y?: number,
|
||||
opacity?: mixed,
|
||||
|};
|
||||
|
||||
class Shape extends React.Component<ShapeProps> {
|
||||
render() {
|
||||
const props = this.props;
|
||||
const path = props.d || childrenAsString(props.children);
|
||||
const d = (path instanceof Path ? path : new Path(path)).toJSON();
|
||||
return (
|
||||
<NativeShape
|
||||
fill={extractBrush(props.fill, props)}
|
||||
opacity={extractOpacity(props)}
|
||||
stroke={extractColor(props.stroke)}
|
||||
strokeCap={extractStrokeCap(props.strokeCap)}
|
||||
strokeDash={props.strokeDash || null}
|
||||
strokeJoin={extractStrokeJoin(props.strokeJoin)}
|
||||
strokeWidth={extractNumber(props.strokeWidth, 1)}
|
||||
transform={extractTransform(props)}
|
||||
d={d}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Text
|
||||
|
||||
const cachedFontObjectsFromString = {};
|
||||
|
||||
const fontFamilyPrefix = /^[\s"']*/;
|
||||
const fontFamilySuffix = /[\s"']*$/;
|
||||
|
||||
function extractSingleFontFamily(fontFamilyString) {
|
||||
// ART on the web allows for multiple font-families to be specified.
|
||||
// For compatibility, we extract the first font-family, hoping
|
||||
// we'll get a match.
|
||||
return fontFamilyString
|
||||
.split(',')[0]
|
||||
.replace(fontFamilyPrefix, '')
|
||||
.replace(fontFamilySuffix, '');
|
||||
}
|
||||
|
||||
function parseFontString(font) {
|
||||
if (cachedFontObjectsFromString.hasOwnProperty(font)) {
|
||||
return cachedFontObjectsFromString[font];
|
||||
}
|
||||
const regexp = /^\s*((?:(?:normal|bold|italic)\s+)*)(?:(\d+(?:\.\d+)?)[ptexm\%]*(?:\s*\/.*?)?\s+)?\s*\"?([^\"]*)/i;
|
||||
const match = regexp.exec(font);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
const fontFamily = extractSingleFontFamily(match[3]);
|
||||
const fontSize = +match[2] || 12;
|
||||
const isBold = /bold/.exec(match[1]);
|
||||
const isItalic = /italic/.exec(match[1]);
|
||||
cachedFontObjectsFromString[font] = {
|
||||
fontFamily: fontFamily,
|
||||
fontSize: fontSize,
|
||||
fontWeight: isBold ? 'bold' : 'normal',
|
||||
fontStyle: isItalic ? 'italic' : 'normal',
|
||||
};
|
||||
return cachedFontObjectsFromString[font];
|
||||
}
|
||||
|
||||
function extractFont(font) {
|
||||
if (font == null) {
|
||||
return null;
|
||||
}
|
||||
if (typeof font === 'string') {
|
||||
return parseFontString(font);
|
||||
}
|
||||
const fontFamily = extractSingleFontFamily(font.fontFamily);
|
||||
const fontSize = +font.fontSize || 12;
|
||||
const fontWeight =
|
||||
font.fontWeight != null ? font.fontWeight.toString() : '400';
|
||||
return {
|
||||
// Normalize
|
||||
fontFamily: fontFamily,
|
||||
fontSize: fontSize,
|
||||
fontWeight: fontWeight,
|
||||
fontStyle: font.fontStyle,
|
||||
};
|
||||
}
|
||||
|
||||
const newLine = /\n/g;
|
||||
function extractFontAndLines(font, text) {
|
||||
return {font: extractFont(font), lines: text.split(newLine)};
|
||||
}
|
||||
|
||||
function extractAlignment(alignment) {
|
||||
switch (alignment) {
|
||||
case 'right':
|
||||
return 1;
|
||||
case 'center':
|
||||
return 2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class Text extends React.Component {
|
||||
render() {
|
||||
const props = this.props;
|
||||
const path = props.path;
|
||||
const textPath = path
|
||||
? (path instanceof Path ? path : new Path(path)).toJSON()
|
||||
: null;
|
||||
const textFrame = extractFontAndLines(
|
||||
props.font,
|
||||
childrenAsString(props.children),
|
||||
);
|
||||
return (
|
||||
<NativeText
|
||||
fill={extractBrush(props.fill, props)}
|
||||
opacity={extractOpacity(props)}
|
||||
stroke={extractColor(props.stroke)}
|
||||
strokeCap={extractStrokeCap(props.strokeCap)}
|
||||
strokeDash={props.strokeDash || null}
|
||||
strokeJoin={extractStrokeJoin(props.strokeJoin)}
|
||||
strokeWidth={extractNumber(props.strokeWidth, 1)}
|
||||
transform={extractTransform(props)}
|
||||
alignment={extractAlignment(props.alignment)}
|
||||
frame={textFrame}
|
||||
path={textPath}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Declarative fill type objects - API design not finalized
|
||||
|
||||
function LinearGradient(stops, x1, y1, x2, y2) {
|
||||
const type = LINEAR_GRADIENT;
|
||||
|
||||
if (arguments.length < 5) {
|
||||
const angle = ((x1 == null ? 270 : x1) * Math.PI) / 180;
|
||||
|
||||
let x = Math.cos(angle);
|
||||
let y = -Math.sin(angle);
|
||||
const l = (Math.abs(x) + Math.abs(y)) / 2;
|
||||
|
||||
x *= l;
|
||||
y *= l;
|
||||
|
||||
x1 = 0.5 - x;
|
||||
x2 = 0.5 + x;
|
||||
y1 = 0.5 - y;
|
||||
y2 = 0.5 + y;
|
||||
this._bb = true;
|
||||
} else {
|
||||
this._bb = false;
|
||||
}
|
||||
|
||||
const brushData = [type, +x1, +y1, +x2, +y2];
|
||||
insertColorStopsIntoArray(stops, brushData, 5);
|
||||
this._brush = brushData;
|
||||
}
|
||||
|
||||
function RadialGradient(stops, fx, fy, rx, ry, cx, cy) {
|
||||
if (ry == null) {
|
||||
ry = rx;
|
||||
}
|
||||
if (cx == null) {
|
||||
cx = fx;
|
||||
}
|
||||
if (cy == null) {
|
||||
cy = fy;
|
||||
}
|
||||
if (fx == null) {
|
||||
// As a convenience we allow the whole radial gradient to cover the
|
||||
// bounding box. We should consider dropping this API.
|
||||
fx = fy = rx = ry = cx = cy = 0.5;
|
||||
this._bb = true;
|
||||
} else {
|
||||
this._bb = false;
|
||||
}
|
||||
// The ART API expects the radial gradient to be repeated at the edges.
|
||||
// To simulate this we render the gradient twice as large and add double
|
||||
// color stops. Ideally this API would become more restrictive so that this
|
||||
// extra work isn't needed.
|
||||
const brushData = [RADIAL_GRADIENT, +fx, +fy, +rx * 2, +ry * 2, +cx, +cy];
|
||||
insertDoubleColorStopsIntoArray(stops, brushData, 7);
|
||||
this._brush = brushData;
|
||||
}
|
||||
|
||||
function Pattern(url, width, height, left, top) {
|
||||
this._brush = [PATTERN, url, +left || 0, +top || 0, +width, +height];
|
||||
}
|
||||
|
||||
const ReactART = {
|
||||
LinearGradient: LinearGradient,
|
||||
RadialGradient: RadialGradient,
|
||||
Pattern: Pattern,
|
||||
Transform: Transform,
|
||||
Path: Path,
|
||||
Surface: Surface,
|
||||
Group: Group,
|
||||
ClippingRectangle: ClippingRectangle,
|
||||
Shape: Shape,
|
||||
Text: Text,
|
||||
};
|
||||
|
||||
module.exports = ReactART;
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTNodeManager.h"
|
||||
|
||||
@interface ARTGroupManager : ARTNodeManager
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTGroupManager.h"
|
||||
|
||||
#import "ARTGroup.h"
|
||||
#import "RCTConvert+ART.h"
|
||||
|
||||
@implementation ARTGroupManager
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (ARTNode *)node
|
||||
{
|
||||
return [ARTGroup new];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(clipping, CGRect)
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <React/RCTViewManager.h>
|
||||
|
||||
@class ARTNode;
|
||||
|
||||
@interface ARTNodeManager : RCTViewManager
|
||||
|
||||
- (ARTNode *)node;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTNodeManager.h"
|
||||
|
||||
#import "ARTNode.h"
|
||||
|
||||
@implementation ARTNodeManager
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (ARTNode *)node
|
||||
{
|
||||
return [ARTNode new];
|
||||
}
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
return [self node];
|
||||
}
|
||||
|
||||
- (RCTShadowView *)shadowView
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(opacity, CGFloat)
|
||||
RCT_EXPORT_VIEW_PROPERTY(transform, CGAffineTransform)
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTNodeManager.h"
|
||||
#import "ARTRenderable.h"
|
||||
|
||||
@interface ARTRenderableManager : ARTNodeManager
|
||||
|
||||
- (ARTRenderable *)node;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTRenderableManager.h"
|
||||
|
||||
#import "RCTConvert+ART.h"
|
||||
|
||||
@implementation ARTRenderableManager
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (ARTRenderable *)node
|
||||
{
|
||||
return [ARTRenderable new];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(strokeWidth, CGFloat)
|
||||
RCT_EXPORT_VIEW_PROPERTY(strokeCap, CGLineCap)
|
||||
RCT_EXPORT_VIEW_PROPERTY(strokeJoin, CGLineJoin)
|
||||
RCT_EXPORT_VIEW_PROPERTY(fill, ARTBrush)
|
||||
RCT_EXPORT_VIEW_PROPERTY(stroke, CGColor)
|
||||
RCT_EXPORT_VIEW_PROPERTY(strokeDash, ARTCGFloatArray)
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTRenderableManager.h"
|
||||
|
||||
@interface ARTShapeManager : ARTRenderableManager
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTShapeManager.h"
|
||||
|
||||
#import "ARTShape.h"
|
||||
#import "RCTConvert+ART.h"
|
||||
|
||||
@implementation ARTShapeManager
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (ARTRenderable *)node
|
||||
{
|
||||
return [ARTShape new];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(d, CGPath)
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <React/RCTViewManager.h>
|
||||
|
||||
@interface ARTSurfaceViewManager : RCTViewManager
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTSurfaceViewManager.h"
|
||||
|
||||
#import "ARTSurfaceView.h"
|
||||
|
||||
@implementation ARTSurfaceViewManager
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
return [ARTSurfaceView new];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTRenderableManager.h"
|
||||
|
||||
@interface ARTTextManager : ARTRenderableManager
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "ARTTextManager.h"
|
||||
|
||||
#import "ARTText.h"
|
||||
#import "RCTConvert+ART.h"
|
||||
|
||||
@implementation ARTTextManager
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (ARTRenderable *)node
|
||||
{
|
||||
return [ARTText new];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(alignment, CTTextAlignment)
|
||||
RCT_REMAP_VIEW_PROPERTY(frame, textFrame, ARTTextFrame)
|
||||
|
||||
@end
|
||||
@@ -7,20 +7,18 @@
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import RCTActionSheetManager from './NativeActionSheetManager';
|
||||
const RCTActionSheetManager = require('../BatchedBridge/NativeModules')
|
||||
.ActionSheetManager;
|
||||
|
||||
const invariant = require('invariant');
|
||||
const processColor = require('../StyleSheet/processColor');
|
||||
import type {ColorValue} from '../StyleSheet/StyleSheet';
|
||||
import type {ProcessedColorValue} from '../StyleSheet/processColor';
|
||||
|
||||
/**
|
||||
* Display action sheets and share sheets on iOS.
|
||||
*
|
||||
* See https://reactnative.dev/docs/actionsheetios.html
|
||||
* See http://facebook.github.io/react-native/docs/actionsheetios.html
|
||||
*/
|
||||
const ActionSheetIOS = {
|
||||
/**
|
||||
@@ -33,24 +31,21 @@ const ActionSheetIOS = {
|
||||
* - `destructiveButtonIndex` (int or array of ints) - index or indices of destructive buttons in `options`
|
||||
* - `title` (string) - a title to show above the action sheet
|
||||
* - `message` (string) - a message to show below the title
|
||||
* - `disabledButtonIndices` (array of numbers) - a list of button indices which should be disabled
|
||||
*
|
||||
* The 'callback' function takes one parameter, the zero-based index
|
||||
* of the selected item.
|
||||
*
|
||||
* See https://reactnative.dev/docs/actionsheetios.html#showactionsheetwithoptions
|
||||
* See http://facebook.github.io/react-native/docs/actionsheetios.html#showactionsheetwithoptions
|
||||
*/
|
||||
showActionSheetWithOptions(
|
||||
options: {|
|
||||
+title?: ?string,
|
||||
+message?: ?string,
|
||||
+options: Array<string>,
|
||||
+destructiveButtonIndex?: ?number | ?Array<number>,
|
||||
+destructiveButtonIndex?: ?number,
|
||||
+cancelButtonIndex?: ?number,
|
||||
+anchor?: ?number,
|
||||
+tintColor?: ColorValue | ProcessedColorValue,
|
||||
+userInterfaceStyle?: string,
|
||||
+disabledButtonIndices?: Array<number>,
|
||||
+tintColor?: number | string,
|
||||
|},
|
||||
callback: (buttonIndex: number) => void,
|
||||
) {
|
||||
@@ -59,28 +54,9 @@ const ActionSheetIOS = {
|
||||
'Options must be a valid object',
|
||||
);
|
||||
invariant(typeof callback === 'function', 'Must provide a valid callback');
|
||||
invariant(RCTActionSheetManager, "ActionSheetManager doesn't exist");
|
||||
|
||||
const {tintColor, destructiveButtonIndex, ...remainingOptions} = options;
|
||||
let destructiveButtonIndices = null;
|
||||
|
||||
if (Array.isArray(destructiveButtonIndex)) {
|
||||
destructiveButtonIndices = destructiveButtonIndex;
|
||||
} else if (typeof destructiveButtonIndex === 'number') {
|
||||
destructiveButtonIndices = [destructiveButtonIndex];
|
||||
}
|
||||
|
||||
const processedTintColor = processColor(tintColor);
|
||||
invariant(
|
||||
processedTintColor == null || typeof processedTintColor === 'number',
|
||||
'Unexpected color given for ActionSheetIOS.showActionSheetWithOptions tintColor',
|
||||
);
|
||||
RCTActionSheetManager.showActionSheetWithOptions(
|
||||
{
|
||||
...remainingOptions,
|
||||
tintColor: processedTintColor,
|
||||
destructiveButtonIndices,
|
||||
},
|
||||
{...options, tintColor: processColor(options.tintColor)},
|
||||
callback,
|
||||
);
|
||||
},
|
||||
@@ -106,7 +82,7 @@ const ActionSheetIOS = {
|
||||
* - a boolean value signifying success or failure
|
||||
* - a string that, in the case of success, indicates the method of sharing
|
||||
*
|
||||
* See https://reactnative.dev/docs/actionsheetios.html#showshareactionsheetwithoptions
|
||||
* See http://facebook.github.io/react-native/docs/actionsheetios.html#showshareactionsheetwithoptions
|
||||
*/
|
||||
showShareActionSheetWithOptions(
|
||||
options: Object,
|
||||
@@ -125,7 +101,6 @@ const ActionSheetIOS = {
|
||||
typeof successCallback === 'function',
|
||||
'Must provide a valid successCallback',
|
||||
);
|
||||
invariant(RCTActionSheetManager, "ActionSheetManager doesn't exist");
|
||||
RCTActionSheetManager.showShareActionSheetWithOptions(
|
||||
{...options, tintColor: processColor(options.tintColor)},
|
||||
failureCallback,
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {TurboModule} from '../TurboModule/RCTExport';
|
||||
import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+getConstants: () => {||};
|
||||
+showActionSheetWithOptions: (
|
||||
options: {|
|
||||
+title?: ?string,
|
||||
+message?: ?string,
|
||||
+options: ?Array<string>,
|
||||
+destructiveButtonIndices?: ?Array<number>,
|
||||
+cancelButtonIndex?: ?number,
|
||||
+anchor?: ?number,
|
||||
+tintColor?: ?number,
|
||||
+userInterfaceStyle?: ?string,
|
||||
+disabledButtonIndices?: Array<number>,
|
||||
|},
|
||||
callback: (buttonIndex: number) => void,
|
||||
) => void;
|
||||
+showShareActionSheetWithOptions: (
|
||||
options: {|
|
||||
+message?: ?string,
|
||||
+url?: ?string,
|
||||
+subject?: ?string,
|
||||
+anchor?: ?number,
|
||||
+tintColor?: ?number,
|
||||
+excludedActivityTypes?: ?Array<string>,
|
||||
+userInterfaceStyle?: ?string,
|
||||
|},
|
||||
failureCallback: (error: {|
|
||||
+domain: string,
|
||||
+code: string,
|
||||
+userInfo?: ?Object,
|
||||
+message: string,
|
||||
|}) => void,
|
||||
successCallback: (completed: boolean, activityType: ?string) => void,
|
||||
) => void;
|
||||
}
|
||||
|
||||
export default (TurboModuleRegistry.get<Spec>('ActionSheetManager'): ?Spec);
|
||||
@@ -0,0 +1,258 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
14C644C41AB0DFC900DE3C65 /* RCTActionSheetManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C644C21AB0DFC900DE3C65 /* RCTActionSheetManager.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
134814201AA4EA6300B7C361 /* libRCTActionSheet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTActionSheet.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
14C644C11AB0DFC900DE3C65 /* RCTActionSheetManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTActionSheetManager.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
14C644C21AB0DFC900DE3C65 /* RCTActionSheetManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTActionSheetManager.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
134814211AA4EA7D00B7C361 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
134814201AA4EA6300B7C361 /* libRCTActionSheet.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
58B511D21A9E6C8500147676 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
14C644C11AB0DFC900DE3C65 /* RCTActionSheetManager.h */,
|
||||
14C644C21AB0DFC900DE3C65 /* RCTActionSheetManager.m */,
|
||||
134814211AA4EA7D00B7C361 /* Products */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
sourceTree = "<group>";
|
||||
tabWidth = 2;
|
||||
usesTabs = 0;
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
58B511DA1A9E6C8500147676 /* RCTActionSheet */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTActionSheet" */;
|
||||
buildPhases = (
|
||||
58B511D71A9E6C8500147676 /* Sources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = RCTActionSheet;
|
||||
productName = RCTDataManager;
|
||||
productReference = 134814201AA4EA6300B7C361 /* libRCTActionSheet.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
58B511D31A9E6C8500147676 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0940;
|
||||
ORGANIZATIONNAME = Facebook;
|
||||
TargetAttributes = {
|
||||
58B511DA1A9E6C8500147676 = {
|
||||
CreatedOnToolsVersion = 6.1.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTActionSheet" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = 58B511D21A9E6C8500147676;
|
||||
productRefGroup = 58B511D21A9E6C8500147676;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
58B511DA1A9E6C8500147676 /* RCTActionSheet */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
58B511D71A9E6C8500147676 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
14C644C41AB0DFC900DE3C65 /* RCTActionSheetManager.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
58B511ED1A9E6C8500147676 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_SHADOW = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
WARNING_CFLAGS = (
|
||||
"-Werror",
|
||||
"-Wall",
|
||||
);
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
58B511EE1A9E6C8500147676 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_SHADOW = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
WARNING_CFLAGS = (
|
||||
"-Werror",
|
||||
"-Wall",
|
||||
);
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
58B511F01A9E6C8500147676 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = RCTActionSheet;
|
||||
RUN_CLANG_STATIC_ANALYZER = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
58B511F11A9E6C8500147676 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = RCTActionSheet;
|
||||
RUN_CLANG_STATIC_ANALYZER = NO;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTActionSheet" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
58B511ED1A9E6C8500147676 /* Debug */,
|
||||
58B511EE1A9E6C8500147676 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTActionSheet" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
58B511F01A9E6C8500147676 /* Debug */,
|
||||
58B511F11A9E6C8500147676 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 58B511D31A9E6C8500147676 /* Project object */;
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "RCTActionSheetManager.h"
|
||||
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTConvert.h>
|
||||
#import <React/RCTLog.h>
|
||||
#import <React/RCTUIManager.h>
|
||||
#import <React/RCTUtils.h>
|
||||
|
||||
@interface RCTActionSheetManager () <UIActionSheetDelegate>
|
||||
@end
|
||||
|
||||
@implementation RCTActionSheetManager
|
||||
{
|
||||
// Use NSMapTable, as UIAlertViews do not implement <NSCopying>
|
||||
// which is required for NSDictionary keys
|
||||
NSMapTable *_callbacks;
|
||||
}
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
|
||||
- (dispatch_queue_t)methodQueue
|
||||
{
|
||||
return dispatch_get_main_queue();
|
||||
}
|
||||
|
||||
- (void)presentViewController:(UIViewController *)alertController
|
||||
onParentViewController:(UIViewController *)parentViewController
|
||||
anchorViewTag:(NSNumber *)anchorViewTag
|
||||
{
|
||||
alertController.modalPresentationStyle = UIModalPresentationPopover;
|
||||
UIView *sourceView = parentViewController.view;
|
||||
|
||||
if (anchorViewTag) {
|
||||
sourceView = [self.bridge.uiManager viewForReactTag:anchorViewTag];
|
||||
} else {
|
||||
alertController.popoverPresentationController.permittedArrowDirections = 0;
|
||||
}
|
||||
alertController.popoverPresentationController.sourceView = sourceView;
|
||||
alertController.popoverPresentationController.sourceRect = sourceView.bounds;
|
||||
[parentViewController presentViewController:alertController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(showActionSheetWithOptions:(NSDictionary *)options
|
||||
callback:(RCTResponseSenderBlock)callback)
|
||||
{
|
||||
if (RCTRunningInAppExtension()) {
|
||||
RCTLogError(@"Unable to show action sheet from app extension");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_callbacks) {
|
||||
_callbacks = [NSMapTable strongToStrongObjectsMapTable];
|
||||
}
|
||||
|
||||
NSString *title = [RCTConvert NSString:options[@"title"]];
|
||||
NSString *message = [RCTConvert NSString:options[@"message"]];
|
||||
NSArray<NSString *> *buttons = [RCTConvert NSStringArray:options[@"options"]];
|
||||
NSInteger cancelButtonIndex = options[@"cancelButtonIndex"] ? [RCTConvert NSInteger:options[@"cancelButtonIndex"]] : -1;
|
||||
NSArray<NSNumber *> *destructiveButtonIndices;
|
||||
if ([options[@"destructiveButtonIndex"] isKindOfClass:[NSArray class]]) {
|
||||
destructiveButtonIndices = [RCTConvert NSArray:options[@"destructiveButtonIndex"]];
|
||||
} else {
|
||||
NSNumber *destructiveButtonIndex = options[@"destructiveButtonIndex"] ? [RCTConvert NSNumber:options[@"destructiveButtonIndex"]] : @-1;
|
||||
destructiveButtonIndices = @[destructiveButtonIndex];
|
||||
}
|
||||
|
||||
UIViewController *controller = RCTPresentedViewController();
|
||||
|
||||
if (controller == nil) {
|
||||
RCTLogError(@"Tried to display action sheet but there is no application window. options: %@", options);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The `anchor` option takes a view to set as the anchor for the share
|
||||
* popup to point to, on iPads running iOS 8. If it is not passed, it
|
||||
* defaults to centering the share popup on screen without any arrows.
|
||||
*/
|
||||
NSNumber *anchorViewTag = [RCTConvert NSNumber:options[@"anchor"]];
|
||||
|
||||
UIAlertController *alertController =
|
||||
[UIAlertController alertControllerWithTitle:title
|
||||
message:message
|
||||
preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
|
||||
NSInteger index = 0;
|
||||
for (NSString *option in buttons) {
|
||||
UIAlertActionStyle style = UIAlertActionStyleDefault;
|
||||
if ([destructiveButtonIndices containsObject:@(index)]) {
|
||||
style = UIAlertActionStyleDestructive;
|
||||
} else if (index == cancelButtonIndex) {
|
||||
style = UIAlertActionStyleCancel;
|
||||
}
|
||||
|
||||
NSInteger localIndex = index;
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:option
|
||||
style:style
|
||||
handler:^(__unused UIAlertAction *action){
|
||||
callback(@[@(localIndex)]);
|
||||
}]];
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
alertController.view.tintColor = [RCTConvert UIColor:options[@"tintColor"]];
|
||||
[self presentViewController:alertController onParentViewController:controller anchorViewTag:anchorViewTag];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(showShareActionSheetWithOptions:(NSDictionary *)options
|
||||
failureCallback:(RCTResponseErrorBlock)failureCallback
|
||||
successCallback:(RCTResponseSenderBlock)successCallback)
|
||||
{
|
||||
if (RCTRunningInAppExtension()) {
|
||||
RCTLogError(@"Unable to show action sheet from app extension");
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableArray<id> *items = [NSMutableArray array];
|
||||
NSString *message = [RCTConvert NSString:options[@"message"]];
|
||||
if (message) {
|
||||
[items addObject:message];
|
||||
}
|
||||
NSURL *URL = [RCTConvert NSURL:options[@"url"]];
|
||||
if (URL) {
|
||||
if ([URL.scheme.lowercaseString isEqualToString:@"data"]) {
|
||||
NSError *error;
|
||||
NSData *data = [NSData dataWithContentsOfURL:URL
|
||||
options:(NSDataReadingOptions)0
|
||||
error:&error];
|
||||
if (!data) {
|
||||
failureCallback(error);
|
||||
return;
|
||||
}
|
||||
[items addObject:data];
|
||||
} else {
|
||||
[items addObject:URL];
|
||||
}
|
||||
}
|
||||
if (items.count == 0) {
|
||||
RCTLogError(@"No `url` or `message` to share");
|
||||
return;
|
||||
}
|
||||
|
||||
UIActivityViewController *shareController = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil];
|
||||
|
||||
NSString *subject = [RCTConvert NSString:options[@"subject"]];
|
||||
if (subject) {
|
||||
[shareController setValue:subject forKey:@"subject"];
|
||||
}
|
||||
|
||||
NSArray *excludedActivityTypes = [RCTConvert NSStringArray:options[@"excludedActivityTypes"]];
|
||||
if (excludedActivityTypes) {
|
||||
shareController.excludedActivityTypes = excludedActivityTypes;
|
||||
}
|
||||
|
||||
UIViewController *controller = RCTPresentedViewController();
|
||||
shareController.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, __unused NSArray *returnedItems, NSError *activityError) {
|
||||
if (activityError) {
|
||||
failureCallback(activityError);
|
||||
} else {
|
||||
successCallback(@[@(completed), RCTNullIfNil(activityType)]);
|
||||
}
|
||||
};
|
||||
|
||||
NSNumber *anchorViewTag = [RCTConvert NSNumber:options[@"anchor"]];
|
||||
shareController.view.tintColor = [RCTConvert UIColor:options[@"tintColor"]];
|
||||
|
||||
[self presentViewController:shareController onParentViewController:controller anchorViewTag:anchorViewTag];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,3 +1,4 @@
|
||||
# coding: utf-8
|
||||
# Copyright (c) Facebook, Inc. and its affiliates.
|
||||
#
|
||||
# This source code is licensed under the MIT license found in the
|
||||
@@ -20,15 +21,15 @@ Pod::Spec.new do |s|
|
||||
s.name = "React-RCTActionSheet"
|
||||
s.version = version
|
||||
s.summary = "An API for displaying iOS action sheets and share sheets."
|
||||
s.homepage = "https://reactnative.dev/"
|
||||
s.documentation_url = "https://reactnative.dev/docs/actionsheetios"
|
||||
s.homepage = "http://facebook.github.io/react-native/"
|
||||
s.documentation_url = "https://facebook.github.io/react-native/docs/actionsheetios"
|
||||
s.license = package["license"]
|
||||
s.author = "Facebook, Inc. and its affiliates"
|
||||
s.platforms = { :ios => "10.0" }
|
||||
s.platforms = { :ios => "9.0", :tvos => "9.2" }
|
||||
s.source = source
|
||||
s.source_files = "*.{m}"
|
||||
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
|
||||
s.header_dir = "RCTActionSheet"
|
||||
s.source_files = "*.{h,m}"
|
||||
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
|
||||
s.header_dir = "React"
|
||||
|
||||
s.dependency "React-Core/RCTActionSheetHeaders", version
|
||||
s.dependency "React-Core", version
|
||||
end
|
||||
|
||||
+69
-44
@@ -10,35 +10,38 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import Platform from '../Utilities/Platform';
|
||||
import NativeDialogManagerAndroid, {
|
||||
type DialogOptions,
|
||||
} from '../NativeModules/specs/NativeDialogManagerAndroid';
|
||||
import RCTAlertManager from './RCTAlertManager';
|
||||
const NativeModules = require('../BatchedBridge/NativeModules');
|
||||
const RCTAlertManager = NativeModules.AlertManager;
|
||||
const Platform = require('../Utilities/Platform');
|
||||
|
||||
export type AlertType =
|
||||
| 'default'
|
||||
| 'plain-text'
|
||||
| 'secure-text'
|
||||
| 'login-password';
|
||||
export type AlertButtonStyle = 'default' | 'cancel' | 'destructive';
|
||||
export type Buttons = Array<{
|
||||
text?: string,
|
||||
onPress?: ?Function,
|
||||
style?: AlertButtonStyle,
|
||||
...
|
||||
}>;
|
||||
|
||||
type Options = {
|
||||
cancelable?: ?boolean,
|
||||
onDismiss?: ?() => void,
|
||||
...
|
||||
onDismiss?: ?Function,
|
||||
};
|
||||
|
||||
type AlertType = $Keys<{
|
||||
default: string,
|
||||
'plain-text': string,
|
||||
'secure-text': string,
|
||||
'login-password': string,
|
||||
}>;
|
||||
|
||||
export type AlertButtonStyle = $Keys<{
|
||||
default: string,
|
||||
cancel: string,
|
||||
destructive: string,
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Launches an alert dialog with the specified title and message.
|
||||
*
|
||||
* See https://reactnative.dev/docs/alert.html
|
||||
* See http://facebook.github.io/react-native/docs/alert.html
|
||||
*/
|
||||
class Alert {
|
||||
static alert(
|
||||
@@ -50,55 +53,55 @@ class Alert {
|
||||
if (Platform.OS === 'ios') {
|
||||
Alert.prompt(title, message, buttons, 'default');
|
||||
} else if (Platform.OS === 'android') {
|
||||
if (!NativeDialogManagerAndroid) {
|
||||
return;
|
||||
}
|
||||
const constants = NativeDialogManagerAndroid.getConstants();
|
||||
|
||||
const config: DialogOptions = {
|
||||
let config = {
|
||||
title: title || '',
|
||||
message: message || '',
|
||||
cancelable: false,
|
||||
};
|
||||
|
||||
if (options && options.cancelable) {
|
||||
config.cancelable = options.cancelable;
|
||||
if (options) {
|
||||
config = {...config, cancelable: options.cancelable};
|
||||
}
|
||||
// At most three buttons (neutral, negative, positive). Ignore rest.
|
||||
// The text 'OK' should be probably localized. iOS Alert does that in native.
|
||||
const defaultPositiveText = 'OK';
|
||||
const validButtons: Buttons = buttons
|
||||
? buttons.slice(0, 3)
|
||||
: [{text: defaultPositiveText}];
|
||||
: [{text: 'OK'}];
|
||||
const buttonPositive = validButtons.pop();
|
||||
const buttonNegative = validButtons.pop();
|
||||
const buttonNeutral = validButtons.pop();
|
||||
|
||||
if (buttonNeutral) {
|
||||
config.buttonNeutral = buttonNeutral.text || '';
|
||||
config = {...config, buttonNeutral: buttonNeutral.text || ''};
|
||||
}
|
||||
if (buttonNegative) {
|
||||
config.buttonNegative = buttonNegative.text || '';
|
||||
config = {...config, buttonNegative: buttonNegative.text || ''};
|
||||
}
|
||||
if (buttonPositive) {
|
||||
config.buttonPositive = buttonPositive.text || defaultPositiveText;
|
||||
config = {...config, buttonPositive: buttonPositive.text || ''};
|
||||
}
|
||||
|
||||
const onAction = (action, buttonKey) => {
|
||||
if (action === constants.buttonClicked) {
|
||||
if (buttonKey === constants.buttonNeutral) {
|
||||
buttonNeutral.onPress && buttonNeutral.onPress();
|
||||
} else if (buttonKey === constants.buttonNegative) {
|
||||
buttonNegative.onPress && buttonNegative.onPress();
|
||||
} else if (buttonKey === constants.buttonPositive) {
|
||||
buttonPositive.onPress && buttonPositive.onPress();
|
||||
NativeModules.DialogManagerAndroid.showAlert(
|
||||
config,
|
||||
errorMessage => console.warn(errorMessage),
|
||||
(action, buttonKey) => {
|
||||
if (action === NativeModules.DialogManagerAndroid.buttonClicked) {
|
||||
if (
|
||||
buttonKey === NativeModules.DialogManagerAndroid.buttonNeutral
|
||||
) {
|
||||
buttonNeutral.onPress && buttonNeutral.onPress();
|
||||
} else if (
|
||||
buttonKey === NativeModules.DialogManagerAndroid.buttonNegative
|
||||
) {
|
||||
buttonNegative.onPress && buttonNegative.onPress();
|
||||
} else if (
|
||||
buttonKey === NativeModules.DialogManagerAndroid.buttonPositive
|
||||
) {
|
||||
buttonPositive.onPress && buttonPositive.onPress();
|
||||
}
|
||||
} else if (action === NativeModules.DialogManagerAndroid.dismissed) {
|
||||
options && options.onDismiss && options.onDismiss();
|
||||
}
|
||||
} else if (action === constants.dismissed) {
|
||||
options && options.onDismiss && options.onDismiss();
|
||||
}
|
||||
};
|
||||
const onError = errorMessage => console.warn(errorMessage);
|
||||
NativeDialogManagerAndroid.showAlert(config, onError, onAction);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +114,28 @@ class Alert {
|
||||
keyboardType?: string,
|
||||
): void {
|
||||
if (Platform.OS === 'ios') {
|
||||
if (typeof type === 'function') {
|
||||
console.warn(
|
||||
'You passed a callback function as the "type" argument to Alert.prompt(). React Native is ' +
|
||||
'assuming you want to use the deprecated Alert.prompt(title, defaultValue, buttons, callback) ' +
|
||||
'signature. The current signature is Alert.prompt(title, message, callbackOrButtons, type, defaultValue, ' +
|
||||
'keyboardType) and the old syntax will be removed in a future version.',
|
||||
);
|
||||
|
||||
const callback = type;
|
||||
RCTAlertManager.alertWithArgs(
|
||||
{
|
||||
title: title || '',
|
||||
type: 'plain-text',
|
||||
defaultValue: message,
|
||||
},
|
||||
(id, value) => {
|
||||
callback(value);
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let callbacks = [];
|
||||
const buttons = [];
|
||||
let cancelButtonKey;
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {TurboModule} from '../TurboModule/RCTExport';
|
||||
import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
|
||||
|
||||
export type Args = {|
|
||||
title?: string,
|
||||
message?: string,
|
||||
buttons?: Array<Object>, // TODO(T67565166): have a better type
|
||||
type?: string,
|
||||
defaultValue?: string,
|
||||
cancelButtonKey?: string,
|
||||
destructiveButtonKey?: string,
|
||||
keyboardType?: string,
|
||||
|};
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+alertWithArgs: (
|
||||
args: Args,
|
||||
callback: (id: number, value: string) => void,
|
||||
) => void;
|
||||
}
|
||||
|
||||
export default (TurboModuleRegistry.get<Spec>('AlertManager'): ?Spec);
|
||||
@@ -9,18 +9,14 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import NativeDialogManagerAndroid from '../NativeModules/specs/NativeDialogManagerAndroid';
|
||||
const NativeModules = require('../BatchedBridge/NativeModules');
|
||||
|
||||
function emptyCallback() {}
|
||||
|
||||
module.exports = {
|
||||
alertWithArgs: function(args, callback) {
|
||||
// TODO(5998984): Polyfill it correctly with DialogManagerAndroid
|
||||
if (!NativeDialogManagerAndroid) {
|
||||
return;
|
||||
}
|
||||
|
||||
NativeDialogManagerAndroid.showAlert(
|
||||
NativeModules.DialogManagerAndroid.showAlert(
|
||||
args,
|
||||
emptyCallback,
|
||||
callback || emptyCallback,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user