diff --git a/.ado/windows-vs-pr.yml b/.ado/windows-vs-pr.yml index b425c0dffbd..2ac41dde3bd 100644 --- a/.ado/windows-vs-pr.yml +++ b/.ado/windows-vs-pr.yml @@ -11,7 +11,7 @@ variables: - template: variables/msbuild.yml - template: variables/vs2019.yml - name: reactNativeVersion - value: 0.61.5 + value: 0.62.2 jobs: - job: Setup diff --git a/change/@office-iss-react-native-win32-2020-04-14-05-18-46-62.json b/change/@office-iss-react-native-win32-2020-04-14-05-18-46-62.json new file mode 100644 index 00000000000..fbb8b835e90 --- /dev/null +++ b/change/@office-iss-react-native-win32-2020-04-14-05-18-46-62.json @@ -0,0 +1,8 @@ +{ + "type": "prerelease", + "comment": "Upgrade to React Native 0.62", + "packageName": "@office-iss/react-native-win32", + "email": "ngerlem@microsoft.com", + "dependentChangeType": "patch", + "date": "2020-04-14T12:18:41.888Z" +} \ No newline at end of file diff --git a/change/react-native-windows-2020-04-14-05-18-46-62.json b/change/react-native-windows-2020-04-14-05-18-46-62.json new file mode 100644 index 00000000000..950d15458cb --- /dev/null +++ b/change/react-native-windows-2020-04-14-05-18-46-62.json @@ -0,0 +1,8 @@ +{ + "type": "prerelease", + "comment": "Upgrade to React Native 0.62", + "packageName": "react-native-windows", + "email": "ngerlem@microsoft.com", + "dependentChangeType": "patch", + "date": "2020-04-14T12:18:46.280Z" +} \ No newline at end of file diff --git a/docs/api/react-native-windows.apptheme.md b/docs/api/react-native-windows.apptheme.md index 60807d1aed2..43ffc937963 100644 --- a/docs/api/react-native-windows.apptheme.md +++ b/docs/api/react-native-windows.apptheme.md @@ -7,5 +7,5 @@ Signature: ```typescript -AppTheme: AppThemeModule +AppTheme: AppThemeModule | MissingNativeAppThemeShim ``` diff --git a/packages/E2ETest/app/TreeDumpControl.ts b/packages/E2ETest/app/TreeDumpControl.ts index 9de23d1c93f..8a910e9d0e8 100644 --- a/packages/E2ETest/app/TreeDumpControl.ts +++ b/packages/E2ETest/app/TreeDumpControl.ts @@ -4,5 +4,11 @@ * Licensed under the MIT License. */ -import { requireNativeComponent } from 'react-native'; -export const TreeDumpControl = requireNativeComponent('TreeDumpControl'); +import { requireNativeComponent, ViewStyle } from 'react-native'; +export const TreeDumpControl = requireNativeComponent<{ + style: ViewStyle; + dumpID: string; + uiaID: string; + testID: string; + additionalProperties?: string[]; +}>('TreeDumpControl'); diff --git a/packages/E2ETest/package.json b/packages/E2ETest/package.json index 1c3c5ba1cfa..515a3b67af1 100644 --- a/packages/E2ETest/package.json +++ b/packages/E2ETest/package.json @@ -23,7 +23,7 @@ }, "dependencies": { "react": "16.9.0", - "react-native": "0.61.5", + "react-native": "0.62.2", "react-native-windows": "0.0.0-master.34", "rnpm-plugin-windows": "^0.6.1" }, @@ -33,7 +33,7 @@ "@types/jasmine": "2.8.7", "@types/node": "^10.14.8", "@types/react": "16.9.0", - "@types/react-native": "~0.61.5", + "@types/react-native": "^0.62.2", "@wdio/appium-service": "5.12.1", "@wdio/cli": "5.12.1", "@wdio/dot-reporter": "5.12.1", diff --git a/packages/microsoft-reactnative-sampleapps/package.json b/packages/microsoft-reactnative-sampleapps/package.json index 83446add086..f69c651db53 100644 --- a/packages/microsoft-reactnative-sampleapps/package.json +++ b/packages/microsoft-reactnative-sampleapps/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "react": "16.9.0", - "react-native": "0.61.5", + "react-native": "0.62.2", "react-native-windows": "0.0.0-master.34", "rnpm-plugin-windows": "^0.6.1" }, @@ -23,7 +23,7 @@ "@babel/core": "^7.8.4", "@babel/runtime": "^7.8.4", "@types/react": "16.9.0", - "@types/react-native": "~0.61.5", + "@types/react-native": "^0.62.2", "just-scripts": "^0.36.1", "metro-react-native-babel-preset": "^0.56.0", "react-test-renderer": "16.9.0" diff --git a/packages/override-tools/src/Cli.ts b/packages/override-tools/src/Cli.ts index 982c4aac7ce..1462c1ec85f 100644 --- a/packages/override-tools/src/Cli.ts +++ b/packages/override-tools/src/Cli.ts @@ -188,8 +188,6 @@ async function addOverride(overridePath: string) { * Remove an override from the manifest */ async function removeOverride(overridePath: string) { - await checkFileExists('override', overridePath); - const manifestPath = await FileSearch.findManifest(overridePath); const manifestDir = path.dirname(manifestPath); @@ -330,7 +328,7 @@ function printValidationErrors(errors: Array) { if (filesMissing.length > 0) { const errorMessage = - "Found override files that aren't listed in the manifest. Overrides can be added to the manifest by using 'yarn override add ':"; + "Found override files that aren't listed in the manifest. Overrides can be added to the manifest by using 'yarn override add ' (where override is package relative):"; console.error(chalk.red(errorMessage)); filesMissing.forEach(err => console.error(` - ${err.file}`)); console.error(); @@ -338,7 +336,7 @@ function printValidationErrors(errors: Array) { if (overridesMissing.length > 0) { const errorMessage = - "Found overrides in the manifest that don't exist on disk. Remove existing overrides using 'yarn override remove ':"; + "Found overrides in the manifest that don't exist on disk. Remove existing overrides using 'yarn override remove ' (where override is package relative):"; console.error(chalk.red(errorMessage)); overridesMissing.forEach(err => console.error(` - ${err.file}`)); console.error(); @@ -346,7 +344,7 @@ function printValidationErrors(errors: Array) { if (baseFilesNotFound.length > 0) { const errorMessage = - "Found overrides whose original files do not exist. Remove existing overrides using 'yarn override remove ':"; + "Found overrides whose original files do not exist. Remove existing overrides using 'yarn override remove ' (where override is package relative):"; console.error(chalk.red(errorMessage)); baseFilesNotFound.forEach(err => console.error(` - ${err.file}`)); console.error(); @@ -354,7 +352,7 @@ function printValidationErrors(errors: Array) { if (outOfDateFiles.length > 0) { const errorMessage = - "Found overrides whose original files have changed. Upgrade overrides using 'yarn override auto-upgrade ' and 'yarn override manual-upgrade ':"; + "Found overrides whose original files have changed. Upgrade overrides using 'yarn override auto-upgrade ' and 'yarn override manual-upgrade ' (where manifest is package relative):"; console.error(chalk.red(errorMessage)); outOfDateFiles.forEach(err => console.error(` - ${err.file}`)); console.error(); diff --git a/packages/override-tools/src/Manifest.ts b/packages/override-tools/src/Manifest.ts index c48a7848ab0..78e872cf3d3 100644 --- a/packages/override-tools/src/Manifest.ts +++ b/packages/override-tools/src/Manifest.ts @@ -81,7 +81,7 @@ export default class Manifest { const baseFile = override.baseFile; const baseContent = await this.reactRepo.getFileContents(baseFile); if (baseContent === null) { - errors.push({type: 'baseFileNotFound', file: override.baseFile}); + errors.push({type: 'baseFileNotFound', file: override.file}); return; } diff --git a/packages/override-tools/src/test/Manifest.test.ts b/packages/override-tools/src/test/Manifest.test.ts index 80ae99c30c8..2900c3cef09 100644 --- a/packages/override-tools/src/test/Manifest.test.ts +++ b/packages/override-tools/src/test/Manifest.test.ts @@ -156,7 +156,7 @@ test('BaseFileNotFound', async () => { const expectedError: ValidationError = { type: 'baseFileNotFound', - file: 'foo\\bar.js', + file: 'aaa\\aaa.windows.js', }; const testManifest = new Manifest(ourManifestData, ovrRepo, reactRepo); diff --git a/packages/playground/package.json b/packages/playground/package.json index 76cd07e2faa..30b34441ba6 100644 --- a/packages/playground/package.json +++ b/packages/playground/package.json @@ -10,14 +10,14 @@ }, "dependencies": { "react": "16.9.0", - "react-native": "0.61.5", + "react-native": "0.62.2", "react-native-windows": "0.0.0-master.34" }, "devDependencies": { "@babel/core": "^7.8.4", "@babel/runtime": "^7.8.4", "@types/react": "16.9.0", - "@types/react-native": "~0.61.5", + "@types/react-native": "^0.62.2", "just-scripts": "^0.36.1", "metro-react-native-babel-preset": "^0.56.0", "react-test-renderer": "16.9.0", diff --git a/packages/react-native-win32/.flowconfig b/packages/react-native-win32/.flowconfig index ff810c24cac..e9e76df4a37 100644 --- a/packages/react-native-win32/.flowconfig +++ b/packages/react-native-win32/.flowconfig @@ -10,23 +10,30 @@ ; initRNLibraries build step /Libraries/Alert/Alert.js /Libraries/Animated/src/nodes/AnimatedInterpolation.js -/Libraries/Color/normalizeColor.js -/Libraries/Color/normalizeColorObject.js /Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js /Libraries/Components/Picker/Picker.js /Libraries/Components/SafeAreaView/SafeAreaView.js -/Libraries/Components/StatusBar/StatusBar.js +/Libraries/Components/StatusBar/NativeStatusBarManagerAndroid.js /Libraries/Components/TextInput/TextInput.js /Libraries/Components/TextInput/TextInputState.js +/Libraries/Components/Touchable/TouchableBounce.js +/Libraries/Components/Touchable/TouchableHighlight.js /Libraries/Components/Touchable/TouchableNativeFeedback.js +/Libraries/Components/Touchable/TouchableOpacity.js +/Libraries/Components/Touchable/TouchableWithoutFeedback.js /Libraries/Components/View/ReactNativeViewAttributes.js /Libraries/Components/View/ReactNativeViewViewConfig.js /Libraries/Core/setUpDeveloperTools.js +/Libraries/Core/setUpReactDevTools.js /Libraries/Image/Image.js +/Libraries/Image/ImageViewNativeComponent.js /Libraries/Inspector/Inspector.js /Libraries/Inspector/InspectorOverlay.js /Libraries/Network/RCTNetworking.js +/Libraries/Pressability/PressabilityDebug.js /Libraries/ReactNative/getNativeComponentAttributes.js +/Libraries/StyleSheet/normalizeColor.js +/Libraries/StyleSheet/normalizeColorObject.js /Libraries/StyleSheet/processColor.js /Libraries/StyleSheet/processColorArray.js /Libraries/StyleSheet/StyleSheet.js @@ -39,10 +46,6 @@ /RNTester/js/components/ListExampleShared.js /RNTester/js/components/RNTesterExampleFilter.js -; These examples currently uses mac dynamic colors -/RNTester/js/ActivityIndicatorExample.js -/RNTester/js/DarkModeExample.js - ; Schema files are used for turbo-module code generation, but are not bundled. ; We don't yet have the react-native-codegen package they rely on, so supress ; checks for now. @@ -72,11 +75,6 @@ ; 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 - ; These should not be required directly ; require from fbjs/lib instead: require('fbjs/lib/warning') .*/node_modules/warning/.* @@ -102,7 +100,7 @@ ../../node_modules/ [libs] -Libraries/react-native/react-native-interface.js +interface.js flow/ [options] @@ -115,34 +113,10 @@ module.file_ext=.js module.file_ext=.json module.file_ext=.win32.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='^\(.*\)\.macos$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.win32$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.windesktop$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1' -module.system.haste.paths.blacklist=/src/.* -module.system.haste.paths.blacklist=.*/__tests__/.* -module.system.haste.paths.blacklist=.*/__mocks__/.* -module.system.haste.paths.whitelist=/Libraries/.* -module.system.haste.paths.whitelist=/RNTester/.* -module.system.haste.paths.whitelist=/IntegrationTests/.* -module.system.haste.paths.blacklist=/Libraries/react-native/react-native-implementation.js -module.system.haste.paths.blacklist=/Libraries/Animated/src/polyfills/.* -module.system.haste.paths.blacklist=/Libraries/Image/resolveAssetSource.js - munge_underscores=true -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' -module.name_mapper='react-native$' -> '/Libraries/react-native/react-native-implementation.js' +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\)$' -> '/Libraries/Image/RelativeImageStub' +module.name_mapper='react-native$' -> '/index.js' module.name_mapper='react-native/\(.*\)' -> '/\1' suppress_type=$FlowIssue @@ -153,8 +127,14 @@ suppress_type=$FlowFixMeEmpty suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\) suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+ +suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native\\(_android\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\) +suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_android\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+ suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError +experimental.well_formed_exports=true +experimental.types_first=true +experimental.abstract_locations=true + [lints] sketchy-null-number=warn sketchy-null-mixed=warn @@ -178,4 +158,4 @@ untyped-import untyped-type-import [version] -^0.105.0 \ No newline at end of file +^0.113.0 \ No newline at end of file diff --git a/packages/react-native-win32/.gitignore b/packages/react-native-win32/.gitignore index a16c2e663b4..08468799856 100644 --- a/packages/react-native-win32/.gitignore +++ b/packages/react-native-win32/.gitignore @@ -1,7 +1,7 @@ /dist /flow -/flow-typed /index.* +/interface.* /IntegrationTests /jest /lib @@ -9,4 +9,4 @@ /RNTester /RNTester.* /temp -/WorkingHeaders \ No newline at end of file +/typings-index.* diff --git a/packages/react-native-win32/api-extractor.json b/packages/react-native-win32/api-extractor.json index 98a562b21a7..2c856a25261 100644 --- a/packages/react-native-win32/api-extractor.json +++ b/packages/react-native-win32/api-extractor.json @@ -1,6 +1,6 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "./Libraries/react-native/typings-main.d.ts", + "mainEntryPointFilePath": "./typings-index.d.ts", "docModel": { "enabled": true }, diff --git a/packages/react-native-win32/etc/react-native-win32.api.md b/packages/react-native-win32/etc/react-native-win32.api.md index 5a1a3a6eb99..656bdd6c40c 100644 --- a/packages/react-native-win32/etc/react-native-win32.api.md +++ b/packages/react-native-win32/etc/react-native-win32.api.md @@ -51,7 +51,7 @@ export type BasePropsWin32 = { accessibilityActions?: ReadonlyArray; }; -// Warning: (ae-forgotten-export) The symbol "IButtonWin32State" needs to be exported by the entry point typings-main.d.ts +// Warning: (ae-forgotten-export) The symbol "IButtonWin32State" needs to be exported by the entry point typings-index.d.ts // // @public export class ButtonWin32 extends React_2.Component { @@ -89,7 +89,7 @@ export interface IButtonWin32Props extends RN.ButtonProps { style?: RN.StyleProp; } -// Warning: (ae-forgotten-export) The symbol "Omit" needs to be exported by the entry point typings-main.d.ts +// Warning: (ae-forgotten-export) The symbol "Omit" needs to be exported by the entry point typings-index.d.ts // // @public (undocumented) export interface IButtonWin32Style extends Omit_4 { @@ -106,7 +106,7 @@ export interface IDimensions { width: number; } -// Warning: (ae-forgotten-export) The symbol "PartiallyRequired" needs to be exported by the entry point typings-main.d.ts +// Warning: (ae-forgotten-export) The symbol "PartiallyRequired" needs to be exported by the entry point typings-index.d.ts // // @public (undocumented) export type IHandledKeyboardEvent = PartiallyRequired; @@ -152,7 +152,7 @@ export interface IPersonaCoinProps extends ViewProps { presence: PersonaCoinPresence; // (undocumented) size: PersonaCoinSize; - // Warning: (ae-forgotten-export) The symbol "IImageSourceProps" needs to be exported by the entry point typings-main.d.ts + // Warning: (ae-forgotten-export) The symbol "IImageSourceProps" needs to be exported by the entry point typings-index.d.ts // // (undocumented) source?: string | IImageSourceProps; @@ -220,7 +220,7 @@ export type IStateConditions = { [P in IState]: boolean; }; -// Warning: (ae-forgotten-export) The symbol "Omit" needs to be exported by the entry point typings-main.d.ts +// Warning: (ae-forgotten-export) The symbol "Omit" needs to be exported by the entry point typings-index.d.ts // // @public (undocumented) export interface ITextWin32Props extends Omit_3, BasePropsWin32 { @@ -302,7 +302,7 @@ export interface ITouchInfo { touchActive: boolean; } -// Warning: (ae-forgotten-export) The symbol "ISignalTransitions" needs to be exported by the entry point typings-main.d.ts +// Warning: (ae-forgotten-export) The symbol "ISignalTransitions" needs to be exported by the entry point typings-index.d.ts // // @public export type ITransitions = { @@ -315,7 +315,7 @@ export interface IViewWin32 { focus: () => void; } -// Warning: (ae-forgotten-export) The symbol "Omit" needs to be exported by the entry point typings-main.d.ts +// Warning: (ae-forgotten-export) The symbol "Omit" needs to be exported by the entry point typings-index.d.ts // // @public export interface IViewWin32Props extends Omit_2, BasePropsWin32 { @@ -425,7 +425,7 @@ export class TextWin32 extends React_2.Component { // @public (undocumented) export type TextWin32OmitTypes = RN.TextPropsAndroid & RN.TextPropsIOS & RN.AccessibilityPropsAndroid & Omit_3 & OmittedAccessibilityPropsWin32; -// Warning: (ae-forgotten-export) The symbol "IInternalTouchableWin32State" needs to be exported by the entry point typings-main.d.ts +// Warning: (ae-forgotten-export) The symbol "IInternalTouchableWin32State" needs to be exported by the entry point typings-index.d.ts // // @public export class TouchableWin32 extends React_2.Component { diff --git a/packages/react-native-win32/just-task.js b/packages/react-native-win32/just-task.js index e56e4b66486..ba25aa659cd 100644 --- a/packages/react-native-win32/just-task.js +++ b/packages/react-native-win32/just-task.js @@ -33,7 +33,7 @@ task('apiExtractorUpdate', apiExtractorUpdateTask()); task('apiDocumenter', () => { require('child_process').execSync( 'npx @microsoft/api-documenter markdown -i temp -o docs/api', - { stdio: 'inherit' }, + {stdio: 'inherit'}, ); }); @@ -41,7 +41,7 @@ task('eslint', () => { return eslintTask(); }); task('eslint:fix', () => { - return eslintTask({ fix: true }); + return eslintTask({fix: true}); }); task('copyFlowFiles', () => { return copyTask(['src/**/*.js'], '.'); @@ -54,7 +54,7 @@ task('initRNLibraries', () => { }); task('flow-check', () => { - require('child_process').execSync('npx flow check', { stdio: 'inherit' }); + require('child_process').execSync('npx flow check', {stdio: 'inherit'}); }); task('ts', () => { @@ -70,8 +70,8 @@ task('ts', () => { }); task('clean', () => { return cleanTask( - ['dist', 'flow', 'flow-typed', 'jest', 'Libraries', 'RNTester', 'lib'].map( - p => path.join(process.cwd(), p), + ['dist', 'flow', 'jest', 'Libraries', 'RNTester'].map(p => + path.join(process.cwd(), p), ), ); }); diff --git a/packages/react-native-win32/package.json b/packages/react-native-win32/package.json index 5e8ad7cfb8d..2149237bb86 100644 --- a/packages/react-native-win32/package.json +++ b/packages/react-native-win32/package.json @@ -3,8 +3,8 @@ "version": "0.0.0-master.3", "description": "Implementation of react native on top of Office's Win32 platform.", "license": "MIT", - "main": "./Libraries/react-native/react-native-implementation.win32.js", - "typings": "./Libraries/react-native/typings-main.d.ts", + "main": "./index.win32.js", + "typings": "./typings-index.d.ts", "scripts": { "build": "just-scripts build", "bundle": "just-scripts prepareBundle && react-native bundle --platform win32 --entry-file RNTester.js --bundle-output dist/win32/dev/RNTester.bundle --assets-dest dist/win32/dev --sourcemap-output ./dist/win32/dev/sourcemap.js", @@ -49,20 +49,20 @@ "@types/node": "^12.11.2", "@types/prop-types": "15.5.1", "@types/react": "16.9.0", - "@types/react-native": "~0.61.5", - "flow-bin": "^0.105.0", + "@types/react-native": "^0.62.2", + "flow-bin": "^0.113.0", "jscodeshift": "^0.6.2", "just-scripts": "^0.36.1", "react": "16.9.0", "react-native-windows-override-tools": "^0.0.1", - "react-native": "0.61.5", + "react-native": "0.62.2", "rimraf": "^3.0.0", "typescript": "^3.8.3" }, "peerDependencies": { "react": "16.9.0", "react-dom": "16.8.6", - "react-native": "0.61.5" + "react-native": "0.62.2" }, "beachball": { "defaultNpmTag": "master", diff --git a/packages/react-native-win32/src/Libraries/Alert/Alert.win32.js b/packages/react-native-win32/src/Libraries/Alert/Alert.win32.js index 935e8956f96..6ab36927761 100644 --- a/packages/react-native-win32/src/Libraries/Alert/Alert.win32.js +++ b/packages/react-native-win32/src/Libraries/Alert/Alert.win32.js @@ -25,11 +25,13 @@ export type Buttons = Array<{ text?: string, onPress?: ?Function, style?: AlertButtonStyle, + ... }>; type Options = { cancelable?: ?boolean, onDismiss?: ?() => void, + ... }; /** diff --git a/packages/react-native-win32/src/Libraries/Animated/src/nodes/AnimatedInterpolation.win32.js b/packages/react-native-win32/src/Libraries/Animated/src/nodes/AnimatedInterpolation.win32.js index daf3c0961af..b6c9c3eac4f 100644 --- a/packages/react-native-win32/src/Libraries/Animated/src/nodes/AnimatedInterpolation.win32.js +++ b/packages/react-native-win32/src/Libraries/Animated/src/nodes/AnimatedInterpolation.win32.js @@ -7,7 +7,9 @@ * @flow * @format */ + /* eslint no-bitwise: 0 */ + 'use strict'; const AnimatedNode = require('./AnimatedNode'); @@ -15,7 +17,7 @@ const AnimatedWithChildren = require('./AnimatedWithChildren'); const NativeAnimatedHelper = require('../NativeAnimatedHelper'); const invariant = require('invariant'); -const normalizeColor = require('../../../Color/normalizeColor'); +const normalizeColor = require('../../../StyleSheet/normalizeColor'); type ExtrapolateType = 'extend' | 'identity' | 'clamp'; @@ -30,6 +32,7 @@ export type InterpolationConfigType = { extrapolate?: ExtrapolateType, extrapolateLeft?: ExtrapolateType, extrapolateRight?: ExtrapolateType, + ... }; const linear = t => t; diff --git a/packages/react-native-win32/src/Libraries/Components/AccessibilityInfo/AccessibilityInfo.win32.js b/packages/react-native-win32/src/Libraries/Components/AccessibilityInfo/AccessibilityInfo.win32.js index c91a8d97049..aed6e3ff734 100644 --- a/packages/react-native-win32/src/Libraries/Components/AccessibilityInfo/AccessibilityInfo.win32.js +++ b/packages/react-native-win32/src/Libraries/Components/AccessibilityInfo/AccessibilityInfo.win32.js @@ -10,8 +10,6 @@ 'use strict'; -import NativeAccessibilityInfo from './NativeAccessibilityInfo'; - const RCTDeviceEventEmitter = require('../../EventEmitter/RCTDeviceEventEmitter'); // [Windows @@ -20,6 +18,8 @@ const RCTDeviceEventEmitter = require('../../EventEmitter/RCTDeviceEventEmitter' const SCREEN_READER_CHANGED_EVENT = 'screenReaderChanged'; // Windows] +import NativeAccessibilityInfo from './NativeAccessibilityInfo'; + const REDUCE_MOTION_EVENT = 'reduceMotionDidChange'; const TOUCH_EXPLORATION_EVENT = 'touchExplorationDidChange'; @@ -27,6 +27,7 @@ type ChangeEventName = $Keys<{ change: string, reduceMotionChanged: string, screenReaderChanged: string, + ... }>; const _subscriptions = new Map(); @@ -97,7 +98,10 @@ const AccessibilityInfo = { * * Same as `isScreenReaderEnabled` */ - get fetch() { + get fetch(): () => Promise { + console.warn( + 'AccessibilityInfo.fetch is deprecated, call Accessibility.isScreenReaderEnabled instead', + ); return this.isScreenReaderEnabled; }, diff --git a/packages/react-native-win32/src/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.win32.js b/packages/react-native-win32/src/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.win32.js index 3b1fcbdae29..4ce7ce954ba 100644 --- a/packages/react-native-win32/src/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.win32.js +++ b/packages/react-native-win32/src/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.win32.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow + * @flow strict-local * @format */ diff --git a/packages/react-native-win32/src/Libraries/Components/MaskedView/MaskedViewIOS.win32.js b/packages/react-native-win32/src/Libraries/Components/MaskedView/MaskedViewIOS.win32.js index f6d4cd7a409..c7a621c5054 100644 --- a/packages/react-native-win32/src/Libraries/Components/MaskedView/MaskedViewIOS.win32.js +++ b/packages/react-native-win32/src/Libraries/Components/MaskedView/MaskedViewIOS.win32.js @@ -2,6 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. * @format + * @flow strict-local */ 'use strict'; diff --git a/packages/react-native-win32/src/Libraries/Components/SafeAreaView/SafeAreaView.win32.js b/packages/react-native-win32/src/Libraries/Components/SafeAreaView/SafeAreaView.win32.js index b748c6db52b..905864aa732 100644 --- a/packages/react-native-win32/src/Libraries/Components/SafeAreaView/SafeAreaView.win32.js +++ b/packages/react-native-win32/src/Libraries/Components/SafeAreaView/SafeAreaView.win32.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow + * @flow strict-local * @format */ @@ -12,7 +12,7 @@ const Platform = require('../../Utilities/Platform'); const React = require('react'); const View = require('../View/View'); -import type {NativeComponent} from '../../Renderer/shims/ReactNative'; +import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes'; import type {ViewProps} from '../View/ViewPropTypes'; type Props = $ReadOnly<{| @@ -20,7 +20,10 @@ type Props = $ReadOnly<{| emulateUnlessSupported?: boolean, |}>; -let exported: Class> | Class>; +let exported: React.AbstractComponent< + Props, + React.ElementRef>, +>; /** * Renders nested content and automatically applies paddings reflect the portion @@ -34,37 +37,27 @@ let exported: Class> | Class>; // [Win32 - Added win32 to if if (Platform.OS === 'android' || Platform.OS === 'win32') { // Win32] - const SafeAreaView = ( - props: Props, - forwardedRef?: ?React.Ref, - ) => { - const {emulateUnlessSupported, ...localProps} = props; - return ; - }; - - const SafeAreaViewRef = React.forwardRef(SafeAreaView); - SafeAreaViewRef.displayName = 'SafeAreaView'; - exported = ((SafeAreaViewRef: any): Class>); + exported = React.forwardRef>>( + function SafeAreaView(props, forwardedRef) { + const {emulateUnlessSupported, ...localProps} = props; + return ; + }, + ); } else { const RCTSafeAreaViewNativeComponent = require('./RCTSafeAreaViewNativeComponent') .default; - const SafeAreaView = ( - props: Props, - forwardedRef?: ?React.Ref, - ) => { - return ( - - ); - }; - - const SafeAreaViewRef = React.forwardRef(SafeAreaView); - SafeAreaViewRef.displayName = 'SafeAreaView'; - exported = ((SafeAreaViewRef: any): Class>); + exported = React.forwardRef>>( + function SafeAreaView(props, forwardedRef) { + return ( + + ); + }, + ); } module.exports = exported; diff --git a/packages/react-native-win32/src/Libraries/Components/ScrollView/ScrollView.win32.js b/packages/react-native-win32/src/Libraries/Components/ScrollView/ScrollView.win32.js new file mode 100644 index 00000000000..5f71d0ee231 --- /dev/null +++ b/packages/react-native-win32/src/Libraries/Components/ScrollView/ScrollView.win32.js @@ -0,0 +1,1236 @@ +/** + * 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'; + +const AnimatedImplementation = require('../../Animated/src/AnimatedImplementation'); +const Platform = require('../../Utilities/Platform'); +const React = require('react'); +const ReactNative = require('../../Renderer/shims/ReactNative'); +require('../../Renderer/shims/ReactNative'); // Force side effects to prevent T55744311 +const ScrollResponder = require('../ScrollResponder'); +const ScrollViewStickyHeader = require('./ScrollViewStickyHeader'); +const StyleSheet = require('../../StyleSheet/StyleSheet'); +const View = require('../View/View'); + +const dismissKeyboard = require('../../Utilities/dismissKeyboard'); +const flattenStyle = require('../../StyleSheet/flattenStyle'); +const invariant = require('invariant'); +const processDecelerationRate = require('./processDecelerationRate'); +const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); +const resolveAssetSource = require('../../Image/resolveAssetSource'); +const splitLayoutProps = require('../../StyleSheet/splitLayoutProps'); + +import type {EdgeInsetsProp} from '../../StyleSheet/EdgeInsetsPropType'; +import type {PointProp} from '../../StyleSheet/PointPropType'; +import type {ViewStyleProp} from '../../StyleSheet/StyleSheet'; +import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; +import type { + PressEvent, + ScrollEvent, + LayoutEvent, +} from '../../Types/CoreEventTypes'; +import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes'; +import type {State as ScrollResponderState} from '../ScrollResponder'; +import type {ViewProps} from '../View/ViewPropTypes'; +import type {Props as ScrollViewStickyHeaderProps} from './ScrollViewStickyHeader'; + +import ScrollViewNativeComponent from './ScrollViewNativeComponent'; +import ScrollContentViewNativeComponent from './ScrollContentViewNativeComponent'; +import AndroidHorizontalScrollViewNativeComponent from './AndroidHorizontalScrollViewNativeComponent'; +import AndroidHorizontalScrollContentViewNativeComponent from './AndroidHorizontalScrollContentViewNativeComponent'; + +let AndroidScrollView; +let AndroidHorizontalScrollContentView; +let AndroidHorizontalScrollView; +let RCTScrollView; +let RCTScrollContentView; + +if (Platform.OS === 'android') { + AndroidScrollView = ScrollViewNativeComponent; + AndroidHorizontalScrollView = AndroidHorizontalScrollViewNativeComponent; + AndroidHorizontalScrollContentView = AndroidHorizontalScrollContentViewNativeComponent; +} else { // [Windows] Remove iOS check + RCTScrollView = ScrollViewNativeComponent; + RCTScrollContentView = ScrollContentViewNativeComponent; +} + +export type ScrollResponderType = { + // We'd like to do ...ScrollView here, however Flow doesn't seem + // to see the imperative methods of ScrollView that way. Workaround the + // issue by specifying them manually. + getScrollableNode: $PropertyType, + getInnerViewNode: $PropertyType, + getInnerViewRef: $PropertyType, + getNativeScrollRef: $PropertyType, + setNativeProps: $PropertyType, + scrollTo: $PropertyType, + flashScrollIndicators: $PropertyType, + ...typeof ScrollResponder.Mixin, + ... +}; + +type IOSProps = $ReadOnly<{| + /** + * Controls whether iOS should automatically adjust the content inset + * for scroll views that are placed behind a navigation bar or + * tab bar/ toolbar. The default value is true. + * @platform ios + */ + automaticallyAdjustContentInsets?: ?boolean, + /** + * The amount by which the scroll view content is inset from the edges + * of the scroll view. Defaults to `{top: 0, left: 0, bottom: 0, right: 0}`. + * @platform ios + */ + contentInset?: ?EdgeInsetsProp, + /** + * Used to manually set the starting scroll offset. + * The default value is `{x: 0, y: 0}`. + * @platform ios + */ + contentOffset?: ?PointProp, + /** + * When true, the scroll view bounces when it reaches the end of the + * content if the content is larger then the scroll view along the axis of + * the scroll direction. When false, it disables all bouncing even if + * the `alwaysBounce*` props are true. The default value is true. + * @platform ios + */ + bounces?: ?boolean, + /** + * By default, ScrollView has an active pan responder that hijacks panresponders + * deeper in the render tree in order to prevent accidental touches while scrolling. + * However, in certain occasions (such as when using snapToInterval) in a vertical scrollview + * You may want to disable this behavior in order to prevent the ScrollView from blocking touches + */ + disableScrollViewPanResponder?: ?boolean, + /** + * When true, gestures can drive zoom past min/max and the zoom will animate + * to the min/max value at gesture end, otherwise the zoom will not exceed + * the limits. + * @platform ios + */ + bouncesZoom?: ?boolean, + /** + * When true, the scroll view bounces horizontally when it reaches the end + * even if the content is smaller than the scroll view itself. The default + * value is true when `horizontal={true}` and false otherwise. + * @platform ios + */ + alwaysBounceHorizontal?: ?boolean, + /** + * When true, the scroll view bounces vertically when it reaches the end + * even if the content is smaller than the scroll view itself. The default + * value is false when `horizontal={true}` and true otherwise. + * @platform ios + */ + alwaysBounceVertical?: ?boolean, + /** + * When true, the scroll view automatically centers the content when the + * content is smaller than the scroll view bounds; when the content is + * larger than the scroll view, this property has no effect. The default + * value is false. + * @platform ios + */ + centerContent?: ?boolean, + /** + * The style of the scroll indicators. + * + * - `'default'` (the default), same as `black`. + * - `'black'`, scroll indicator is black. This style is good against a light background. + * - `'white'`, scroll indicator is white. This style is good against a dark background. + * + * @platform ios + */ + indicatorStyle?: ?('default' | 'black' | 'white'), + /** + * When true, the ScrollView will try to lock to only vertical or horizontal + * scrolling while dragging. The default value is false. + * @platform ios + */ + directionalLockEnabled?: ?boolean, + /** + * When false, once tracking starts, won't try to drag if the touch moves. + * The default value is true. + * @platform ios + */ + canCancelContentTouches?: ?boolean, + /** + * When set, the scroll view will adjust the scroll position so that the first child that is + * currently visible and at or beyond `minIndexForVisible` will not change position. This is + * useful for lists that are loading content in both directions, e.g. a chat thread, where new + * messages coming in might otherwise cause the scroll position to jump. A value of 0 is common, + * but other values such as 1 can be used to skip loading spinners or other content that should + * not maintain position. + * + * The optional `autoscrollToTopThreshold` can be used to make the content automatically scroll + * to the top after making the adjustment if the user was within the threshold of the top before + * the adjustment was made. This is also useful for chat-like applications where you want to see + * new messages scroll into place, but not if the user has scrolled up a ways and it would be + * disruptive to scroll a bunch. + * + * Caveat 1: Reordering elements in the scrollview with this enabled will probably cause + * jumpiness and jank. It can be fixed, but there are currently no plans to do so. For now, + * don't re-order the content of any ScrollViews or Lists that use this feature. + * + * Caveat 2: This simply uses `contentOffset` and `frame.origin` in native code to compute + * visibility. Occlusion, transforms, and other complexity won't be taken into account as to + * whether content is "visible" or not. + * + * @platform ios + */ + maintainVisibleContentPosition?: ?$ReadOnly<{| + minIndexForVisible: number, + autoscrollToTopThreshold?: ?number, + |}>, + /** + * The maximum allowed zoom scale. The default value is 1.0. + * @platform ios + */ + maximumZoomScale?: ?number, + /** + * The minimum allowed zoom scale. The default value is 1.0. + * @platform ios + */ + minimumZoomScale?: ?number, + /** + * When true, ScrollView allows use of pinch gestures to zoom in and out. + * The default value is true. + * @platform ios + */ + pinchGestureEnabled?: ?boolean, + /** + * This controls how often the scroll event will be fired while scrolling + * (as a time interval in ms). A lower number yields better accuracy for code + * that is tracking the scroll position, but can lead to scroll performance + * problems due to the volume of information being send over the bridge. + * + * Values between 0 and 17ms indicate 60fps updates are needed and throttling + * will be disabled. + * + * If you do not need precise scroll position tracking, set this value higher + * to limit the information being sent across the bridge. + * + * The default value is zero, which results in the scroll event being sent only + * once each time the view is scrolled. + * + * @platform ios + */ + scrollEventThrottle?: ?number, + /** + * The amount by which the scroll view indicators are inset from the edges + * of the scroll view. This should normally be set to the same value as + * the `contentInset`. Defaults to `{0, 0, 0, 0}`. + * @platform ios + */ + scrollIndicatorInsets?: ?EdgeInsetsProp, + /** + * When true, the scroll view can be programmatically scrolled beyond its + * content size. The default value is false. + * @platform ios + */ + scrollToOverflowEnabled?: ?boolean, + /** + * When true, the scroll view scrolls to top when the status bar is tapped. + * The default value is true. + * @platform ios + */ + scrollsToTop?: ?boolean, + /** + * Fires when the scroll view scrolls to top after the status bar has been tapped + * @platform ios + */ + onScrollToTop?: (event: ScrollEvent) => void, + /** + * When true, shows a horizontal scroll indicator. + * The default value is true. + */ + showsHorizontalScrollIndicator?: ?boolean, + /** + * When `snapToInterval` is set, `snapToAlignment` will define the relationship + * of the snapping to the scroll view. + * + * - `'start'` (the default) will align the snap at the left (horizontal) or top (vertical) + * - `'center'` will align the snap in the center + * - `'end'` will align the snap at the right (horizontal) or bottom (vertical) + * + * @platform ios + */ + snapToAlignment?: ?('start' | 'center' | 'end'), + /** + * The current scale of the scroll view content. The default value is 1.0. + * @platform ios + */ + zoomScale?: ?number, + /** + * This property specifies how the safe area insets are used to modify the + * content area of the scroll view. The default value of this property is + * "never". Available on iOS 11 and later. + * @platform ios + */ + contentInsetAdjustmentBehavior?: ?( + | 'automatic' + | 'scrollableAxes' + | 'never' + | 'always' + ), + /** + * When true, ScrollView will emit updateChildFrames data in scroll events, + * otherwise will not compute or emit child frame data. This only exists + * to support legacy issues, `onLayout` should be used instead to retrieve + * frame data. + * The default value is false. + * @platform ios + */ + DEPRECATED_sendUpdatedChildFrames?: ?boolean, +|}>; + +type AndroidProps = $ReadOnly<{| + /** + * Enables nested scrolling for Android API level 21+. + * Nested scrolling is supported by default on iOS + * @platform android + */ + nestedScrollEnabled?: ?boolean, + /** + * Sometimes a scrollview takes up more space than its content fills. When this is + * the case, this prop will fill the rest of the scrollview with a color to avoid setting + * a background and creating unnecessary overdraw. This is an advanced optimization + * that is not needed in the general case. + * @platform android + */ + endFillColor?: ?ColorValue, + /** + * Tag used to log scroll performance on this scroll view. Will force + * momentum events to be turned on (see sendMomentumEvents). This doesn't do + * anything out of the box and you need to implement a custom native + * FpsListener for it to be useful. + * @platform android + */ + scrollPerfTag?: ?string, + /** + * Used to override default value of overScroll mode. + * + * Possible values: + * + * - `'auto'` - Default value, allow a user to over-scroll + * this view only if the content is large enough to meaningfully scroll. + * - `'always'` - Always allow a user to over-scroll this view. + * - `'never'` - Never allow a user to over-scroll this view. + * + * @platform android + */ + overScrollMode?: ?('auto' | 'always' | 'never'), + /** + * Causes the scrollbars not to turn transparent when they are not in use. + * The default value is false. + * + * @platform android + */ + persistentScrollbar?: ?boolean, + /** + * Fades out the edges of the the scroll content. + * + * If the value is greater than 0, the fading edges will be set accordingly + * to the current scroll direction and position, + * indicating if there is more content to show. + * + * The default value is 0. + * + * @platform android + */ + fadingEdgeLength?: ?number, +|}>; + +type VRProps = $ReadOnly<{| + /** + * Optionally an image can be used for the scroll bar thumb. This will + * override the color. While the image is loading or the image fails to + * load the color will be used instead. Use an alpha of 0 in the color + * to avoid seeing it while the image is loading. + * + * - `uri` - a string representing the resource identifier for the image, which + * should be either a local file path or the name of a static image resource + * - `number` - Opaque type returned by something like + * `import IMAGE from './image.jpg'`. + * @platform vr + */ + scrollBarThumbImage?: ?($ReadOnly<{||}> | number), // Opaque type returned by import IMAGE from './image.jpg' +|}>; + +type StickyHeaderComponentType = React.AbstractComponent< + ScrollViewStickyHeaderProps, + $ReadOnly<{setNextHeaderY: number => void, ...}>, +>; + +export type Props = $ReadOnly<{| + ...ViewProps, + ...IOSProps, + ...AndroidProps, + ...VRProps, + + /** + * These styles will be applied to the scroll view content container which + * wraps all of the child views. Example: + * + * ``` + * return ( + * + * + * ); + * ... + * const styles = StyleSheet.create({ + * contentContainer: { + * paddingVertical: 20 + * } + * }); + * ``` + */ + contentContainerStyle?: ?ViewStyleProp, + /** + * When true, the scroll view stops on the next index (in relation to scroll + * position at release) regardless of how fast the gesture is. This can be + * used for horizontal pagination when the page is less than the width of + * the ScrollView. The default value is false. + */ + disableIntervalMomentum?: ?boolean, + /** + * A floating-point number that determines how quickly the scroll view + * decelerates after the user lifts their finger. You may also use string + * shortcuts `"normal"` and `"fast"` which match the underlying iOS settings + * for `UIScrollViewDecelerationRateNormal` and + * `UIScrollViewDecelerationRateFast` respectively. + * + * - `'normal'`: 0.998 on iOS, 0.985 on Android (the default) + * - `'fast'`: 0.99 on iOS, 0.9 on Android + */ + decelerationRate?: ?('fast' | 'normal' | number), + /** + * When true, the scroll view's children are arranged horizontally in a row + * instead of vertically in a column. The default value is false. + */ + horizontal?: ?boolean, + /** + * If sticky headers should stick at the bottom instead of the top of the + * ScrollView. This is usually used with inverted ScrollViews. + */ + invertStickyHeaders?: ?boolean, + /** + * Determines whether the keyboard gets dismissed in response to a drag. + * + * *Cross platform* + * + * - `'none'` (the default), drags do not dismiss the keyboard. + * - `'on-drag'`, the keyboard is dismissed when a drag begins. + * + * *iOS Only* + * + * - `'interactive'`, the keyboard is dismissed interactively with the drag and moves in + * synchrony with the touch; dragging upwards cancels the dismissal. + * On android this is not supported and it will have the same behavior as 'none'. + */ + keyboardDismissMode?: ?// default + (| 'none' // cross-platform + | 'on-drag' + | 'interactive' + ), // ios only + /** + * Determines when the keyboard should stay visible after a tap. + * + * - `'never'` (the default), tapping outside of the focused text input when the keyboard + * is up dismisses the keyboard. When this happens, children won't receive the tap. + * - `'always'`, the keyboard will not dismiss automatically, and the scroll view will not + * catch taps, but children of the scroll view can catch taps. + * - `'handled'`, the keyboard will not dismiss automatically when the tap was handled by + * a children, (or captured by an ancestor). + * - `false`, deprecated, use 'never' instead + * - `true`, deprecated, use 'always' instead + */ + keyboardShouldPersistTaps?: ?('always' | 'never' | 'handled' | true | false), + /** + * Called when the momentum scroll starts (scroll which occurs as the ScrollView glides to a stop). + */ + onMomentumScrollBegin?: ?(event: ScrollEvent) => void, + /** + * Called when the momentum scroll ends (scroll which occurs as the ScrollView glides to a stop). + */ + onMomentumScrollEnd?: ?(event: ScrollEvent) => void, + + /** + * Fires at most once per frame during scrolling. The frequency of the + * events can be controlled using the `scrollEventThrottle` prop. + */ + onScroll?: ?(event: ScrollEvent) => void, + /** + * Called when the user begins to drag the scroll view. + */ + onScrollBeginDrag?: ?(event: ScrollEvent) => void, + /** + * Called when the user stops dragging the scroll view and it either stops + * or begins to glide. + */ + onScrollEndDrag?: ?(event: ScrollEvent) => void, + /** + * Called when scrollable content view of the ScrollView changes. + * + * Handler function is passed the content width and content height as parameters: + * `(contentWidth, contentHeight)` + * + * It's implemented using onLayout handler attached to the content container + * which this ScrollView renders. + */ + onContentSizeChange?: (contentWidth: number, contentHeight: number) => void, + onKeyboardDidShow?: (event: PressEvent) => void, + /** + * When true, the scroll view stops on multiples of the scroll view's size + * when scrolling. This can be used for horizontal pagination. The default + * value is false. + * + * Note: Vertical pagination is not supported on Android. + */ + pagingEnabled?: ?boolean, + + /** + * When false, the view cannot be scrolled via touch interaction. + * The default value is true. + * + * Note that the view can always be scrolled by calling `scrollTo`. + */ + scrollEnabled?: ?boolean, + /** + * When true, shows a vertical scroll indicator. + * The default value is true. + */ + showsVerticalScrollIndicator?: ?boolean, + /** + * An array of child indices determining which children get docked to the + * top of the screen when scrolling. For example, passing + * `stickyHeaderIndices={[0]}` will cause the first child to be fixed to the + * top of the scroll view. This property is not supported in conjunction + * with `horizontal={true}`. + */ + stickyHeaderIndices?: ?$ReadOnlyArray, + /** + * A React Component that will be used to render sticky headers. + * To be used together with `stickyHeaderIndices` or with `SectionList`, defaults to `ScrollViewStickyHeader`. + * You may need to set this if your sticky header uses custom transforms (eg. translation), + * for example when you want your list to have an animated hidable header. + */ + StickyHeaderComponent?: StickyHeaderComponentType, + /** + * When set, causes the scroll view to stop at multiples of the value of + * `snapToInterval`. This can be used for paginating through children + * that have lengths smaller than the scroll view. Typically used in + * combination with `snapToAlignment` and `decelerationRate="fast"`. + * + * Overrides less configurable `pagingEnabled` prop. + */ + snapToInterval?: ?number, + /** + * When set, causes the scroll view to stop at the defined offsets. + * This can be used for paginating through variously sized children + * that have lengths smaller than the scroll view. Typically used in + * combination with `decelerationRate="fast"`. + * + * Overrides less configurable `pagingEnabled` and `snapToInterval` props. + */ + snapToOffsets?: ?$ReadOnlyArray, + /** + * Use in conjunction with `snapToOffsets`. By default, the beginning + * of the list counts as a snap offset. Set `snapToStart` to false to disable + * this behavior and allow the list to scroll freely between its start and + * the first `snapToOffsets` offset. + * The default value is true. + */ + snapToStart?: ?boolean, + /** + * Use in conjunction with `snapToOffsets`. By default, the end + * of the list counts as a snap offset. Set `snapToEnd` to false to disable + * this behavior and allow the list to scroll freely between its end and + * the last `snapToOffsets` offset. + * The default value is true. + */ + snapToEnd?: ?boolean, + /** + * Experimental: When true, offscreen child views (whose `overflow` value is + * `hidden`) are removed from their native backing superview when offscreen. + * This can improve scrolling performance on long lists. The default value is + * true. + */ + removeClippedSubviews?: ?boolean, + /** + * A RefreshControl component, used to provide pull-to-refresh + * functionality for the ScrollView. Only works for vertical ScrollViews + * (`horizontal` prop must be `false`). + * + * See [RefreshControl](docs/refreshcontrol.html). + */ + // $FlowFixMe - how to handle generic type without existential operator? + refreshControl?: ?React.Element, + children?: React.Node, +|}>; + +type State = {| + layoutHeight: ?number, + ...ScrollResponderState, +|}; + +function createScrollResponder( + node: React.ElementRef, +): typeof ScrollResponder.Mixin { + const scrollResponder = {...ScrollResponder.Mixin}; + + for (const key in scrollResponder) { + if (typeof scrollResponder[key] === 'function') { + scrollResponder[key] = scrollResponder[key].bind(node); + } + } + + return scrollResponder; +} + +type ContextType = {|horizontal: boolean|} | null; +const Context = React.createContext(null); +const standardHorizontalContext: ContextType = Object.freeze({ + horizontal: true, +}); +const standardVerticalContext: ContextType = Object.freeze({horizontal: false}); + +/** + * Component that wraps platform ScrollView while providing + * integration with touch locking "responder" system. + * + * Keep in mind that ScrollViews must have a bounded height in order to work, + * since they contain unbounded-height children into a bounded container (via + * a scroll interaction). In order to bound the height of a ScrollView, either + * set the height of the view directly (discouraged) or make sure all parent + * views have bounded height. Forgetting to transfer `{flex: 1}` down the + * view stack can lead to errors here, which the element inspector makes + * easy to debug. + * + * Doesn't yet support other contained responders from blocking this scroll + * view from becoming the responder. + * + * + * `` vs [``](/react-native/docs/flatlist.html) - which one to use? + * + * `ScrollView` simply renders all its react child components at once. That + * makes it very easy to understand and use. + * + * On the other hand, this has a performance downside. Imagine you have a very + * long list of items you want to display, maybe several screens worth of + * content. Creating JS components and native views for everything all at once, + * much of which may not even be shown, will contribute to slow rendering and + * increased memory usage. + * + * This is where `FlatList` comes into play. `FlatList` renders items lazily, + * just when they are about to appear, and removes items that scroll way off + * screen to save memory and processing time. + * + * `FlatList` is also handy if you want to render separators between your items, + * multiple columns, infinite scroll loading, or any number of other features it + * supports out of the box. + */ +class ScrollView extends React.Component { + static Context: React$Context = Context; + /** + * Part 1: Removing ScrollResponder.Mixin: + * + * 1. Mixin methods should be flow typed. That's why we create a + * copy of ScrollResponder.Mixin and attach it to this._scrollResponder. + * Otherwise, we'd have to manually declare each method on the component + * class and assign it a flow type. + * 2. Mixin methods can call component methods, and access the component's + * props and state. So, we need to bind all mixin methods to the + * component instance. + * 3. Continued... + */ + _scrollResponder: typeof ScrollResponder.Mixin = createScrollResponder(this); + + constructor(props: Props) { + super(props); + + /** + * Part 2: Removing ScrollResponder.Mixin + * + * 3. Mixin methods access other mixin methods via dynamic dispatch using + * this. Since mixin methods are bound to the component instance, we need + * to copy all mixin methods to the component instance. This is also + * necessary because getScrollResponder() is a public method that returns + * an object that can be used to execute all scrollResponder methods. + * Since the object returned from that method is the ScrollView instance, + * we need to bind all mixin methods to the ScrollView instance. + */ + for (const key in ScrollResponder.Mixin) { + if ( + typeof ScrollResponder.Mixin[key] === 'function' && + key.startsWith('scrollResponder') + ) { + // $FlowFixMe - dynamically adding properties to a class + (this: any)[key] = ScrollResponder.Mixin[key].bind(this); + } + } + + /** + * Part 3: Removing ScrollResponder.Mixin + * + * 4. Mixins can initialize properties and use properties on the component + * instance. + */ + Object.keys(ScrollResponder.Mixin) + .filter(key => typeof ScrollResponder.Mixin[key] !== 'function') + .forEach(key => { + // $FlowFixMe - dynamically adding properties to a class + (this: any)[key] = ScrollResponder.Mixin[key]; + }); + } + + _scrollAnimatedValue: AnimatedImplementation.Value = new AnimatedImplementation.Value( + 0, + ); + _scrollAnimatedValueAttachment: ?{detach: () => void, ...} = null; + _stickyHeaderRefs: Map< + string, + React.ElementRef, + > = new Map(); + _headerLayoutYs: Map = new Map(); + + state: State = { + layoutHeight: null, + ...ScrollResponder.Mixin.scrollResponderMixinGetInitialState(), + }; + + UNSAFE_componentWillMount() { + this._scrollResponder.UNSAFE_componentWillMount(); + this._scrollAnimatedValue = new AnimatedImplementation.Value( + this.props.contentOffset ? this.props.contentOffset.y : 0, + ); + this._scrollAnimatedValue.setOffset( + this.props.contentInset ? this.props.contentInset.top || 0 : 0, + ); + this._stickyHeaderRefs = new Map(); + this._headerLayoutYs = new Map(); + } + + UNSAFE_componentWillReceiveProps(nextProps: Props) { + const currentContentInsetTop = this.props.contentInset + ? this.props.contentInset.top + : 0; + const nextContentInsetTop = nextProps.contentInset + ? nextProps.contentInset.top + : 0; + if (currentContentInsetTop !== nextContentInsetTop) { + this._scrollAnimatedValue.setOffset(nextContentInsetTop || 0); + } + } + + componentDidMount() { + this._updateAnimatedNodeAttachment(); + } + + componentDidUpdate() { + this._updateAnimatedNodeAttachment(); + } + + componentWillUnmount() { + this._scrollResponder.componentWillUnmount(); + if (this._scrollAnimatedValueAttachment) { + this._scrollAnimatedValueAttachment.detach(); + } + } + + setNativeProps(props: {[key: string]: mixed, ...}) { + this._scrollViewRef && this._scrollViewRef.setNativeProps(props); + } + + /** + * Returns a reference to the underlying scroll responder, which supports + * operations like `scrollTo`. All ScrollView-like components should + * implement this method so that they can be composed while providing access + * to the underlying scroll responder's methods. + */ + getScrollResponder(): ScrollResponderType { + // $FlowFixMe - overriding type to include ScrollResponder.Mixin + return ((this: any): ScrollResponderType); + } + + getScrollableNode(): ?number { + return ReactNative.findNodeHandle(this._scrollViewRef); + } + + getInnerViewNode(): ?number { + return ReactNative.findNodeHandle(this._innerViewRef); + } + + getInnerViewRef(): ?React.ElementRef> { + return this._innerViewRef; + } + + getNativeScrollRef(): ?React.ElementRef> { + return this._scrollViewRef; + } + + /** + * Scrolls to a given x, y offset, either immediately or with a smooth animation. + * + * Example: + * + * `scrollTo({x: 0, y: 0, animated: true})` + * + * Note: The weird function signature is due to the fact that, for historical reasons, + * the function also accepts separate arguments as an alternative to the options object. + * This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED. + */ + scrollTo( + options?: + | { + x?: number, + y?: number, + animated?: boolean, + ... + } + | number, + deprecatedX?: number, + deprecatedAnimated?: boolean, + ) { + let x, y, animated; + if (typeof options === 'number') { + console.warn( + '`scrollTo(y, x, animated)` is deprecated. Use `scrollTo({x: 5, y: 5, ' + + 'animated: true})` instead.', + ); + y = options; + x = deprecatedX; + animated = deprecatedAnimated; + } else if (options) { + y = options.y; + x = options.x; + animated = options.animated; + } + this._scrollResponder.scrollResponderScrollTo({ + x: x || 0, + y: y || 0, + animated: animated !== false, + }); + } + + /** + * If this is a vertical ScrollView scrolls to the bottom. + * If this is a horizontal ScrollView scrolls to the right. + * + * Use `scrollToEnd({animated: true})` for smooth animated scrolling, + * `scrollToEnd({animated: false})` for immediate scrolling. + * If no options are passed, `animated` defaults to true. + */ + scrollToEnd(options?: ?{animated?: boolean, ...}) { + // Default to true + const animated = (options && options.animated) !== false; + this._scrollResponder.scrollResponderScrollToEnd({ + animated: animated, + }); + } + + /** + * Displays the scroll indicators momentarily. + * + * @platform ios + */ + flashScrollIndicators() { + this._scrollResponder.scrollResponderFlashScrollIndicators(); + } + + _getKeyForIndex(index, childArray) { + const child = childArray[index]; + return child && child.key; + } + + _updateAnimatedNodeAttachment() { + if (this._scrollAnimatedValueAttachment) { + this._scrollAnimatedValueAttachment.detach(); + } + if ( + this.props.stickyHeaderIndices && + this.props.stickyHeaderIndices.length > 0 + ) { + this._scrollAnimatedValueAttachment = AnimatedImplementation.attachNativeEvent( + this._scrollViewRef, + 'onScroll', + [{nativeEvent: {contentOffset: {y: this._scrollAnimatedValue}}}], + ); + } + } + + _setStickyHeaderRef( + key: string, + ref: ?React.ElementRef, + ) { + if (ref) { + this._stickyHeaderRefs.set(key, ref); + } else { + this._stickyHeaderRefs.delete(key); + } + } + + _onStickyHeaderLayout(index, event, key) { + const {stickyHeaderIndices} = this.props; + if (!stickyHeaderIndices) { + return; + } + const childArray = React.Children.toArray(this.props.children); + if (key !== this._getKeyForIndex(index, childArray)) { + // ignore stale layout update + return; + } + + const layoutY = event.nativeEvent.layout.y; + this._headerLayoutYs.set(key, layoutY); + + const indexOfIndex = stickyHeaderIndices.indexOf(index); + const previousHeaderIndex = stickyHeaderIndices[indexOfIndex - 1]; + if (previousHeaderIndex != null) { + const previousHeader = this._stickyHeaderRefs.get( + this._getKeyForIndex(previousHeaderIndex, childArray), + ); + previousHeader && + previousHeader.setNextHeaderY && + previousHeader.setNextHeaderY(layoutY); + } + } + + _handleScroll = (e: ScrollEvent) => { + if (__DEV__) { + if ( + this.props.onScroll && + this.props.scrollEventThrottle == null && + Platform.OS === 'ios' + ) { + console.log( + 'You specified `onScroll` on a but not ' + + '`scrollEventThrottle`. You will only receive one event. ' + + 'Using `16` you get all the events but be aware that it may ' + + "cause frame drops, use a bigger number if you don't need as " + + 'much precision.', + ); + } + } + if (Platform.OS === 'android') { + if ( + this.props.keyboardDismissMode === 'on-drag' && + this.state.isTouching + ) { + dismissKeyboard(); + } + } + this._scrollResponder.scrollResponderHandleScroll(e); + }; + + _handleLayout = (e: LayoutEvent) => { + if (this.props.invertStickyHeaders === true) { + this.setState({layoutHeight: e.nativeEvent.layout.height}); + } + if (this.props.onLayout) { + this.props.onLayout(e); + } + }; + + _handleContentOnLayout = (e: LayoutEvent) => { + const {width, height} = e.nativeEvent.layout; + this.props.onContentSizeChange && + this.props.onContentSizeChange(width, height); + }; + + _scrollViewRef: ?React.ElementRef> = null; + _setScrollViewRef = (ref: ?React.ElementRef>) => { + this._scrollViewRef = ref; + }; + + _innerViewRef: ?React.ElementRef> = null; + _setInnerViewRef = (ref: ?React.ElementRef>) => { + this._innerViewRef = ref; + }; + + render(): React.Node | React.Element { + let ScrollViewClass; + let ScrollContentContainerViewClass; + if (Platform.OS === 'android') { + if (this.props.horizontal === true) { + ScrollViewClass = AndroidHorizontalScrollView; + ScrollContentContainerViewClass = AndroidHorizontalScrollContentView; + } else { + ScrollViewClass = AndroidScrollView; + ScrollContentContainerViewClass = View; + } + } else { + ScrollViewClass = RCTScrollView; + ScrollContentContainerViewClass = RCTScrollContentView; + } + + invariant( + ScrollViewClass !== undefined, + 'ScrollViewClass must not be undefined', + ); + + invariant( + ScrollContentContainerViewClass !== undefined, + 'ScrollContentContainerViewClass must not be undefined', + ); + + const contentContainerStyle = [ + this.props.horizontal === true && styles.contentContainerHorizontal, + this.props.contentContainerStyle, + ]; + if (__DEV__ && this.props.style !== undefined) { + const style = flattenStyle(this.props.style); + const childLayoutProps = ['alignItems', 'justifyContent'].filter( + prop => style && style[prop] !== undefined, + ); + invariant( + childLayoutProps.length === 0, + 'ScrollView child layout (' + + JSON.stringify(childLayoutProps) + + ') must be applied through the contentContainerStyle prop.', + ); + } + + let contentSizeChangeProps = {}; + if (this.props.onContentSizeChange) { + contentSizeChangeProps = { + onLayout: this._handleContentOnLayout, + }; + } + + const {stickyHeaderIndices} = this.props; + let children = this.props.children; + + if (stickyHeaderIndices != null && stickyHeaderIndices.length > 0) { + const childArray = React.Children.toArray(this.props.children); + + children = childArray.map((child, index) => { + const indexOfIndex = child ? stickyHeaderIndices.indexOf(index) : -1; + if (indexOfIndex > -1) { + const key = child.key; + const nextIndex = stickyHeaderIndices[indexOfIndex + 1]; + const StickyHeaderComponent = + this.props.StickyHeaderComponent || ScrollViewStickyHeader; + return ( + this._setStickyHeaderRef(key, ref)} + nextHeaderLayoutY={this._headerLayoutYs.get( + this._getKeyForIndex(nextIndex, childArray), + )} + onLayout={event => this._onStickyHeaderLayout(index, event, key)} + scrollAnimatedValue={this._scrollAnimatedValue} + inverted={this.props.invertStickyHeaders} + scrollViewHeight={this.state.layoutHeight}> + {child} + + ); + } else { + return child; + } + }); + } + children = ( + + {children} + + ); + + const hasStickyHeaders = + Array.isArray(stickyHeaderIndices) && stickyHeaderIndices.length > 0; + + const contentContainer = ( + /* $FlowFixMe(>=0.112.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.112 was deployed. To see the error, delete + * this comment and run Flow. */ + + {children} + + ); + + const alwaysBounceHorizontal = + this.props.alwaysBounceHorizontal !== undefined + ? this.props.alwaysBounceHorizontal + : this.props.horizontal; + + const alwaysBounceVertical = + this.props.alwaysBounceVertical !== undefined + ? this.props.alwaysBounceVertical + : !this.props.horizontal; + + const DEPRECATED_sendUpdatedChildFrames = !!this.props + .DEPRECATED_sendUpdatedChildFrames; + + const baseStyle = + this.props.horizontal === true + ? styles.baseHorizontal + : styles.baseVertical; + const props = { + ...this.props, + alwaysBounceHorizontal, + alwaysBounceVertical, + style: [baseStyle, this.props.style], + // Override the onContentSizeChange from props, since this event can + // bubble up from TextInputs + onContentSizeChange: null, + onLayout: this._handleLayout, + onMomentumScrollBegin: this._scrollResponder + .scrollResponderHandleMomentumScrollBegin, + onMomentumScrollEnd: this._scrollResponder + .scrollResponderHandleMomentumScrollEnd, + onResponderGrant: this._scrollResponder + .scrollResponderHandleResponderGrant, + onResponderReject: this._scrollResponder + .scrollResponderHandleResponderReject, + onResponderRelease: this._scrollResponder + .scrollResponderHandleResponderRelease, + onResponderTerminationRequest: this._scrollResponder + .scrollResponderHandleTerminationRequest, + onScrollBeginDrag: this._scrollResponder + .scrollResponderHandleScrollBeginDrag, + onScrollEndDrag: this._scrollResponder.scrollResponderHandleScrollEndDrag, + onScrollShouldSetResponder: this._scrollResponder + .scrollResponderHandleScrollShouldSetResponder, + onStartShouldSetResponder: this._scrollResponder + .scrollResponderHandleStartShouldSetResponder, + onStartShouldSetResponderCapture: this._scrollResponder + .scrollResponderHandleStartShouldSetResponderCapture, + onTouchEnd: this._scrollResponder.scrollResponderHandleTouchEnd, + onTouchMove: this._scrollResponder.scrollResponderHandleTouchMove, + onTouchStart: this._scrollResponder.scrollResponderHandleTouchStart, + onTouchCancel: this._scrollResponder.scrollResponderHandleTouchCancel, + onScroll: this._handleScroll, + scrollBarThumbImage: resolveAssetSource(this.props.scrollBarThumbImage), + scrollEventThrottle: hasStickyHeaders + ? 1 + : this.props.scrollEventThrottle, + sendMomentumEvents: + this.props.onMomentumScrollBegin || this.props.onMomentumScrollEnd + ? true + : false, + DEPRECATED_sendUpdatedChildFrames, + // default to true + snapToStart: this.props.snapToStart !== false, + // default to true + snapToEnd: this.props.snapToEnd !== false, + // pagingEnabled is overridden by snapToInterval / snapToOffsets + pagingEnabled: Platform.select({ + // on iOS, pagingEnabled must be set to false to have snapToInterval / snapToOffsets work + ios: + this.props.pagingEnabled === true && + this.props.snapToInterval == null && + this.props.snapToOffsets == null, + // on Android, pagingEnabled must be set to true to have snapToInterval / snapToOffsets work + android: + this.props.pagingEnabled === true || + this.props.snapToInterval != null || + this.props.snapToOffsets != null, + // on Windows, pagingEnabled must be set to false to have snapToInterval / snapToOffsets work + windows: + this.props.pagingEnabled === true && + this.props.snapToInterval == null && + this.props.snapToOffsets == null, + }), + }; + + const {decelerationRate} = this.props; + if (decelerationRate != null) { + props.decelerationRate = processDecelerationRate(decelerationRate); + } + + const refreshControl = this.props.refreshControl; + + if (refreshControl) { + if (Platform.OS === 'ios') { + // On iOS the RefreshControl is a child of the ScrollView. + // tvOS lacks native support for RefreshControl, so don't include it in that case + return ( + + {Platform.isTV ? null : refreshControl} + {contentContainer} + + ); + } else if (Platform.OS === 'android') { + // On Android wrap the ScrollView with a AndroidSwipeRefreshLayout. + // Since the ScrollView is wrapped add the style props to the + // AndroidSwipeRefreshLayout and use flex: 1 for the ScrollView. + // Note: we should split props.style on the inner and outer props + // however, the ScrollView still needs the baseStyle to be scrollable + const {outer, inner} = splitLayoutProps(flattenStyle(props.style)); + return React.cloneElement( + refreshControl, + {style: [baseStyle, outer]}, + + {contentContainer} + , + ); + } else if (Platform.OS === 'windows') { + const {outer, inner} = splitLayoutProps(flattenStyle(props.style)); + return React.cloneElement( + refreshControl, + {style: [baseStyle, outer]}, + + {contentContainer} + , + ); + } + } + return ( + + {contentContainer} + + ); + } +} + +const styles = StyleSheet.create({ + baseVertical: { + flexGrow: 1, + flexShrink: 1, + flexDirection: 'column', + overflow: 'scroll', + }, + baseHorizontal: { + flexGrow: 1, + flexShrink: 1, + flexDirection: 'row', + overflow: 'scroll', + }, + contentContainerHorizontal: { + flexDirection: 'row', + }, +}); + +module.exports = ScrollView; diff --git a/packages/react-native-win32/src/Libraries/Components/StatusBar/NativeStatusBarManagerAndroid.win32.js b/packages/react-native-win32/src/Libraries/Components/StatusBar/NativeStatusBarManagerAndroid.win32.js new file mode 100644 index 00000000000..62400bd0df7 --- /dev/null +++ b/packages/react-native-win32/src/Libraries/Components/StatusBar/NativeStatusBarManagerAndroid.win32.js @@ -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. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; +import type {NativeOrDynamicColorType} from '../../StyleSheet/NativeOrDynamicColorType'; // [Win32] + +export interface Spec extends TurboModule { + +getConstants: () => {| + +HEIGHT: number, + +DEFAULT_BACKGROUND_COLOR: number, + |}; + // [Win32 Allow NativeOrDynamicColorType to make Flow happy (this will never be called) + +setColor: ( + color: number | NativeOrDynamicColorType, + animated: boolean, + ) => void; + // Win32] + +setTranslucent: (translucent: boolean) => void; + + /** + * - statusBarStyles can be: + * - 'default' + * - 'dark-content' + */ + +setStyle: (statusBarStyle?: ?string) => void; + +setHidden: (hidden: boolean) => void; +} + +// [Win32 Change from getEnforcing to get and provide a stub (See #4363) +let NativeStausBarManager = TurboModuleRegistry.get('StatusBarManager'); +if (!NativeStausBarManager) { + NativeStausBarManager = { + getConstants: () => ({HEIGHT: 0, DEFAULT_BACKGROUND_COLOR: 0}), + setColor: ( + color: number | NativeOrDynamicColorType, + animated: boolean, + ) => {}, + setTranslucent: (translucent: boolean) => {}, + setStyle: (statusBarStyle?: ?string) => {}, + setHidden: (hidden: boolean) => {}, + }; +} + +export default (NativeStausBarManager: Spec); +// Win32] diff --git a/packages/react-native-win32/src/Libraries/Components/StatusBar/NativeStatusBarManagerIOS.win32.js b/packages/react-native-win32/src/Libraries/Components/StatusBar/NativeStatusBarManagerIOS.win32.js new file mode 100644 index 00000000000..d298cae8d71 --- /dev/null +++ b/packages/react-native-win32/src/Libraries/Components/StatusBar/NativeStatusBarManagerIOS.win32.js @@ -0,0 +1,45 @@ +/** + * 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 strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => {| + +HEIGHT: number, + +DEFAULT_BACKGROUND_COLOR?: number, + |}; + + // TODO(T47754272) Can we remove this method? + +getHeight: (callback: (result: {|height: number|}) => void) => void; + +setNetworkActivityIndicatorVisible: (visible: boolean) => void; + +addListener: (eventType: string) => void; + +removeListeners: (count: number) => void; + + /** + * - statusBarStyles can be: + * - 'default' + * - 'dark-content' + * - 'light-content' + */ + +setStyle: (statusBarStyle?: ?string, animated: boolean) => void; + /** + * - withAnimation can be: 'none' | 'fade' | 'slide' + */ + +setHidden: (hidden: boolean, withAnimation: string) => void; +} + +// [Win32 Do not enforce native module is present +export default (TurboModuleRegistry.get( + 'StatusBarManager', +): ?Spec); +// Win32] diff --git a/packages/react-native-win32/src/Libraries/Components/StatusBar/StatusBar.win32.ts b/packages/react-native-win32/src/Libraries/Components/StatusBar/StatusBar.win32.ts deleted file mode 100644 index b0f877f19c2..00000000000 --- a/packages/react-native-win32/src/Libraries/Components/StatusBar/StatusBar.win32.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT license. - * - * @format - */ -'use strict'; - -// @ts-ignore This file is present after the JS build -import * as UnimplementedView from '../UnimplementedViews/UnimplementedView'; -import {StatusBarProps} from 'react-native'; - -class StatusBar extends UnimplementedView {} - -export = StatusBar; diff --git a/packages/react-native-win32/src/Libraries/Components/StatusBar/StatusBarIOS.win32.ts b/packages/react-native-win32/src/Libraries/Components/StatusBar/StatusBarIOS.win32.ts deleted file mode 100644 index 4ec9e204c68..00000000000 --- a/packages/react-native-win32/src/Libraries/Components/StatusBar/StatusBarIOS.win32.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * This copies what StatusBar.android.js does - */ -'use strict'; - -export = null; diff --git a/packages/react-native-win32/src/Libraries/Components/TextInput/TextInput.Types.win32.ts b/packages/react-native-win32/src/Libraries/Components/TextInput/TextInput.Types.win32.ts index 7e68a5e3f87..cedc19fed51 100644 --- a/packages/react-native-win32/src/Libraries/Components/TextInput/TextInput.Types.win32.ts +++ b/packages/react-native-win32/src/Libraries/Components/TextInput/TextInput.Types.win32.ts @@ -66,10 +66,3 @@ export type IEditingEvent = NativeSyntheticEvent>; // TODO: Why do I need this one export type IPasswordRules = string; - -// TODO: Can I get away without this? -export interface IRCTInput { - blur(): void; - focus(): void; - clear(): void; -} diff --git a/packages/react-native-win32/src/Libraries/Components/TextInput/TextInput.win32.tsx b/packages/react-native-win32/src/Libraries/Components/TextInput/TextInput.win32.tsx index 2b923c54b48..39594d5c9cd 100644 --- a/packages/react-native-win32/src/Libraries/Components/TextInput/TextInput.win32.tsx +++ b/packages/react-native-win32/src/Libraries/Components/TextInput/TextInput.win32.tsx @@ -29,19 +29,23 @@ import { NativeModules, requireNativeComponent, TextInputProps, + NativeMethods, } from 'react-native'; import { IBlurEvent, IChangeEvent, IFocusEvent, - IRCTInput, } from './TextInput.Types.win32'; const TextAncestor = require('../../Text/TextAncestor'); const TextInputState = require('./TextInputState'); +type RCTTextInputProps = TextInputProps & { + text: string; +}; + // RCTTextInput is the native component that win32 understands -const RCTTextInput = requireNativeComponent('RCTTextInput'); +const RCTTextInput = requireNativeComponent('RCTTextInput'); // Adding typings on ViewManagers is problematic as available functionality is not known until // registration at runtime and would require native and js to always be in sync. @@ -55,13 +59,13 @@ class TextInput extends React.Component { private _rafID: number; - private _inputRef: React.RefObject; + private _inputRef: React.RefObject & Readonly>; private _lastNativeText: string; private _eventCount = 0; constructor(props) { super(props); - this._inputRef = React.createRef(); + this._inputRef = React.createRef(); } /** diff --git a/packages/react-native-win32/src/Libraries/Components/TextInput/TextInputState.win32.js b/packages/react-native-win32/src/Libraries/Components/TextInput/TextInputState.win32.js index 17accd4314c..97c6ead360d 100644 --- a/packages/react-native-win32/src/Libraries/Components/TextInput/TextInputState.win32.js +++ b/packages/react-native-win32/src/Libraries/Components/TextInput/TextInputState.win32.js @@ -4,15 +4,14 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * - * This class is responsible for coordinating the "focused" - * state for TextInputs. All calls relating to the keyboard - * should be funneled through here - * * @format * @flow strict-local */ +// This class is responsible for coordinating the "focused" state for +// TextInputs. All calls relating to the keyboard should be funneled +// through here. + 'use strict'; const Platform = require('../../Utilities/Platform'); @@ -29,17 +28,29 @@ function currentlyFocusedField(): ?number { return currentlyFocusedID; } +function focusField(textFieldID: ?number): void { + if (currentlyFocusedID !== textFieldID && textFieldID != null) { + currentlyFocusedID = textFieldID; + } +} + +function blurField(textFieldID: ?number) { + if (currentlyFocusedID === textFieldID && textFieldID != null) { + currentlyFocusedID = null; + } +} + /** * @param {number} TextInputID id of the text field to focus * Focuses the specified text field * noop if the text field was already focused */ function focusTextInput(textFieldID: ?number) { - if (currentlyFocusedID !== textFieldID && textFieldID !== null) { - currentlyFocusedID = textFieldID; + if (currentlyFocusedID !== textFieldID && textFieldID != null) { + focusField(textFieldID); // [Windows if (Platform.OS === 'ios' || Platform.OS === 'win32') { - // Windows] + // Windows] UIManager.focus(textFieldID); } else if (Platform.OS === 'android') { UIManager.dispatchViewManagerCommand( @@ -58,11 +69,11 @@ function focusTextInput(textFieldID: ?number) { * noop if it wasn't focused */ function blurTextInput(textFieldID: ?number) { - if (currentlyFocusedID === textFieldID && textFieldID !== null) { - currentlyFocusedID = null; + if (currentlyFocusedID === textFieldID && textFieldID != null) { + blurField(textFieldID); // [Windows if (Platform.OS === 'ios' || Platform.OS === 'win32') { - // Windows] + // Windows] UIManager.blur(textFieldID); } else if (Platform.OS === 'android') { UIManager.dispatchViewManagerCommand( @@ -113,6 +124,8 @@ function isTextInput(textFieldID: number): boolean { module.exports = { currentlyFocusedField, + focusField, + blurField, setFocusedTextInput, // TODO(android ISS) clearFocusedTextInput, // TODO(android ISS) focusTextInput, diff --git a/packages/react-native-win32/src/Libraries/Components/Touchable/TouchableBounce.win32.js b/packages/react-native-win32/src/Libraries/Components/Touchable/TouchableBounce.win32.js new file mode 100644 index 00000000000..cc3543ec223 --- /dev/null +++ b/packages/react-native-win32/src/Libraries/Components/Touchable/TouchableBounce.win32.js @@ -0,0 +1,218 @@ +/** + * 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 strict-local + * @format + */ + +'use strict'; + +// [Win32 Remove .js +import Pressability from '../../Pressability/Pressability'; +import {PressabilityDebugView} from '../../Pressability/PressabilityDebug'; +import type {ViewStyleProp} from '../../StyleSheet/StyleSheet'; +import TVTouchable from './TVTouchable'; +import typeof TouchableWithoutFeedback from './TouchableWithoutFeedback'; +// Win32] +import {Animated, Platform} from 'react-native'; +import * as React from 'react'; + +type Props = $ReadOnly<{| + ...React.ElementConfig, + + onPressAnimationComplete?: ?() => void, + onPressWithCompletion?: ?(callback: () => void) => void, + releaseBounciness?: ?number, + releaseVelocity?: ?number, + style?: ?ViewStyleProp, + + hostRef: React.Ref, +|}>; + +type State = $ReadOnly<{| + pressability: Pressability, + scale: Animated.Value, +|}>; + +class TouchableBounce extends React.Component { + _tvTouchable: ?TVTouchable; + + state: State = { + pressability: new Pressability({ + getHitSlop: () => this.props.hitSlop, + getLongPressDelayMS: () => { + if (this.props.delayLongPress != null) { + const maybeNumber = this.props.delayLongPress; + if (typeof maybeNumber === 'number') { + return maybeNumber; + } + } + return 500; + }, + getPressDelayMS: () => this.props.delayPressIn, + getPressOutDelayMS: () => this.props.delayPressOut, + getPressRectOffset: () => this.props.pressRetentionOffset, + getTouchSoundDisabled: () => this.props.touchSoundDisabled, + onBlur: event => { + if (Platform.isTV) { + this._bounceTo(1, 0.4, 0); + } + if (this.props.onBlur != null) { + this.props.onBlur(event); + } + }, + onFocus: event => { + if (Platform.isTV) { + this._bounceTo(0.93, 0.1, 0); + } + if (this.props.onFocus != null) { + this.props.onFocus(event); + } + }, + onLongPress: event => { + if (this.props.onLongPress != null) { + this.props.onLongPress(event); + } + }, + onPress: event => { + const {onPressAnimationComplete, onPressWithCompletion} = this.props; + const releaseBounciness = this.props.releaseBounciness ?? 10; + const releaseVelocity = this.props.releaseVelocity ?? 10; + + if (onPressWithCompletion != null) { + onPressWithCompletion(() => { + this.state.scale.setValue(0.93); + this._bounceTo( + 1, + releaseVelocity, + releaseBounciness, + onPressAnimationComplete, + ); + }); + return; + } + + this._bounceTo( + 1, + releaseVelocity, + releaseBounciness, + onPressAnimationComplete, + ); + if (this.props.onPress != null) { + this.props.onPress(event); + } + }, + onPressIn: event => { + this._bounceTo(0.93, 0.1, 0); + if (this.props.onPressIn != null) { + this.props.onPressIn(event); + } + }, + onPressOut: event => { + this._bounceTo(1, 0.4, 0); + if (this.props.onPressOut != null) { + this.props.onPressOut(event); + } + }, + onResponderTerminationRequest: () => + !this.props.rejectResponderTermination, + onStartShouldSetResponder: () => !this.props.disabled, + }), + scale: new Animated.Value(1), + }; + + _bounceTo( + toValue: number, + velocity: number, + bounciness: number, + callback?: ?() => void, + ) { + Animated.spring(this.state.scale, { + toValue, + velocity, + bounciness, + useNativeDriver: true, + }).start(callback); + } + + render(): React.Node { + // BACKWARD-COMPATIBILITY: Focus and blur events were never supported before + // adopting `Pressability`, so preserve that behavior. + const { + onBlur, + onFocus, + ...eventHandlersWithoutBlurAndFocus + } = this.state.pressability.getEventHandlers(); + + return ( + + {this.props.children} + {__DEV__ ? ( + + ) : null} + + ); + } + + componentDidMount(): void { + if (Platform.isTV) { + this._tvTouchable = new TVTouchable(this, { + getDisabled: () => this.props.disabled === true, + onBlur: event => { + if (this.props.onBlur != null) { + this.props.onBlur(event); + } + }, + onFocus: event => { + if (this.props.onFocus != null) { + this.props.onFocus(event); + } + }, + onPress: event => { + if (this.props.onPress != null) { + this.props.onPress(event); + } + }, + }); + } + } + + componentWillUnmount(): void { + if (Platform.isTV) { + if (this._tvTouchable != null) { + this._tvTouchable.destroy(); + } + } + this.state.pressability.reset(); + } +} + +module.exports = (React.forwardRef((props, hostRef) => ( + +)): React.ComponentType<$ReadOnly<$Diff>>); diff --git a/packages/react-native-win32/src/Libraries/Components/Touchable/TouchableHighlight.win32.js b/packages/react-native-win32/src/Libraries/Components/Touchable/TouchableHighlight.win32.js new file mode 100644 index 00000000000..475bbc09c95 --- /dev/null +++ b/packages/react-native-win32/src/Libraries/Components/Touchable/TouchableHighlight.win32.js @@ -0,0 +1,384 @@ +/** + * 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 strict-local + * @format + */ + +'use strict'; + +// [Win32 Remove .js +import Pressability from '../../Pressability/Pressability'; +import {PressabilityDebugView} from '../../Pressability/PressabilityDebug'; +import StyleSheet, {type ViewStyleProp} from '../../StyleSheet/StyleSheet'; +import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; +import TVTouchable from './TVTouchable.js'; +import typeof TouchableWithoutFeedback from './TouchableWithoutFeedback'; +// Win32] +import Platform from '../../Utilities/Platform'; +import View from '../../Components/View/View'; +import * as React from 'react'; + +type AndroidProps = $ReadOnly<{| + nextFocusDown?: ?number, + nextFocusForward?: ?number, + nextFocusLeft?: ?number, + nextFocusRight?: ?number, + nextFocusUp?: ?number, +|}>; + +type IOSProps = $ReadOnly<{| + hasTVPreferredFocus?: ?boolean, +|}>; + +type Props = $ReadOnly<{| + ...React.ElementConfig, + ...AndroidProps, + ...IOSProps, + + activeOpacity?: ?number, + underlayColor?: ?ColorValue, + style?: ?ViewStyleProp, + onShowUnderlay?: ?() => void, + onHideUnderlay?: ?() => void, + testOnly_pressed?: ?boolean, + + hostRef: React.Ref, +|}>; + +type ExtraStyles = $ReadOnly<{| + child: ViewStyleProp, + underlay: ViewStyleProp, +|}>; + +type State = $ReadOnly<{| + pressability: Pressability, + extraStyles: ?ExtraStyles, +|}>; + +/** + * A wrapper for making views respond properly to touches. + * On press down, the opacity of the wrapped view is decreased, which allows + * the underlay color to show through, darkening or tinting the view. + * + * The underlay comes from wrapping the child in a new View, which can affect + * layout, and sometimes cause unwanted visual artifacts if not used correctly, + * for example if the backgroundColor of the wrapped view isn't explicitly set + * to an opaque color. + * + * TouchableHighlight must have one child (not zero or more than one). + * If you wish to have several child components, wrap them in a View. + * + * Example: + * + * ``` + * renderButton: function() { + * return ( + * + * + * + * ); + * }, + * ``` + * + * + * ### Example + * + * ```ReactNativeWebPlayer + * import React, { Component } from 'react' + * import { + * AppRegistry, + * StyleSheet, + * TouchableHighlight, + * Text, + * View, + * } from 'react-native' + * + * class App extends Component { + * constructor(props) { + * super(props) + * this.state = { count: 0 } + * } + * + * onPress = () => { + * this.setState({ + * count: this.state.count+1 + * }) + * } + * + * render() { + * return ( + * + * + * Touch Here + * + * + * + * { this.state.count !== 0 ? this.state.count: null} + * + * + * + * ) + * } + * } + * + * const styles = StyleSheet.create({ + * container: { + * flex: 1, + * justifyContent: 'center', + * paddingHorizontal: 10 + * }, + * button: { + * alignItems: 'center', + * backgroundColor: '#DDDDDD', + * padding: 10 + * }, + * countContainer: { + * alignItems: 'center', + * padding: 10 + * }, + * countText: { + * color: '#FF00FF' + * } + * }) + * + * AppRegistry.registerComponent('App', () => App) + * ``` + * + */ +class TouchableHighlight extends React.Component { + _hideTimeout: ?TimeoutID; + _isMounted: boolean = false; + _tvTouchable: ?TVTouchable; + + state: State = { + pressability: new Pressability({ + getHitSlop: () => this.props.hitSlop, + getLongPressDelayMS: () => { + if (this.props.delayLongPress != null) { + const maybeNumber = this.props.delayLongPress; + if (typeof maybeNumber === 'number') { + return maybeNumber; + } + } + return 500; + }, + getPressDelayMS: () => this.props.delayPressIn, + getPressOutDelayMS: () => this.props.delayPressOut, + getPressRectOffset: () => this.props.pressRetentionOffset, + getTouchSoundDisabled: () => this.props.touchSoundDisabled, + onBlur: event => { + if (Platform.isTV) { + this._hideUnderlay(); + } + if (this.props.onBlur != null) { + this.props.onBlur(event); + } + }, + onFocus: event => { + if (Platform.isTV) { + this._showUnderlay(); + } + if (this.props.onFocus != null) { + this.props.onFocus(event); + } + }, + onLongPress: event => { + if (this.props.onLongPress != null) { + this.props.onLongPress(event); + } + }, + onPress: event => { + if (this._hideTimeout != null) { + clearTimeout(this._hideTimeout); + } + if (!Platform.isTV) { + this._showUnderlay(); + this._hideTimeout = setTimeout(() => { + this._hideUnderlay(); + }, this.props.delayPressOut ?? 0); + } + if (this.props.onPress != null) { + this.props.onPress(event); + } + }, + onPressIn: event => { + if (this._hideTimeout != null) { + clearTimeout(this._hideTimeout); + this._hideTimeout = null; + } + this._showUnderlay(); + if (this.props.onPressIn != null) { + this.props.onPressIn(event); + } + }, + onPressOut: event => { + if (this._hideTimeout == null) { + this._hideUnderlay(); + } + if (this.props.onPressOut != null) { + this.props.onPressOut(event); + } + }, + onResponderTerminationRequest: () => + !this.props.rejectResponderTermination, + onStartShouldSetResponder: () => !this.props.disabled, + }), + extraStyles: + this.props.testOnly_pressed === true ? this._createExtraStyles() : null, + }; + + _createExtraStyles(): ExtraStyles { + return { + child: {opacity: this.props.activeOpacity ?? 0.85}, + underlay: { + backgroundColor: + this.props.underlayColor === undefined + ? 'black' + : this.props.underlayColor, + }, + }; + } + + _showUnderlay(): void { + if (!this._isMounted || !this._hasPressHandler()) { + return; + } + this.setState({extraStyles: this._createExtraStyles()}); + if (this.props.onShowUnderlay != null) { + this.props.onShowUnderlay(); + } + } + + _hideUnderlay(): void { + if (this._hideTimeout != null) { + clearTimeout(this._hideTimeout); + this._hideTimeout = null; + } + if (this.props.testOnly_pressed === true) { + return; + } + if (this._hasPressHandler()) { + this.setState({extraStyles: null}); + if (this.props.onHideUnderlay != null) { + this.props.onHideUnderlay(); + } + } + } + + _hasPressHandler(): boolean { + return ( + this.props.onPress != null || + this.props.onPressIn != null || + this.props.onPressOut != null || + this.props.onLongPress != null + ); + } + + render(): React.Node { + const child = React.Children.only(this.props.children); + + // BACKWARD-COMPATIBILITY: Focus and blur events were never supported before + // adopting `Pressability`, so preserve that behavior. + const { + onBlur, + onFocus, + ...eventHandlersWithoutBlurAndFocus + } = this.state.pressability.getEventHandlers(); + + return ( + + {React.cloneElement(child, { + style: StyleSheet.compose( + child.props.style, + this.state.extraStyles?.child, + ), + })} + {__DEV__ ? ( + + ) : null} + + ); + } + + componentDidMount(): void { + this._isMounted = true; + if (Platform.isTV) { + this._tvTouchable = new TVTouchable(this, { + getDisabled: () => this.props.disabled === true, + onBlur: event => { + if (this.props.onBlur != null) { + this.props.onBlur(event); + } + }, + onFocus: event => { + if (this.props.onFocus != null) { + this.props.onFocus(event); + } + }, + onPress: event => { + if (this.props.onPress != null) { + this.props.onPress(event); + } + }, + }); + } + } + + componentWillUnmount(): void { + this._isMounted = false; + if (this._hideTimeout != null) { + clearTimeout(this._hideTimeout); + } + if (Platform.isTV) { + if (this._tvTouchable != null) { + this._tvTouchable.destroy(); + } + } + this.state.pressability.reset(); + } +} + +module.exports = (React.forwardRef((props, hostRef) => ( + +)): React.ComponentType<$ReadOnly<$Diff>>); diff --git a/packages/react-native-win32/src/Libraries/Components/Touchable/TouchableOpacity.win32.js b/packages/react-native-win32/src/Libraries/Components/Touchable/TouchableOpacity.win32.js new file mode 100644 index 00000000000..c6acd99289a --- /dev/null +++ b/packages/react-native-win32/src/Libraries/Components/Touchable/TouchableOpacity.win32.js @@ -0,0 +1,314 @@ +/** + * 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 strict-local + * @format + */ + +'use strict'; + +// [Win32 Remove ".js" +import Pressability from '../../Pressability/Pressability'; +import {PressabilityDebugView} from '../../Pressability/PressabilityDebug'; +import TVTouchable from './TVTouchable'; +import typeof TouchableWithoutFeedback from './TouchableWithoutFeedback'; +// Win32] +import Animated from 'react-native/Libraries/Animated/src/Animated'; +import Easing from 'react-native/Libraries/Animated/src/Easing'; +import type {ViewStyleProp} from 'react-native/Libraries/StyleSheet/StyleSheet'; +import flattenStyle from 'react-native/Libraries/StyleSheet/flattenStyle'; +import Platform from '../../Utilities/Platform'; +import * as React from 'react'; + +type TVProps = $ReadOnly<{| + hasTVPreferredFocus?: ?boolean, + nextFocusDown?: ?number, + nextFocusForward?: ?number, + nextFocusLeft?: ?number, + nextFocusRight?: ?number, + nextFocusUp?: ?number, +|}>; + +type Props = $ReadOnly<{| + ...React.ElementConfig, + ...TVProps, + + activeOpacity?: ?number, + style?: ?ViewStyleProp, + + hostRef: React.Ref, +|}>; + +type State = $ReadOnly<{| + anim: Animated.Value, + pressability: Pressability, +|}>; + +/** + * A wrapper for making views respond properly to touches. + * On press down, the opacity of the wrapped view is decreased, dimming it. + * + * Opacity is controlled by wrapping the children in an Animated.View, which is + * added to the view hierarchy. Be aware that this can affect layout. + * + * Example: + * + * ``` + * renderButton: function() { + * return ( + * + * + * + * ); + * }, + * ``` + * ### Example + * + * ```ReactNativeWebPlayer + * import React, { Component } from 'react' + * import { + * AppRegistry, + * StyleSheet, + * TouchableOpacity, + * Text, + * View, + * } from 'react-native' + * + * class App extends Component { + * state = { count: 0 } + * + * onPress = () => { + * this.setState(state => ({ + * count: state.count + 1 + * })); + * }; + * + * render() { + * return ( + * + * + * Touch Here + * + * + * + * { this.state.count !== 0 ? this.state.count: null} + * + * + * + * ) + * } + * } + * + * const styles = StyleSheet.create({ + * container: { + * flex: 1, + * justifyContent: 'center', + * paddingHorizontal: 10 + * }, + * button: { + * alignItems: 'center', + * backgroundColor: '#DDDDDD', + * padding: 10 + * }, + * countContainer: { + * alignItems: 'center', + * padding: 10 + * }, + * countText: { + * color: '#FF00FF' + * } + * }) + * + * AppRegistry.registerComponent('App', () => App) + * ``` + * + */ +class TouchableOpacity extends React.Component { + _tvTouchable: ?TVTouchable; + + state: State = { + anim: new Animated.Value(this._getChildStyleOpacityWithDefault()), + pressability: new Pressability({ + getHitSlop: () => this.props.hitSlop, + getLongPressDelayMS: () => { + if (this.props.delayLongPress != null) { + const maybeNumber = this.props.delayLongPress; + if (typeof maybeNumber === 'number') { + return maybeNumber; + } + } + return 500; + }, + getPressDelayMS: () => this.props.delayPressIn, + getPressOutDelayMS: () => this.props.delayPressOut, + getPressRectOffset: () => this.props.pressRetentionOffset, + onBlur: event => { + if (Platform.isTV) { + this._opacityInactive(250); + } + if (this.props.onBlur != null) { + this.props.onBlur(event); + } + }, + onFocus: event => { + if (Platform.isTV) { + this._opacityActive(150); + } + if (this.props.onFocus != null) { + this.props.onFocus(event); + } + }, + onLongPress: event => { + if (this.props.onLongPress != null) { + this.props.onLongPress(event); + } + }, + onPress: event => { + if (this.props.onPress != null) { + this.props.onPress(event); + } + }, + onPressIn: event => { + this._opacityActive( + event.dispatchConfig.registrationName === 'onResponderGrant' + ? 0 + : 150, + ); + if (this.props.onPressIn != null) { + this.props.onPressIn(event); + } + }, + onPressOut: event => { + this._opacityInactive(250); + if (this.props.onPressOut != null) { + this.props.onPressOut(event); + } + }, + onResponderTerminationRequest: () => + !this.props.rejectResponderTermination, + onStartShouldSetResponder: () => !this.props.disabled, + }), + }; + + /** + * Animate the touchable to a new opacity. + */ + _setOpacityTo(toValue: number, duration: number): void { + Animated.timing(this.state.anim, { + toValue, + duration, + easing: Easing.inOut(Easing.quad), + useNativeDriver: true, + }).start(); + } + + _opacityActive(duration: number): void { + this._setOpacityTo(this.props.activeOpacity ?? 0.2, duration); + } + + _opacityInactive(duration: number): void { + this._setOpacityTo(this._getChildStyleOpacityWithDefault(), duration); + } + + _getChildStyleOpacityWithDefault(): number { + const opacity = flattenStyle(this.props.style)?.opacity; + return typeof opacity === 'number' ? opacity : 1; + } + + render(): React.Node { + // BACKWARD-COMPATIBILITY: Focus and blur events were never supported before + // adopting `Pressability`, so preserve that behavior. + const { + onBlur, + onFocus, + ...eventHandlersWithoutBlurAndFocus + } = this.state.pressability.getEventHandlers(); + + return ( + + {this.props.children} + {__DEV__ ? ( + + ) : null} + + ); + } + + componentDidMount(): void { + if (Platform.isTV) { + this._tvTouchable = new TVTouchable(this, { + getDisabled: () => this.props.disabled === true, + onBlur: event => { + if (this.props.onBlur != null) { + this.props.onBlur(event); + } + }, + onFocus: event => { + if (this.props.onFocus != null) { + this.props.onFocus(event); + } + }, + onPress: event => { + if (this.props.onPress != null) { + this.props.onPress(event); + } + }, + }); + } + } + + componentDidUpdate(prevProps: Props, prevState: State) { + if (this.props.disabled !== prevProps.disabled) { + this._opacityInactive(250); + } + } + + componentWillUnmount(): void { + if (Platform.isTV) { + if (this._tvTouchable != null) { + this._tvTouchable.destroy(); + } + } + this.state.pressability.reset(); + } +} + +module.exports = (React.forwardRef((props, hostRef) => ( + +)): React.ComponentType<$ReadOnly<$Diff>>); diff --git a/packages/react-native-win32/src/Libraries/Components/Touchable/TouchableWithoutFeedback.win32.js b/packages/react-native-win32/src/Libraries/Components/Touchable/TouchableWithoutFeedback.win32.js new file mode 100644 index 00000000000..8ad6be00003 --- /dev/null +++ b/packages/react-native-win32/src/Libraries/Components/Touchable/TouchableWithoutFeedback.win32.js @@ -0,0 +1,218 @@ +/** + * 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 strict-local + * @format + */ + +'use strict'; + +// [Win32 Remove ".js" +import Pressability from '../../Pressability/Pressability'; +import {PressabilityDebugView} from '../../Pressability/PressabilityDebug'; +import TVTouchable from './TVTouchable'; +// Win32] +import type { + AccessibilityActionEvent, + AccessibilityActionInfo, + AccessibilityRole, + AccessibilityState, + AccessibilityValue, +} from '../../Components/View/ViewAccessibility'; +import type {EdgeInsetsProp} from '../../StyleSheet/EdgeInsetsPropType'; +import type { + BlurEvent, + FocusEvent, + LayoutEvent, + PressEvent, +} from '../../Types/CoreEventTypes'; +import Platform from '../../Utilities/Platform'; +import View from '../../Components/View/View'; +import * as React from 'react'; + +type Props = $ReadOnly<{| + accessibilityActions?: ?$ReadOnlyArray, + accessibilityElementsHidden?: ?boolean, + accessibilityHint?: ?Stringish, + accessibilityIgnoresInvertColors?: ?boolean, + accessibilityLabel?: ?Stringish, + accessibilityLiveRegion?: ?('none' | 'polite' | 'assertive'), + accessibilityRole?: ?AccessibilityRole, + accessibilityState?: ?AccessibilityState, + accessibilityValue?: ?AccessibilityValue, + accessibilityViewIsModal?: ?boolean, + accessible?: ?boolean, + children?: ?React.Node, + delayLongPress?: ?number, + delayPressIn?: ?number, + delayPressOut?: ?number, + disabled?: ?boolean, + focusable?: ?boolean, + hitSlop?: ?EdgeInsetsProp, + importantForAccessibility?: ?('auto' | 'yes' | 'no' | 'no-hide-descendants'), + nativeID?: ?string, + onAccessibilityAction?: ?(event: AccessibilityActionEvent) => mixed, + onBlur?: ?(event: BlurEvent) => mixed, + onFocus?: ?(event: FocusEvent) => mixed, + onLayout?: ?(event: LayoutEvent) => mixed, + onLongPress?: ?(event: PressEvent) => mixed, + onPress?: ?(event: PressEvent) => mixed, + onPressIn?: ?(event: PressEvent) => mixed, + onPressOut?: ?(event: PressEvent) => mixed, + pressRetentionOffset?: ?EdgeInsetsProp, + rejectResponderTermination?: ?boolean, + testID?: ?string, + touchSoundDisabled?: ?boolean, +|}>; + +type State = $ReadOnly<{| + pressability: Pressability, +|}>; + +const PASSTHROUGH_PROPS = [ + 'accessibilityActions', + 'accessibilityElementsHidden', + 'accessibilityHint', + 'accessibilityIgnoresInvertColors', + 'accessibilityLabel', + 'accessibilityLiveRegion', + 'accessibilityRole', + 'accessibilityState', + 'accessibilityValue', + 'accessibilityViewIsModal', + 'hitSlop', + 'importantForAccessibility', + 'nativeID', + 'onAccessibilityAction', + 'onBlur', + 'onFocus', + 'onLayout', + 'testID', +]; + +class TouchableWithoutFeedback extends React.Component { + _tvTouchable: ?TVTouchable; + + state: State = { + pressability: new Pressability({ + getHitSlop: () => this.props.hitSlop, + getLongPressDelayMS: () => { + if (this.props.delayLongPress != null) { + const maybeNumber = this.props.delayLongPress; + if (typeof maybeNumber === 'number') { + return maybeNumber; + } + } + return 500; + }, + getPressDelayMS: () => this.props.delayPressIn, + getPressOutDelayMS: () => this.props.delayPressOut, + getPressRectOffset: () => this.props.pressRetentionOffset, + getTouchSoundDisabled: () => this.props.touchSoundDisabled, + onBlur: event => { + if (this.props.onBlur != null) { + this.props.onBlur(event); + } + }, + onFocus: event => { + if (this.props.onFocus != null) { + this.props.onFocus(event); + } + }, + onLongPress: event => { + if (this.props.onLongPress != null) { + this.props.onLongPress(event); + } + }, + onPress: event => { + if (this.props.onPress != null) { + this.props.onPress(event); + } + }, + onPressIn: event => { + if (this.props.onPressIn != null) { + this.props.onPressIn(event); + } + }, + onPressOut: event => { + if (this.props.onPressOut != null) { + this.props.onPressOut(event); + } + }, + onResponderTerminationRequest: () => + !this.props.rejectResponderTermination, + onStartShouldSetResponder: () => !this.props.disabled, + }), + }; + + render(): React.Node { + const element = React.Children.only(this.props.children); + const children = [element.props.children]; + if (__DEV__) { + if (element.type === View) { + children.push( + , + ); + } + } + + // BACKWARD-COMPATIBILITY: Focus and blur events were never supported before + // adopting `Pressability`, so preserve that behavior. + const { + onBlur, + onFocus, + ...eventHandlersWithoutBlurAndFocus + } = this.state.pressability.getEventHandlers(); + + const elementProps: {[string]: mixed, ...} = { + ...eventHandlersWithoutBlurAndFocus, + accessible: this.props.accessible !== false, + focusable: + this.props.focusable !== false && this.props.onPress !== undefined, + }; + for (const prop of PASSTHROUGH_PROPS) { + if (this.props[prop] !== undefined) { + elementProps[prop] = this.props[prop]; + } + } + + return React.cloneElement(element, elementProps, ...children); + } + + componentDidMount(): void { + if (Platform.isTV) { + this._tvTouchable = new TVTouchable(this, { + getDisabled: () => this.props.disabled === true, + onBlur: event => { + if (this.props.onBlur != null) { + this.props.onBlur(event); + } + }, + onFocus: event => { + if (this.props.onFocus != null) { + this.props.onFocus(event); + } + }, + onPress: event => { + if (this.props.onPress != null) { + this.props.onPress(event); + } + }, + }); + } + } + + componentWillUnmount(): void { + if (Platform.isTV) { + if (this._tvTouchable != null) { + this._tvTouchable.destroy(); + } + } + this.state.pressability.reset(); + } +} + +module.exports = TouchableWithoutFeedback; diff --git a/packages/react-native-win32/src/Libraries/Components/View/PlatformViewPropTypes.win32.ts b/packages/react-native-win32/src/Libraries/Components/View/PlatformViewPropTypes.win32.ts deleted file mode 100644 index a0a8cc12e63..00000000000 --- a/packages/react-native-win32/src/Libraries/Components/View/PlatformViewPropTypes.win32.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @providesModule PlatformViewPropTypes - * @flow - */ -'use strict'; - -export = {}; diff --git a/packages/react-native-win32/src/Libraries/Components/View/ReactNativeViewAttributes.win32.js b/packages/react-native-win32/src/Libraries/Components/View/ReactNativeViewAttributes.win32.js index 656428f7b06..b580251fb28 100644 --- a/packages/react-native-win32/src/Libraries/Components/View/ReactNativeViewAttributes.win32.js +++ b/packages/react-native-win32/src/Libraries/Components/View/ReactNativeViewAttributes.win32.js @@ -19,8 +19,8 @@ const UIView = { accessibilityLabel: true, accessibilityLiveRegion: true, accessibilityRole: true, - accessibilityStates: true, accessibilityState: true, + accessibilityValue: true, accessibilityHint: true, importantForAccessibility: true, nativeID: true, diff --git a/packages/react-native-win32/src/Libraries/Components/View/ReactNativeViewViewConfig.win32.js b/packages/react-native-win32/src/Libraries/Components/View/ReactNativeViewViewConfig.win32.js index 2733360b24a..0d58f3aaefe 100644 --- a/packages/react-native-win32/src/Libraries/Components/View/ReactNativeViewViewConfig.win32.js +++ b/packages/react-native-win32/src/Libraries/Components/View/ReactNativeViewViewConfig.win32.js @@ -16,8 +16,8 @@ const ReactNativeViewConfig = { uiViewClassName: 'RCTView', baseModuleName: null, Manager: 'ViewManager', - Commands: ({}: $TEMPORARY$object<{||}>), - Constants: ({}: $TEMPORARY$object<{||}>), + Commands: ({}: {...}), + Constants: ({}: {...}), bubblingEventTypes: { ...ReactNativeViewViewConfigAndroid.bubblingEventTypes, topBlur: { @@ -140,8 +140,9 @@ const ReactNativeViewConfig = { accessibilityLabel: true, accessibilityLiveRegion: true, accessibilityRole: true, - accessibilityStates: true, + accessibilityStates: true, // TODO: Can be removed after next release accessibilityState: true, + accessibilityValue: true, accessibilityViewIsModal: true, accessible: true, alignContent: true, diff --git a/packages/react-native-win32/src/Libraries/Image/Image.win32.js b/packages/react-native-win32/src/Libraries/Image/Image.win32.js index 330e2f62749..f9d678a9259 100644 --- a/packages/react-native-win32/src/Libraries/Image/Image.win32.js +++ b/packages/react-native-win32/src/Libraries/Image/Image.win32.js @@ -7,28 +7,23 @@ * @flow * @format */ + 'use strict'; const DeprecatedImagePropType = require('../DeprecatedPropTypes/DeprecatedImagePropType'); -const NativeModules = require('../BatchedBridge/NativeModules'); const React = require('react'); const ReactNative = require('../Renderer/shims/ReactNative'); // eslint-disable-line no-unused-vars const StyleSheet = require('../StyleSheet/StyleSheet'); const flattenStyle = require('../StyleSheet/flattenStyle'); -const requireNativeComponent = require('../ReactNative/requireNativeComponent'); const resolveAssetSource = require('./resolveAssetSource'); -const ImageViewManager = NativeModules.ImageViewManager; - -// [Windows -const ImageLoader = NativeModules.ImageLoader; // [Win32 uses ImageLoader for getSize] -const RCTImageView = requireNativeComponent('RCTImage'); // [Win32] Uses RCTImage instead of RCTImageView -// Windows] - import type {ImageProps as ImagePropsType} from './ImageProps'; import type {ImageStyleProp} from '../StyleSheet/StyleSheet'; +import NativeImageLoaderWin32 from './NativeImageLoaderWin32'; // [Win32] Replace iOS + +const RCTImageView = require('./ImageViewNativeComponent'); function getSize( uri: string, @@ -37,17 +32,17 @@ function getSize( ) { //[Win32 /* - ImageViewManager.getSize( - uri, - success, - failure || - function() { - console.warn('Failed to get size for image: ' + uri); - }, - ); + NativeNativeImageLoaderWin32IOS.getSize(uri) + .then(([width, height]) => success(width, height)) + .catch( + failure || + function() { + console.warn('Failed to get size for image ' + uri); + }, + ); */ - ImageLoader.getSize(uri, (width: number, height: number, err?: string) => { + NativeImageLoaderWin32.getSize(uri, (width: number, height: number, err?: string) => { if (!err) { success(width, height); } else { @@ -63,11 +58,11 @@ function getSize( function getSizeWithHeaders( uri: string, - headers: {[string]: string}, + headers: {[string]: string, ...}, success: (width: number, height: number) => void, failure?: (error: any) => void, ): any { - return ImageViewManager.getSizeWithHeaders({uri, headers}) + return NativeImageLoaderWin32.getSizeWithHeaders(uri, headers) .then(function(sizes) { success(sizes.width, sizes.height); }) @@ -80,23 +75,23 @@ function getSizeWithHeaders( } function prefetch(url: string): any { - return ImageViewManager.prefetchImage(url); + return NativeImageLoaderWin32.prefetchImage(url); } async function queryCache( urls: Array, -): Promise<{[string]: 'memory' | 'disk' | 'disk/memory'}> { - return await ImageViewManager.queryCache(urls); +): Promise<{[string]: 'memory' | 'disk' | 'disk/memory', ...}> { + return await NativeImageLoaderWin32.queryCache(urls); } -declare class ImageComponentType extends ReactNative.NativeComponent { - static getSize: typeof getSize; - static getSizeWithHeaders: typeof getSizeWithHeaders; - static prefetch: typeof prefetch; - static queryCache: typeof queryCache; - static resolveAssetSource: typeof resolveAssetSource; - static propTypes: typeof DeprecatedImagePropType; -} +type ImageComponentStatics = $ReadOnly<{| + getSize: typeof getSize, + getSizeWithHeaders: typeof getSizeWithHeaders, + prefetch: typeof prefetch, + queryCache: typeof queryCache, + resolveAssetSource: typeof resolveAssetSource, + propTypes: typeof DeprecatedImagePropType, +|}>; /** * A React component for displaying different types of images, @@ -105,10 +100,7 @@ declare class ImageComponentType extends ReactNative.NativeComponent, -) => { +let Image = (props: ImagePropsType, forwardedRef) => { const source = resolveAssetSource(props.source) || { uri: undefined, width: undefined, @@ -159,7 +151,9 @@ let Image = ( ); }; -Image = React.forwardRef(Image); +Image = React.forwardRef>( + Image, +); Image.displayName = 'Image'; /** @@ -225,7 +219,8 @@ const styles = StyleSheet.create({ }, }); -/* $FlowFixMe(>=0.89.0 site=react_native_ios_fb) This comment suppresses an - * error found when Flow v0.89 was deployed. To see the error, delete this - * comment and run Flow. */ -module.exports = (Image: Class); +module.exports = ((Image: any): React.AbstractComponent< + ImagePropsType, + React.ElementRef, +> & + ImageComponentStatics); diff --git a/packages/react-native-win32/src/Libraries/Image/ImageViewNativeComponent.win32.js b/packages/react-native-win32/src/Libraries/Image/ImageViewNativeComponent.win32.js new file mode 100644 index 00000000000..6174c3ec5a0 --- /dev/null +++ b/packages/react-native-win32/src/Libraries/Image/ImageViewNativeComponent.win32.js @@ -0,0 +1,54 @@ +/** + * 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'; + +const requireNativeComponent = require('../ReactNative/requireNativeComponent'); + +import codegenNativeComponent from '../Utilities/codegenNativeComponent'; + +import type {DangerouslyImpreciseStyle} from '../StyleSheet/StyleSheet'; +import type {ResolvedAssetSource} from './AssetSourceResolver'; +import type {HostComponent} from '../Renderer/shims/ReactNativeTypes'; +import type {ImageProps} from './ImageProps'; +import type {ViewProps} from '../Components/View/ViewPropTypes'; +import type {ImageStyleProp} from '../StyleSheet/StyleSheet'; +import type {ColorValue} from '../StyleSheet/StyleSheetTypes'; + +type NativeProps = $ReadOnly<{| + ...ImageProps, + ...ViewProps, + + style?: ImageStyleProp | DangerouslyImpreciseStyle, + + // iOS native props + tintColor?: ColorValue, + + // Android native props + shouldNotifyLoadEvents?: boolean, + src?: ?ResolvedAssetSource | $ReadOnlyArray<{uri: string, ...}>, + headers?: ?string, + defaultSrc?: ?string, + loadingIndicatorSrc?: ?string, +|}>; + +let ImageViewNativeComponent; + +if (global.RN$Bridgeless) { + ImageViewNativeComponent = codegenNativeComponent( + 'RCTImage', // [Win32] Rename RCTImageView to RCTImage + ); +} else { + ImageViewNativeComponent = requireNativeComponent( + 'RCTImage', // [Win32] Rename RCTImageView to RCTImage + ); +} + +module.exports = (ImageViewNativeComponent: HostComponent); diff --git a/packages/react-native-win32/src/Libraries/Image/NativeImageLoaderWin32.js b/packages/react-native-win32/src/Libraries/Image/NativeImageLoaderWin32.js new file mode 100644 index 00000000000..a3cd9baf480 --- /dev/null +++ b/packages/react-native-win32/src/Libraries/Image/NativeImageLoaderWin32.js @@ -0,0 +1,37 @@ +/** + * 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: () => {||}; + // [Win32 uses callback instead of promise + +getSize: (uri: string, callback: (width: number, height: number, err?: string) => void) => void; + // Win32] + + // [Win32 These aren't actually implemented, and will just blow up if called + // currently. + +getSizeWithHeaders: ( + uri: string, + headers: Object, + ) => Promise<{ + width: number, + height: number, + ... + }>; + +prefetchImage: (uri: string) => Promise; + +queryCache: (uris: Array) => Promise; + // Win32] +} + +export default (TurboModuleRegistry.getEnforcing('ImageLoader'): Spec); diff --git a/packages/react-native-win32/src/Libraries/Inspector/Inspector.win32.js b/packages/react-native-win32/src/Libraries/Inspector/Inspector.win32.js index 76418d12b9b..39bb8a103c7 100644 --- a/packages/react-native-win32/src/Libraries/Inspector/Inspector.win32.js +++ b/packages/react-native-win32/src/Libraries/Inspector/Inspector.win32.js @@ -25,18 +25,22 @@ const invariant = require('invariant'); export type ReactRenderer = { getInspectorDataForViewTag: (viewTag: number) => Object, + ... }; const hook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__; const renderers = findRenderers(); -// required for devtools to be able to edit react native styles +// Required for React DevTools to view/edit React Native styles in Flipper. +// Flipper doesn't inject these values when initializing DevTools. hook.resolveRNStyle = require('../StyleSheet/flattenStyle'); +const viewConfig = require('../Components/View/ReactNativeViewViewConfig'); // [Win32] Remove ".js" +hook.nativeStyleEditorValidAttributes = Object.keys( + viewConfig.validAttributes.style, +); function findRenderers(): $ReadOnlyArray { - const allRenderers = Object.keys(hook._renderers).map( - key => hook._renderers[key], - ); + const allRenderers = Array.from(hook.renderers.values()); invariant( allRenderers.length >= 1, 'Expected to find at least one React Native renderer on DevTools hook.', @@ -65,6 +69,7 @@ class Inspector extends React.Component< { inspectedViewTag: ?number, onRequestRerenderApp: (callback: (tag: ?number) => void) => void, + ... }, { devtoolsAgent: ?Object, @@ -76,8 +81,10 @@ class Inspector extends React.Component< inspected: any, inspectedViewTag: any, networking: boolean, + ... }, > { + _hideTimeoutID: TimeoutID | null = null; _subs: ?Array<() => void>; constructor(props: Object) { @@ -97,10 +104,10 @@ class Inspector extends React.Component< } componentDidMount() { - hook.on('react-devtools', this.attachToDevtools); + hook.on('react-devtools', this._attachToDevtools); // if devtools is already started if (hook.reactDevtoolsAgent) { - this.attachToDevtools(hook.reactDevtoolsAgent); + this._attachToDevtools(hook.reactDevtoolsAgent); } } @@ -108,53 +115,67 @@ class Inspector extends React.Component< if (this._subs) { this._subs.map(fn => fn()); } - hook.off('react-devtools', this.attachToDevtools); + hook.off('react-devtools', this._attachToDevtools); } UNSAFE_componentWillReceiveProps(newProps: Object) { this.setState({inspectedViewTag: newProps.inspectedViewTag}); } - attachToDevtools: (agent: any) => void = (agent: Object) => { - let _hideWait = null; - const hlSub = agent.sub('highlight', ({node, name, props}) => { - clearTimeout(_hideWait); + _attachToDevtools = (agent: Object) => { + agent.addListener('hideNativeHighlight', this._onAgentHideNativeHighlight); + agent.addListener('showNativeHighlight', this._onAgentShowNativeHighlight); + agent.addListener('shutdown', this._onAgentShutdown); - if (typeof node !== 'number') { - // Fiber - node = ReactNative.findNodeHandle(node); - } + this.setState({ + devtoolsAgent: agent, + }); + }; - UIManager.measure(node, (x, y, width, height, left, top) => { - this.setState({ - hierarchy: [], - inspected: { - frame: {left, top, width, height}, - style: props ? props.style : {}, - }, - }); + _onAgentHideNativeHighlight = () => { + if (this.state.inspected === null) { + return; + } + // we wait to actually hide in order to avoid flicker + this._hideTimeoutID = setTimeout(() => { + this.setState({ + inspected: null, + }); + }, 100); + }; + + _onAgentShowNativeHighlight = node => { + clearTimeout(this._hideTimeoutID); + + if (typeof node !== 'number') { + node = ReactNative.findNodeHandle(node); + } + + UIManager.measure(node, (x, y, width, height, left, top) => { + this.setState({ + hierarchy: [], + inspected: { + frame: {left, top, width, height}, + }, }); }); - const hideSub = agent.sub('hideHighlight', () => { - if (this.state.inspected === null) { - return; - } - // we wait to actually hide in order to avoid flicker - _hideWait = setTimeout(() => { - this.setState({ - inspected: null, - }); - }, 100); - }); - this._subs = [hlSub, hideSub]; + }; + + _onAgentShutdown = () => { + const agent = this.state.devtoolsAgent; + if (agent != null) { + agent.removeListener( + 'hideNativeHighlight', + this._onAgentHideNativeHighlight, + ); + agent.removeListener( + 'showNativeHighlight', + this._onAgentShowNativeHighlight, + ); + agent.removeListener('shutdown', this._onAgentShutdown); - agent.on('shutdown', () => { this.setState({devtoolsAgent: null}); - this._subs = null; - }); - this.setState({ - devtoolsAgent: agent, - }); + } }; setSelection(i: number) { @@ -186,12 +207,7 @@ class Inspector extends React.Component< if (this.state.devtoolsAgent) { // Skip host leafs - const offsetFromLeaf = hierarchy.length - 1 - selection; - this.state.devtoolsAgent.selectFromDOMNode( - touchedViewTag, - true, - offsetFromLeaf, - ); + this.state.devtoolsAgent.selectNode(touchedViewTag); } // [Win32 Avoid Dimensions call diff --git a/packages/react-native-win32/src/Libraries/Network/RCTNetworking.win32.js b/packages/react-native-win32/src/Libraries/Network/RCTNetworking.win32.js new file mode 100644 index 00000000000..49cace38ee3 --- /dev/null +++ b/packages/react-native-win32/src/Libraries/Network/RCTNetworking.win32.js @@ -0,0 +1,96 @@ +/** + * 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 + */ + +'use strict'; + +// Do not require the native RCTNetworking module directly! Use this wrapper module instead. +// It will add the necessary requestId, so that you don't have to generate it yourself. +const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter'); + +const convertRequestBody = require('./convertRequestBody'); + +// [Win32 +// import NativeNetworkingAndroid from './NativeNetworkingAndroid'; +import type {RequestBody} from './convertRequestBody'; +const NativeModules = require('../BatchedBridge/NativeModules'); +const RCTNetworkingNative = NativeModules.Networking; +// Win32] + +type Header = [string, string]; + +// Convert FormData headers to arrays, which are easier to consume in +// native on Android. +function convertHeadersMapToArray(headers: Object): Array
{ + const headerArray = []; + for (const name in headers) { + headerArray.push([name, headers[name]]); + } + return headerArray; +} + +let _requestId = 1; +function generateRequestId(): number { + return _requestId++; +} + +/** + * This class is a wrapper around the native RCTNetworking module. It adds a necessary unique + * requestId to each network request that can be used to abort that request later on. + */ +class RCTNetworking extends NativeEventEmitter { + constructor() { + super(RCTNetworkingNative); // [Win32] Use RCTNetworkingNative + } + + sendRequest( + method: string, + trackingName: string, + url: string, + headers: Object, + data: RequestBody, + responseType: 'text' | 'base64', + incrementalUpdates: boolean, + timeout: number, + callback: (requestId: number) => mixed, + withCredentials: boolean, + ) { + const body = convertRequestBody(data); + if (body && body.formData) { + body.formData = body.formData.map(part => ({ + ...part, + headers: convertHeadersMapToArray(part.headers), + })); + } + const requestId = generateRequestId(); + RCTNetworkingNative.sendRequest( + // [Win32] Use RCTNetworkingNative + method, + url, + requestId, + convertHeadersMapToArray(headers), + {...body, trackingName}, + responseType, + incrementalUpdates, + timeout, + withCredentials, + ); + callback(requestId); + } + + abortRequest(requestId: number) { + RCTNetworkingNative.abortRequest(requestId); // [Win32] Use RCTNetworkingNative + } + + clearCookies(callback: (result: boolean) => any) { + RCTNetworkingNative.clearCookies(callback); // [Win32] Use RCTNetworkingNative + } +} + +module.exports = (new RCTNetworking(): RCTNetworking); diff --git a/packages/react-native-win32/src/Libraries/Network/RCTNetworking.win32.ts b/packages/react-native-win32/src/Libraries/Network/RCTNetworking.win32.ts deleted file mode 100644 index c69ed6d44ed..00000000000 --- a/packages/react-native-win32/src/Libraries/Network/RCTNetworking.win32.ts +++ /dev/null @@ -1,101 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -// Do not require the native RCTNetworking module directly! Use this wrapper module instead. -// It will add the necessary requestId, so that you don't have to generate it yourself. - -declare module 'react-native' { - /* tslint:disable-next-line interface-name */ - interface NativeModulesStatic { - /* tslint:disable-next-line no-any */ - Networking: any; - } -} - -import { NativeEventEmitter as NativeEventEmitter_TypeCarrier } from 'react-native'; -export const NativeEventEmitter: typeof NativeEventEmitter_TypeCarrier = require('../EventEmitter/NativeEventEmitter'); - -const NativeModules = require('../BatchedBridge/NativeModules'); - -const RCTNetworkingNative = NativeModules.Networking; - -type Header = [string, string]; - -function convertHeadersMapToArray(headers: Object): Array
{ - const headerArray = []; - /* tslint:disable:forin */ - for (const name in headers) { - /* tslint:disable:forin */ - headerArray.push([name, headers[name]]); - } - return headerArray; -} - -let _requestId = 1; -function generateRequestId(): number { - return _requestId++; -} - -/** - * This class is a wrapper around the native RCTNetworking module. It adds a necessary unique - * requestId to each network request that can be used to abort that request later on. - */ -class RCTNetworking extends NativeEventEmitter { - public constructor() { - super(RCTNetworkingNative); - } - - public sendRequest( - method: string, - trackingName: string, - url: string, - headers: Object, - data: string | FormData | { uri: string }, - responseType: 'text' | 'base64', - incrementalUpdates: boolean, - timeout: number, - /* tslint:disable:no-any */ - callback: (requestId: number) => any - /* tslint:enable:no-any */ - ) { - const body = typeof data === 'string' ? { string: data } : data instanceof FormData ? { formData: getParts(data) } : data; - const requestId = generateRequestId(); - RCTNetworkingNative.sendRequest( - method, - url, - requestId, - convertHeadersMapToArray(headers), - { ...body, trackingName }, - responseType, - incrementalUpdates, - timeout - ); - callback(requestId); - } - - public abortRequest(requestId: number) { - RCTNetworkingNative.abortRequest(requestId); - } - - /* tslint:disable:no-any */ - public clearCookies(callback: (result: boolean) => any) { - /* tslint:enable:no-any */ - RCTNetworkingNative.clearCookies(callback); - } -} - -function getParts(data) { - return data.getParts().map(part => { - part.headers = convertHeadersMapToArray(part.headers); - return part; - }); -} - -module.exports = new RCTNetworking(); diff --git a/packages/react-native-win32/src/Libraries/Pressability/PressabilityDebug.win32.js b/packages/react-native-win32/src/Libraries/Pressability/PressabilityDebug.win32.js new file mode 100644 index 00000000000..302bb91772f --- /dev/null +++ b/packages/react-native-win32/src/Libraries/Pressability/PressabilityDebug.win32.js @@ -0,0 +1,76 @@ +/** + * 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 strict-local + * @format + */ + +'use strict'; + +import normalizeColor from '../StyleSheet/normalizeColor'; // [Win32] Remove ".js" +import Touchable from '../Components/Touchable/Touchable'; +import View from '../Components/View/View'; +import * as React from 'react'; + +type Props = $ReadOnly<{| + color: string, + hitSlop: ?$ReadOnly<{| + bottom?: ?number, + left?: ?number, + right?: ?number, + top?: ?number, + |}>, +|}>; + +/** + * Displays a debug overlay to visualize press targets when enabled via the + * React Native Inspector. Calls to this module should be guarded by `__DEV__`, + * for example: + * + * return ( + * + * {children} + * {__DEV__ ? ( + * + * ) : null} + * + * ); + * + */ +export function PressabilityDebugView({color, hitSlop}: Props): React.Node { + if (__DEV__) { + if (isEnabled()) { + const baseColor = + // $FlowFixMe [Win32] no toString() for NativeOrDynamicColor + '#' + (normalizeColor(color) ?? 0).toString(16).padStart(8, '0'); + + return ( + + ); + } + } + return null; +} + +export function isEnabled(): boolean { + if (__DEV__) { + return Touchable.TOUCH_TARGET_DEBUG; + } + return false; +} diff --git a/packages/react-native-win32/src/Libraries/ReactNative/getNativeComponentAttributes.win32.js b/packages/react-native-win32/src/Libraries/ReactNative/getNativeComponentAttributes.win32.js index ef7ed946e8f..b2bce91df62 100644 --- a/packages/react-native-win32/src/Libraries/ReactNative/getNativeComponentAttributes.win32.js +++ b/packages/react-native-win32/src/Libraries/ReactNative/getNativeComponentAttributes.win32.js @@ -21,8 +21,7 @@ const processColor = require('../StyleSheet/processColor'); const resolveAssetSource = require('../Image/resolveAssetSource'); const sizesDiffer = require('../Utilities/differ/sizesDiffer'); const warning = require('fbjs/lib/warning'); -import type {NativeOrDynamicColorType} from 'NativeOrDynamicColorType'; // TODO(macOS ISS#2323203) - +import type {NativeOrDynamicColorType} from '../StyleSheet/NativeOrDynamicColorType'; // TODO(macOS ISS#2323203) function getNativeComponentAttributes(uiViewClassName: string): any { const viewConfig = UIManager.getViewManagerConfig(uiViewClassName); diff --git a/packages/react-native-win32/src/Libraries/Color/NativeOrDynamicColorType.win32.js b/packages/react-native-win32/src/Libraries/StyleSheet/NativeOrDynamicColorType.win32.js similarity index 100% rename from packages/react-native-win32/src/Libraries/Color/NativeOrDynamicColorType.win32.js rename to packages/react-native-win32/src/Libraries/StyleSheet/NativeOrDynamicColorType.win32.js diff --git a/packages/react-native-win32/src/Libraries/StyleSheet/StyleSheet.win32.js b/packages/react-native-win32/src/Libraries/StyleSheet/StyleSheet.win32.js index 1f01db408f9..619d209e510 100644 --- a/packages/react-native-win32/src/Libraries/StyleSheet/StyleSheet.win32.js +++ b/packages/react-native-win32/src/Libraries/StyleSheet/StyleSheet.win32.js @@ -7,6 +7,7 @@ * @flow * @format */ + 'use strict'; const PixelRatio = require('../Utilities/PixelRatio'); @@ -152,7 +153,7 @@ export type ImageStyle = ____ImageStyle_Internal; */ export type DangerouslyImpreciseStyle = ____DangerouslyImpreciseStyle_Internal; -let hairlineWidth = +let hairlineWidth: number = Platform.OS === 'win32' ? 0.5 : PixelRatio.roundToNearestPixel(0.4); // TODO(windows ISS) - Avoid calls to PixelRatio - needs multi window support if (hairlineWidth === 0) { hairlineWidth = 1 / PixelRatio.get(); diff --git a/packages/react-native-win32/src/Libraries/Color/normalizeColor.win32.js b/packages/react-native-win32/src/Libraries/StyleSheet/normalizeColor.win32.js similarity index 100% rename from packages/react-native-win32/src/Libraries/Color/normalizeColor.win32.js rename to packages/react-native-win32/src/Libraries/StyleSheet/normalizeColor.win32.js diff --git a/packages/react-native-win32/src/Libraries/Color/normalizeColorObject.win32.js b/packages/react-native-win32/src/Libraries/StyleSheet/normalizeColorObject.win32.js similarity index 100% rename from packages/react-native-win32/src/Libraries/Color/normalizeColorObject.win32.js rename to packages/react-native-win32/src/Libraries/StyleSheet/normalizeColorObject.win32.js diff --git a/packages/react-native-win32/src/Libraries/StyleSheet/processColor.win32.js b/packages/react-native-win32/src/Libraries/StyleSheet/processColor.win32.js index 70c8d2d09f4..821190678bc 100644 --- a/packages/react-native-win32/src/Libraries/StyleSheet/processColor.win32.js +++ b/packages/react-native-win32/src/Libraries/StyleSheet/processColor.win32.js @@ -10,8 +10,8 @@ const Platform = require('../Utilities/Platform'); -const normalizeColor = require('../Color/normalizeColor'); -import type {NativeOrDynamicColorType} from '../Color/NativeOrDynamicColorType'; // ]TODO(macOS ISS#2323203) +const normalizeColor = require('./normalizeColor'); +import type {NativeOrDynamicColorType} from './NativeOrDynamicColorType'; // ]TODO(macOS ISS#2323203) /* eslint no-bitwise: 0 */ function processColor( diff --git a/packages/react-native-win32/src/Libraries/StyleSheet/processColorArray.win32.js b/packages/react-native-win32/src/Libraries/StyleSheet/processColorArray.win32.js index 9cb9206b8cf..066a78caa06 100644 --- a/packages/react-native-win32/src/Libraries/StyleSheet/processColorArray.win32.js +++ b/packages/react-native-win32/src/Libraries/StyleSheet/processColorArray.win32.js @@ -11,7 +11,7 @@ 'use strict'; const processColor = require('./processColor'); -import type {NativeOrDynamicColorType} from 'NativeOrDynamicColorType'; // TODO(macOS ISS#2323203) +import type {NativeOrDynamicColorType} from './NativeOrDynamicColorType'; // TODO(macOS ISS#2323203) function processColorArray( /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an diff --git a/packages/react-native-win32/src/Libraries/StyleSheet/processColorObject.win32.js b/packages/react-native-win32/src/Libraries/StyleSheet/processColorObject.win32.js index fe9eb981c39..6bcfa782b5a 100644 --- a/packages/react-native-win32/src/Libraries/StyleSheet/processColorObject.win32.js +++ b/packages/react-native-win32/src/Libraries/StyleSheet/processColorObject.win32.js @@ -12,9 +12,11 @@ const processColor = require('./processColor'); import type { ColorStop, NativeOrDynamicColorType, -} from '../Color/NativeOrDynamicColorType'; +} from './NativeOrDynamicColorType'; -function processColorObject(color?: NativeOrDynamicColorType) { +function processColorObject( + color?: NativeOrDynamicColorType, +): ?NativeOrDynamicColorType { if (color && typeof color === 'object') { if ( color.hasOwnProperty('colorStops') && diff --git a/packages/react-native-win32/src/Libraries/Utilities/DeviceInfo.win32.js b/packages/react-native-win32/src/Libraries/Utilities/DeviceInfo.win32.js index 3908d69fa42..52be473f598 100644 --- a/packages/react-native-win32/src/Libraries/Utilities/DeviceInfo.win32.js +++ b/packages/react-native-win32/src/Libraries/Utilities/DeviceInfo.win32.js @@ -5,11 +5,17 @@ * Device info doesn't can't be a global set of data for win32 * (probably not for android either). * - * Since the API as designed by facebook can't work, we just return null here to crash when used + * Since the API as designed by facebook can't work, we stub out all we can * @format * @flow */ 'use strict'; -module.exports = {getConstants() { return {isIPhoneX_deprecated: false}}}; +import type {Spec} from './NativeDeviceInfo'; + +const DeviceInfo: Spec = { + getConstants: () => ({Dimensions: {}}), +}; + +module.exports = DeviceInfo; diff --git a/packages/react-native-win32/src/Libraries/Utilities/Dimensions.win32.ts b/packages/react-native-win32/src/Libraries/Utilities/Dimensions.win32.js similarity index 61% rename from packages/react-native-win32/src/Libraries/Utilities/Dimensions.win32.ts rename to packages/react-native-win32/src/Libraries/Utilities/Dimensions.win32.js index 21d09be7c44..81f5c08fa85 100644 --- a/packages/react-native-win32/src/Libraries/Utilities/Dimensions.win32.ts +++ b/packages/react-native-win32/src/Libraries/Utilities/Dimensions.win32.js @@ -1,25 +1,32 @@ /** * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. - + * * @format * @flow */ 'use strict'; class Dimensions { - public static get(dim: string): Object { + static get(dim: string): Object { throw new Error( 'Having a global Dimensions object is too simplistic for Win32, so this API does not work', ); } - public static addEventListener(type: string, handler: Function) { + + static set(dims: $ReadOnly<{[key: string]: any, ...}>): void { + throw new Error( + 'Having a global Dimensions object is too simplistic for Win32, so this API does not work', + ); + } + + static addEventListener(type: 'change', handler: Function) { throw new Error( 'Having a global Dimensions object is too simplistic for Win32, so this API does not work', ); } - public static removeEventListener(type: string, handler: Function) { + static removeEventListener(type: 'change', handler: Function) { throw new Error( 'Having a global Dimensions object is too simplistic for Win32, so this API does not work', ); diff --git a/packages/react-native-win32/src/Libraries/Utilities/Platform.win32.js b/packages/react-native-win32/src/Libraries/Utilities/Platform.win32.js index 795373520f5..c85568ba61f 100644 --- a/packages/react-native-win32/src/Libraries/Utilities/Platform.win32.js +++ b/packages/react-native-win32/src/Libraries/Utilities/Platform.win32.js @@ -10,9 +10,11 @@ import NativePlatformConstantsWin from './NativePlatformConstantsWin'; -export type PlatformSelectSpec = { +export type PlatformSelectSpec = { + win32?: A, + native?: N, default?: D, - win32?: I, + ... }; const Platform = { @@ -39,8 +41,8 @@ const Platform = { isTesting: false, reactNativeVersion: { major: 0, - minor: 61, - patch: 5, + minor: 62, + patch: 0, prerelease: undefined, }, }; @@ -54,11 +56,15 @@ const Platform = { } return false; }, - get isTV() { + get isTV(): boolean { return false; }, - select: (spec: PlatformSelectSpec): D | I => - 'win32' in spec ? spec.win32 : spec.default, + select: (spec: PlatformSelectSpec): A | N | D => + 'win32' in spec + ? spec.win32 + : 'native' in spec + ? spec.native + : spec.default, }; module.exports = Platform; diff --git a/packages/react-native-win32/src/Libraries/YellowBox/UI/YellowBoxInspectorHeader.win32.js b/packages/react-native-win32/src/Libraries/YellowBox/UI/YellowBoxInspectorHeader.win32.js index ca58c413826..468343cb426 100644 --- a/packages/react-native-win32/src/Libraries/YellowBox/UI/YellowBoxInspectorHeader.win32.js +++ b/packages/react-native-win32/src/Libraries/YellowBox/UI/YellowBoxInspectorHeader.win32.js @@ -9,6 +9,15 @@ const React = require('react'); const View = require('../../Components/View/View'); +import type YellowBoxWarning from '../Data/YellowBoxWarning'; + +type Props = $ReadOnly<{| + onSelectIndex: (selectedIndex: number) => void, + selectedIndex: number, + warnings: $ReadOnlyArray, +|}>; + // The RN YellowBoxInspectorHeader uses PixelRatio, which isn't multi DPI aware. // So we just stub the header for now -module.exports = () => ; +const YellowBoxInspectorHeader = (props: Props): React.Node => ; +module.exports = YellowBoxInspectorHeader; diff --git a/packages/react-native-win32/src/Libraries/YellowBox/UI/YellowBoxInspectorSourceMapStatus.win32.js b/packages/react-native-win32/src/Libraries/YellowBox/UI/YellowBoxInspectorSourceMapStatus.win32.js index 7c2632d0878..d38ea2c2e29 100644 --- a/packages/react-native-win32/src/Libraries/YellowBox/UI/YellowBoxInspectorSourceMapStatus.win32.js +++ b/packages/react-native-win32/src/Libraries/YellowBox/UI/YellowBoxInspectorSourceMapStatus.win32.js @@ -19,4 +19,7 @@ type Props = $ReadOnly<{| status: 'COMPLETE' | 'FAILED' | 'NONE' | 'PENDING', |}>; -module.exports = (props: Props) => {props.status}; +const YellowBoxInspectorSourceMapStaus = (props: Props): React.Node => { + return {props.status}; +}; +module.exports = YellowBoxInspectorSourceMapStaus; diff --git a/packages/react-native-win32/src/Libraries/core/setUpDeveloperTools.win32.js b/packages/react-native-win32/src/Libraries/core/setUpDeveloperTools.win32.js index 747561552bf..6e42270b310 100644 --- a/packages/react-native-win32/src/Libraries/core/setUpDeveloperTools.win32.js +++ b/packages/react-native-win32/src/Libraries/core/setUpDeveloperTools.win32.js @@ -7,10 +7,13 @@ * @flow strict-local * @format */ + 'use strict'; import Platform from '../Utilities/Platform'; +declare var console: typeof console & {_isPolyfilled: boolean, ...}; + /** * Sets up developer tools for React Native. * You can use this module directly, or just require InitializeCore. @@ -19,60 +22,60 @@ if (__DEV__) { // TODO (T45803484) Enable devtools for bridgeless RN if (!global.RN$Bridgeless) { if (!global.__RCTProfileIsProfiling) { - // not when debugging in chrome - // TODO(t12832058) This check is broken - if (!window.document) { - const AppState = require('../AppState/AppState'); - // $FlowFixMe Module is untyped - const reactDevTools = require('react-devtools-core'); - const getDevServer = require('./Devtools/getDevServer'); - - // Don't steal the DevTools from currently active app. - // Note: if you add any AppState subscriptions to this file, - // you will also need to guard against `AppState.isAvailable`, - // or the code will throw for bundles that don't have it. - const isAppActive = () => AppState.currentState !== 'background'; - - // Get hostname from development server (packager) - const devServer = getDevServer(); - const host = devServer.bundleLoadedFromServer - ? devServer.url.replace(/https?:\/\//, '').split(':')[0] - : 'localhost'; - - reactDevTools.connectToDevTools({ - isAppActive, - host, - // Read the optional global variable for backward compatibility. - // It was added in https://github.com/facebook/react-native/commit/bf2b435322e89d0aeee8792b1c6e04656c2719a0. - port: window.__REACT_DEVTOOLS_PORT__, - resolveRNStyle: require('../StyleSheet/flattenStyle'), - }); - } + require('./setUpReactDevTools'); // Set up inspector const JSInspector = require('../JSInspector/JSInspector'); JSInspector.registerAgent(require('../JSInspector/NetworkAgent')); } + // Note we can't check if console is "native" because it would appear "native" in JSC and Hermes. + // We also can't check any properties that don't exist in the Chrome worker environment. + // So we check a navigator property that's set to a particular value ("Netscape") in all real browsers. + const isLikelyARealBrowser = + global.navigator != null && + /* _ + * | | + * _ __ ___| |_ ___ ___ __ _ _ __ ___ + * | '_ \ / _ \ __/ __|/ __/ _` | '_ \ / _ \ + * | | | | __/ |_\__ \ (_| (_| | |_) | __/ + * |_| |_|\___|\__|___/\___\__,_| .__/ \___| + * | | + * |_| + */ + global.navigator.appName === 'Netscape'; // Any real browser + if (!Platform.isTesting) { const HMRClient = require('../Utilities/HMRClient'); - [ - 'trace', - 'info', - 'warn', - 'log', - 'group', - 'groupCollapsed', - 'groupEnd', - 'debug', - ].forEach(level => { - const originalFunction = console[level]; - // $FlowFixMe Overwrite console methods - console[level] = function(...args) { - HMRClient.log(level, args); - originalFunction.apply(console, args); - }; - }); + + if (console._isPolyfilled) { + // We assume full control over the console and send JavaScript logs to Metro. + [ + 'trace', + 'info', + 'warn', + 'log', + 'group', + 'groupCollapsed', + 'groupEnd', + 'debug', + ].forEach(level => { + const originalFunction = console[level]; + console[level] = function(...args) { + HMRClient.log(level, args); + originalFunction.apply(console, args); + }; + }); + } else { + // We assume the environment has a real rich console (like Chrome), and don't hijack it to log to Metro. + // It's likely the developer is using rich console to debug anyway, and hijacking it would + // lose the filenames in console.log calls: https://github.com/facebook/react-native/issues/26788. + HMRClient.log('log', [ + `JavaScript logs will appear in your ${ + isLikelyARealBrowser ? 'browser' : 'environment' + } console`, + ]); + } } // [Windows diff --git a/packages/react-native-win32/src/Libraries/core/setUpReactDevTools.win32.js b/packages/react-native-win32/src/Libraries/core/setUpReactDevTools.win32.js new file mode 100644 index 00000000000..638f0f51494 --- /dev/null +++ b/packages/react-native-win32/src/Libraries/core/setUpReactDevTools.win32.js @@ -0,0 +1,59 @@ +/** + * 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'; + +if (__DEV__) { + const reactDevTools = require('react-devtools-core'); + const connectToDevTools = () => { + // not when debugging in chrome + // TODO(t12832058) This check is broken + if (!window.document) { + const AppState = require('../AppState/AppState'); + const getDevServer = require('./Devtools/getDevServer'); + + // Don't steal the DevTools from currently active app. + // Note: if you add any AppState subscriptions to this file, + // you will also need to guard against `AppState.isAvailable`, + // or the code will throw for bundles that don't have it. + const isAppActive = () => AppState.currentState !== 'background'; + + // Get hostname from development server (packager) + const devServer = getDevServer(); + const host = devServer.bundleLoadedFromServer + ? devServer.url.replace(/https?:\/\//, '').split(':')[0] + : 'localhost'; + + // Read the optional global variable for backward compatibility. + // It was added in https://github.com/facebook/react-native/commit/bf2b435322e89d0aeee8792b1c6e04656c2719a0. + const port = + window.__REACT_DEVTOOLS_PORT__ != null + ? window.__REACT_DEVTOOLS_PORT__ + : 8097; + + const WebSocket = require('../WebSocket/WebSocket'); + const ws = new WebSocket('ws://' + host + ':' + port); + + const viewConfig = require('../Components/View/ReactNativeViewViewConfig'); // [Win32] Remove .js + reactDevTools.connectToDevTools({ + isAppActive, + resolveRNStyle: require('../StyleSheet/flattenStyle'), + nativeStyleEditorValidAttributes: Object.keys( + viewConfig.validAttributes.style, + ), + websocket: ws, + }); + } + }; + + const RCTNativeAppEventEmitter = require('../EventEmitter/RCTNativeAppEventEmitter'); + RCTNativeAppEventEmitter.addListener('RCTDevMenuShown', connectToDevTools); + connectToDevTools(); // Try connecting once on load +} diff --git a/packages/react-native-win32/src/Libraries/react-native/react-native-implementation.win32.ts b/packages/react-native-win32/src/Libraries/react-native/react-native-implementation.win32.ts deleted file mode 100644 index 88b51ee7cbc..00000000000 --- a/packages/react-native-win32/src/Libraries/react-native/react-native-implementation.win32.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - This file is used as the root export of this package. - - Since react-native is removing haste as a module lookup mechanism, - we need to re-export the whole of react-native from react-native-win32. - - We also export the things that are actually exposed to users as part of react-native-win32. - Following how react-native exports everything, we export using inline requires - to support the inline require optimizations that the various react-native bundlers use. - - NOTE: when adding exports here, they should also be added to the `typings-index.ts` file, - which will provide proper type information for these exports. -*/ - -const ReactNativeImplementation = require('./react-native-implementation.js'); - -Object.defineProperty(ReactNativeImplementation, 'ViewWin32', { - get: () => { - return require('../Components/View/ViewWin32').ViewWin32; - }, -}); - -Object.defineProperty(ReactNativeImplementation, 'TextWin32', { - get: () => { - return require('../Components/Text/TextWin32').TextWin32; - }, -}); - -Object.defineProperty(ReactNativeImplementation, 'ButtonWin32', { - get: () => { - return require('../Components/Button/ButtonWin32').ButtonWin32; - }, -}); - -Object.defineProperty(ReactNativeImplementation, 'TouchableWin32', { - get: () => { - return require('../Components/Touchable/TouchableWin32').TouchableWin32; - }, -}); - -Object.defineProperty(ReactNativeImplementation, 'PersonaCoin', { - get: () => { - return require('../PersonaCoin/PersonaCoin').PersonaCoin; - }, -}); - -Object.defineProperty(ReactNativeImplementation, 'PersonaCoinSize', { - get: () => { - return require('../PersonaCoin/PersonaCoinTypes').PersonaCoinSize; - }, -}); - -Object.defineProperty(ReactNativeImplementation, 'PersonaCoinPresence', { - get: () => { - return require('../PersonaCoin/PersonaCoinTypes').PersonaCoinPresence; - }, -}); - -export = ReactNativeImplementation; diff --git a/packages/react-native-win32/src/RNTester/js/components/ListExampleShared.win32.js b/packages/react-native-win32/src/RNTester/js/components/ListExampleShared.win32.js index 62c1ea07cf6..e0c96b67110 100644 --- a/packages/react-native-win32/src/RNTester/js/components/ListExampleShared.win32.js +++ b/packages/react-native-win32/src/RNTester/js/components/ListExampleShared.win32.js @@ -30,6 +30,7 @@ export type Item = { key: string, pressed: boolean, noImage?: ?boolean, + ... }; function genItemData(count: number, start: number = 0): Array { @@ -57,6 +58,7 @@ class ItemComponent extends React.PureComponent<{ onPress: (key: string) => void, onShowUnderlay?: () => void, onHideUnderlay?: () => void, + ... }> { _onPress = () => { this.props.onPress(this.props.item.key); @@ -71,9 +73,6 @@ class ItemComponent extends React.PureComponent<{ onPress={this._onPress} onShowUnderlay={this.props.onShowUnderlay} onHideUnderlay={this.props.onHideUnderlay} - tvParallaxProperties={{ - pressMagnification: 1.1, - }} style={horizontal ? styles.horizItem : styles.item}> { +const renderStackedItem = ({item}: {item: Item, ...}): React.Node => { const itemHash = Math.abs(hashCode(item.title)); const imgSource = THUMB_URLS[itemHash % THUMB_URLS.length]; return ( @@ -106,7 +105,7 @@ const renderStackedItem = ({item}: {item: Item}): React.Node => { ); }; -class FooterComponent extends React.PureComponent<{}> { +class FooterComponent extends React.PureComponent<{...}> { render(): React.Node { return ( @@ -119,7 +118,7 @@ class FooterComponent extends React.PureComponent<{}> { } } -class HeaderComponent extends React.PureComponent<{}> { +class HeaderComponent extends React.PureComponent<{...}> { render(): React.Node { return ( @@ -132,7 +131,7 @@ class HeaderComponent extends React.PureComponent<{}> { } } -class ListEmptyComponent extends React.PureComponent<{}> { +class ListEmptyComponent extends React.PureComponent<{...}> { render(): React.Node { return ( @@ -142,7 +141,7 @@ class ListEmptyComponent extends React.PureComponent<{}> { } } -class SeparatorComponent extends React.PureComponent<{}> { +class SeparatorComponent extends React.PureComponent<{...}> { render(): React.Node { return ; } @@ -221,7 +220,7 @@ function getItemLayout( data: any, index: number, horizontal?: boolean, -): $TEMPORARY$object<{|index: number, length: number, offset: number|}> { +): {|index: number, length: number, offset: number|} { const [length, separator, header] = horizontal ? [HORIZ_WIDTH, 0, HEADER.width] : [ITEM_HEIGHT, SEPARATOR_HEIGHT, HEADER.height]; diff --git a/packages/react-native-win32/src/RNTester/js/components/RNTesterExampleFilter.win32.js b/packages/react-native-win32/src/RNTester/js/components/RNTesterExampleFilter.win32.js index eaa81515b24..ef81fdb88e1 100644 --- a/packages/react-native-win32/src/RNTester/js/components/RNTesterExampleFilter.win32.js +++ b/packages/react-native-win32/src/RNTester/js/components/RNTesterExampleFilter.win32.js @@ -13,6 +13,7 @@ const React = require('react'); const {StyleSheet, TextInput, View} = require('react-native'); +import {RNTesterThemeContext} from './RNTesterTheme'; type Props = { filter: Function, @@ -20,11 +21,10 @@ type Props = { sections: Object, disableSearch?: boolean, testID?: string, + ... }; -type State = { - filter: string, -}; +type State = {filter: string, ...}; class RNTesterExampleFilter extends React.Component { state: State = {filter: ''}; @@ -64,33 +64,48 @@ class RNTesterExampleFilter extends React.Component { return null; } return ( - - { - this.setState(() => ({filter: text})); - }} - placeholder="Search..." - underlineColorAndroid="transparent" - style={styles.searchTextInput} - testID={this.props.testID} - value={this.state.filter} - /> - + + {theme => { + return ( + + { + this.setState(() => ({filter: text})); + }} + placeholder="Search..." + placeholderTextColor={theme.PlaceholderTextColor} + underlineColorAndroid="transparent" + style={[ + styles.searchTextInput, + { + color: theme.LabelColor, + // backgroundColor: theme.SecondaryGroupedBackgroundColor, // [Win32 - TextInput doesn't support backgroundColor currently] + borderColor: theme.QuaternaryLabelColor, + }, + ]} + testID={this.props.testID} + value={this.state.filter} + /> + + ); + }} + ); } } const styles = StyleSheet.create({ searchRow: { - backgroundColor: '#eeeeee', padding: 10, }, searchTextInput: { - // backgroundColor: 'white', // [Win32 - TextInput doesn't support backgroundColor currently] - borderColor: '#cccccc', borderRadius: 3, borderWidth: 1, paddingLeft: 8, diff --git a/packages/react-native-win32/src/index.ts b/packages/react-native-win32/src/index.ts deleted file mode 100644 index 7718dd97f90..00000000000 --- a/packages/react-native-win32/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export = require('./Libraries/react-native/react-native-implementation.win32'); diff --git a/packages/react-native-win32/src/index.win32.ts b/packages/react-native-win32/src/index.win32.ts new file mode 100644 index 00000000000..a9bb340d32c --- /dev/null +++ b/packages/react-native-win32/src/index.win32.ts @@ -0,0 +1,59 @@ +/* + This file is used as the root export of this package. + + Since react-native is removing haste as a module lookup mechanism, + we need to re-export the whole of react-native from react-native-win32. + + We also export the things that are actually exposed to users as part of react-native-win32. + Following how react-native exports everything, we export using inline requires + to support the inline require optimizations that the various react-native bundlers use. + + NOTE: when adding exports here, they should also be added to the `typings-index.ts` file, + which will provide proper type information for these exports. +*/ + +const Index = require('./index.js'); + +Object.defineProperty(Index, 'ViewWin32', { + get: () => { + return require('./Libraries/Components/View/ViewWin32').ViewWin32; + }, +}); + +Object.defineProperty(Index, 'TextWin32', { + get: () => { + return require('./Libraries/Components/Text/TextWin32').TextWin32; + }, +}); + +Object.defineProperty(Index, 'ButtonWin32', { + get: () => { + return require('./Libraries/Components/Button/ButtonWin32').ButtonWin32; + }, +}); + +Object.defineProperty(Index, 'TouchableWin32', { + get: () => { + return require('./Libraries/Components/Touchable/TouchableWin32').TouchableWin32; + }, +}); + +Object.defineProperty(Index, 'PersonaCoin', { + get: () => { + return require('./Libraries/PersonaCoin/PersonaCoin').PersonaCoin; + }, +}); + +Object.defineProperty(Index, 'PersonaCoinSize', { + get: () => { + return require('./Libraries/PersonaCoin/PersonaCoinTypes').PersonaCoinSize; + }, +}); + +Object.defineProperty(Index, 'PersonaCoinPresence', { + get: () => { + return require('./Libraries/PersonaCoin/PersonaCoinTypes').PersonaCoinPresence; + }, +}); + +export = Index; diff --git a/packages/react-native-win32/src/overrides.json b/packages/react-native-win32/src/overrides.json index 7aec399d1dd..90f0e11632e 100644 --- a/packages/react-native-win32/src/overrides.json +++ b/packages/react-native-win32/src/overrides.json @@ -2,54 +2,38 @@ "overrides": [ { "type": "platform", - "file": "index.ts" + "file": "index.win32.ts" }, { "type": "patch", "file": "Libraries\\Alert\\Alert.win32.js", "baseFile": "Libraries\\Alert\\Alert.js", - "baseVersion": "0.61.5", - "baseHash": "dd77ba5b6da36da0aea70e638bf6bc2f88e4d073", + "baseVersion": "0.62.0-rc.3", + "baseHash": "bf73c8c30ecdada945c2af1f3146db028950c060", "issue": "LEGACY_FIXME" }, { "type": "patch", "file": "Libraries\\Animated\\src\\nodes\\AnimatedInterpolation.win32.js", "baseFile": "Libraries\\Animated\\src\\nodes\\AnimatedInterpolation.js", - "baseVersion": "0.61.5", - "baseHash": "833b32ae88fecb57858d3dc025fcabaa8f3cbb54", - "issue": "LEGACY_FIXME" - }, - { - "type": "platform", - "file": "Libraries\\Color\\NativeOrDynamicColorType.win32.js" - }, - { - "type": "patch", - "file": "Libraries\\Color\\normalizeColor.win32.js", - "baseFile": "Libraries\\Color\\normalizeColor.js", - "baseVersion": "0.61.5", - "baseHash": "4bc82a7b34323bd68fe74e78effb762267d784d1", + "baseVersion": "0.62.0-rc.3", + "baseHash": "e5e0e4e6c1b20844ec1deecc34ffa9452360ba03", "issue": "LEGACY_FIXME" }, - { - "type": "platform", - "file": "Libraries\\Color\\normalizeColorObject.win32.js" - }, { "type": "derived", "file": "Libraries\\Components\\AccessibilityInfo\\AccessibilityInfo.win32.js", "baseFile": "Libraries\\Components\\AccessibilityInfo\\AccessibilityInfo.android.js", - "baseVersion": "0.61.5", - "baseHash": "d095ab7eaf3fd9fab83187d226905ae90742bccc", + "baseVersion": "0.62.0-rc.3", + "baseHash": "eb1753df0ab59f8c23fdd6469e69bfd349be1a58", "issue": "LEGACY_FIXME" }, { "type": "patch", "file": "Libraries\\Components\\AccessibilityInfo\\NativeAccessibilityInfo.win32.js", "baseFile": "Libraries\\Components\\AccessibilityInfo\\NativeAccessibilityInfo.js", - "baseVersion": "0.61.5", - "baseHash": "92c59d658858c52fb82d708a9cc94e9597f5c36c", + "baseVersion": "0.62.0-rc.3", + "baseHash": "b3e2c37d96de6f00066495267f7c32d6e9d3f840", "issue": "LEGACY_FIXME" }, { @@ -64,8 +48,8 @@ "type": "derived", "file": "Libraries\\Components\\CheckBox\\CheckBox.win32.tsx", "baseFile": "Libraries\\Components\\CheckBox\\CheckBox.android.js", - "baseVersion": "0.61.5", - "baseHash": "ad31417ed1bf4852f450eab6c2bdbd1f4f0285d9", + "baseVersion": "0.62.0-rc.3", + "baseHash": "7006aba4ecdfd27a213172ca92d1877b55729292", "issue": "LEGACY_FIXME" }, { @@ -97,8 +81,8 @@ "type": "derived", "file": "Libraries\\Components\\MaskedView\\MaskedViewIOS.win32.js", "baseFile": "Libraries\\Components\\MaskedView\\MaskedViewIOS.android.js", - "baseVersion": "0.61.5", - "baseHash": "2b46c2ecc8e3cfe8f40f119b628cee2f8fd2d441" + "baseVersion": "0.62.0-rc.3", + "baseHash": "0b409391c852a1001cee74a84414a13c4fe88f8b" }, { "type": "platform", @@ -115,8 +99,8 @@ "type": "derived", "file": "Libraries\\Components\\Picker\\PickerIOS.tsx", "baseFile": "Libraries\\Components\\Picker\\PickerIOS.android.js", - "baseVersion": "0.61.5", - "baseHash": "1fe21e833da3c9e426a6d3abb453e37c3671b0be" + "baseVersion": "0.62.0-rc.3", + "baseHash": "0c6bf0751e053672123cbad30d67851ba0007af6" }, { "type": "derived", @@ -136,14 +120,22 @@ "type": "patch", "file": "Libraries\\Components\\SafeAreaView\\SafeAreaView.win32.js", "baseFile": "Libraries\\Components\\SafeAreaView\\SafeAreaView.js", - "baseVersion": "0.61.5", - "baseHash": "800022db8bf078f907dcd5ce8de2460e2d54d02f", + "baseVersion": "0.62.0-rc.3", + "baseHash": "59dabb86baedb0088e110f8cdeb914fa3271dfd9", "issue": "LEGACY_FIXME" }, { "type": "platform", "file": "Libraries\\Components\\ScrollView\\RecyclerViewBackedScrollView.win32.tsx" }, + { + "type": "patch", + "file": "Libraries\\Components\\ScrollView\\ScrollView.win32.js", + "baseFile": "Libraries\\Components\\ScrollView\\ScrollView.js", + "baseVersion": "0.62.0-rc.3", + "baseHash": "ad1f9e693d11926daf324f992de3741def01e35e", + "issue": 4362 + }, { "type": "derived", "file": "Libraries\\Components\\SegmentedControlIOS\\SegmentedControlIOS.tsx", @@ -152,18 +144,20 @@ "baseHash": "37cea8b532ea4e4335120c6f8b2d3d3548e31b18" }, { - "type": "derived", - "file": "Libraries\\Components\\StatusBar\\StatusBar.win32.ts", - "baseFile": "Libraries\\Components\\StatusBar\\StatusBar.js", - "baseVersion": "0.61.5", - "baseHash": "7f069b8283af9c265adc9978a0d52b5a2e4a0f57" + "type": "patch", + "file": "Libraries\\Components\\StatusBar\\NativeStatusBarManagerAndroid.win32.js", + "baseFile": "Libraries\\Components\\StatusBar\\NativeStatusBarManagerAndroid.js", + "baseVersion": "0.62.0-rc.3", + "baseHash": "2c312e39ea468283e73be4319370d4f29ea5c932", + "issue": 4363 }, { - "type": "derived", - "file": "Libraries\\Components\\StatusBar\\StatusBarIOS.win32.ts", - "baseFile": "Libraries\\Components\\StatusBar\\StatusBarIOS.android.js", - "baseVersion": "0.61.5", - "baseHash": "aeeb1cb69ea1ea151ad037995cd9bf12fe4b93e3" + "type": "patch", + "file": "Libraries\\Components\\StatusBar\\NativeStatusBarManagerIOS.win32.js", + "baseFile": "Libraries\\Components\\StatusBar\\NativeStatusBarManagerIOS.js", + "baseVersion": "0.62.0-rc.3", + "baseHash": "f9f3d19210ade74181dbd291ffd97d8905d61035", + "issue": 4363 }, { "type": "platform", @@ -186,16 +180,16 @@ "type": "derived", "file": "Libraries\\Components\\TextInput\\TextInput.win32.tsx", "baseFile": "Libraries\\Components\\TextInput\\TextInput.js", - "baseVersion": "0.61.5", - "baseHash": "53a59e839404c2f565cb47b00fee6b4541045d6c", + "baseVersion": "0.62.0-rc.3", + "baseHash": "ddc98a5d277a630f3ac95c5d416a1028ba27382d", "issue": "LEGACY_FIXME" }, { "type": "patch", "file": "Libraries\\Components\\TextInput\\TextInputState.win32.js", "baseFile": "Libraries\\Components\\TextInput\\TextInputState.js", - "baseVersion": "0.61.5", - "baseHash": "f55224fb7c1402127cdce024d02b62377988b4f6", + "baseVersion": "0.62.0-rc.3", + "baseHash": "b6abcc197d20eb192444f85e0a1e447a3019658f", "issue": "LEGACY_FIXME" }, { @@ -209,6 +203,22 @@ "type": "platform", "file": "Libraries\\Components\\Touchable\\Tests\\TouchableWin32Test.tsx" }, + { + "type": "patch", + "file": "Libraries\\Components\\Touchable\\TouchableBounce.win32.js", + "baseFile": "Libraries\\Components\\Touchable\\TouchableBounce.js", + "baseVersion": "0.62.0-rc.3", + "baseHash": "d2bb715bb7b4fe8a324252409273747c96a4e687", + "issue": 4310 + }, + { + "type": "patch", + "file": "Libraries\\Components\\Touchable\\TouchableHighlight.win32.js", + "baseFile": "Libraries\\Components\\Touchable\\TouchableHighlight.js", + "baseVersion": "0.62.0-rc.3", + "baseHash": "b930d8995dab7c9aad3e14c3a78b73431c791a56", + "issue": 4310 + }, { "type": "platform", "file": "Libraries\\Components\\Touchable\\TouchableNativeFeedback.Props.ts" @@ -217,6 +227,14 @@ "type": "platform", "file": "Libraries\\Components\\Touchable\\TouchableNativeFeedback.win32.tsx" }, + { + "type": "patch", + "file": "Libraries\\Components\\Touchable\\TouchableOpacity.win32.js", + "baseFile": "Libraries\\Components\\Touchable\\TouchableOpacity.js", + "baseVersion": "0.62.0-rc.3", + "baseHash": "356d5eb7b824b35b79fb4108b3dffcd8c3cfa4f7", + "issue": 4310 + }, { "type": "platform", "file": "Libraries\\Components\\Touchable\\TouchableWin32.Props.tsx" @@ -230,27 +248,27 @@ "file": "Libraries\\Components\\Touchable\\TouchableWin32.Types.tsx" }, { - "type": "derived", - "file": "Libraries\\Components\\View\\PlatformViewPropTypes.win32.ts", - "baseFile": "Libraries\\Components\\View\\PlatformViewPropTypes.android.js", - "baseVersion": "0.61.5", - "baseHash": "215c4c06a2850cc475e4803e521f7394a48fb86f", - "issue": "LEGACY_FIXME" + "type": "patch", + "file": "Libraries\\Components\\Touchable\\TouchableWithoutFeedback.win32.js", + "baseFile": "Libraries\\Components\\Touchable\\TouchableWithoutFeedback.js", + "baseVersion": "0.62.0-rc.3", + "baseHash": "78e0bcf18020ec967f7d96767d7b555af5b9b3b6", + "issue": 4310 }, { "type": "patch", "file": "Libraries\\Components\\View\\ReactNativeViewAttributes.win32.js", "baseFile": "Libraries\\Components\\View\\ReactNativeViewAttributes.js", - "baseVersion": "0.61.5", - "baseHash": "2d767736cb8411f3a7f55624e4407cb428e6ee27", + "baseVersion": "0.62.0-rc.3", + "baseHash": "0825b0257e19cfef2d626f19d219256a01c54b67", "issue": "LEGACY_FIXME" }, { "type": "patch", "file": "Libraries\\Components\\View\\ReactNativeViewViewConfig.win32.js", "baseFile": "Libraries\\Components\\View\\ReactNativeViewViewConfig.js", - "baseVersion": "0.61.5", - "baseHash": "37075ba2b670098da40a2a6450c4f7e0b436428d", + "baseVersion": "0.62.0-rc.3", + "baseHash": "79f89796dab244dad97186438375669479316913", "issue": "LEGACY_FIXME" }, { @@ -269,29 +287,49 @@ "type": "patch", "file": "Libraries\\core\\setUpDeveloperTools.win32.js", "baseFile": "Libraries\\core\\setUpDeveloperTools.js", - "baseVersion": "0.61.5", - "baseHash": "8a250151f5616ab454d9799f6d3e747916f31520", + "baseVersion": "0.62.0-rc.3", + "baseHash": "d09be2d9fc8c621538c2262947580a03ff47177f", "issue": "LEGACY_FIXME" }, + { + "type": "patch", + "file": "Libraries\\core\\setUpReactDevTools.win32.js", + "baseFile": "Libraries\\core\\setUpReactDevTools.js", + "baseVersion": "0.62.0-rc.3", + "baseHash": "90b15d4c0940af7c72077d1eaef45d3256012aed", + "issue": 4310 + }, { "type": "derived", "file": "Libraries\\Image\\Image.win32.js", "baseFile": "Libraries\\Image\\Image.ios.js", - "baseVersion": "0.61.5", - "baseHash": "96c015ca1381817447cc98f72319ac89b30651b1", - "issue": "LEGACY_FIXME" + "baseVersion": "0.62.0-rc.3", + "baseHash": "80a9ee2404220201df09a5ff97e2bf7e03c854e0", + "issue": 4320 }, { "type": "platform", "file": "Libraries\\Image\\ImageTypes.ts" }, + { + "type": "patch", + "file": "Libraries\\Image\\ImageViewNativeComponent.win32.js", + "baseFile": "Libraries\\Image\\ImageViewNativeComponent.js", + "baseVersion": "0.62.0-rc.3", + "baseHash": "8cf992c3c45f77ff2049111bb6ef6972ae4e4c2a", + "issue": 4321 + }, { "type": "derived", - "file": "Libraries\\Image\\resolveAssetSource.win32.js", - "baseFile": "Libraries\\Image\\resolveAssetSource.js", - "baseVersion": "0.61.5", - "baseHash": "f08843b94a3f0f0cd58f473fe9cc8c4658fb9ca1", - "issue": "LEGACY_FIXME" + "file": "Libraries\\Image\\NativeImageLoaderWin32.js", + "baseFile": "Libraries\\Image\\NativeImageLoaderIOS.js", + "baseVersion": "0.62.0-rc.3", + "baseHash": "6161ce89a0b45b24e8df69aa108af22a7b591483", + "issue": 4320 + }, + { + "type": "platform", + "file": "Libraries\\Image\\resolveAssetSource.win32.js" }, { "type": "platform", @@ -301,8 +339,8 @@ "type": "patch", "file": "Libraries\\Inspector\\Inspector.win32.js", "baseFile": "Libraries\\Inspector\\Inspector.js", - "baseVersion": "0.61.5", - "baseHash": "9b1e79a244568f46c9dd54c50ef607c94957e364", + "baseVersion": "0.62.0-rc.3", + "baseHash": "4d8dd865cf9dc902cc415dbf7146df9dc198d2bb", "issue": "LEGACY_FIXME" }, { @@ -315,11 +353,11 @@ }, { "type": "derived", - "file": "Libraries\\Network\\RCTNetworking.win32.ts", + "file": "Libraries\\Network\\RCTNetworking.win32.js", "baseFile": "Libraries\\Network\\RCTNetworking.android.js", - "baseVersion": "0.61.5", - "baseHash": "77abb80c31ebaa13739663c3231a758cebc59461", - "issue": "LEGACY_FIXME" + "baseVersion": "0.62.0-rc.3", + "baseHash": "9ba4db01878648ef181dfd51debd821a837f56b3", + "issue": 4318 }, { "type": "platform", @@ -334,12 +372,12 @@ "file": "Libraries\\PersonaCoin\\PersonaCoinTypes.ts" }, { - "type": "platform", - "file": "Libraries\\react-native\\react-native-implementation.win32.ts" - }, - { - "type": "platform", - "file": "Libraries\\react-native\\typings-main.ts" + "type": "patch", + "file": "Libraries\\Pressability\\PressabilityDebug.win32.js", + "baseFile": "Libraries\\Pressability\\PressabilityDebug.js", + "baseVersion": "0.62.0-rc.3", + "baseHash": "4b94cc9c0fd201000db1a5c2fb874253e5e37606", + "issue": 4310 }, { "type": "patch", @@ -347,7 +385,7 @@ "baseFile": "Libraries\\ReactNative\\getNativeComponentAttributes.js", "baseVersion": "0.61.5", "baseHash": "2de5175e2d006f6d36fca098d3e47cbcc7e05c25", - "issue": "LEGACY_FIXME" + "issue": 3990 }, { "type": "derived", @@ -357,13 +395,29 @@ "baseHash": "00604dd0ab624b3f5b80d460f48dbc3ac7ee905d", "issue": "LEGACY_FIXME" }, + { + "type": "platform", + "file": "Libraries\\StyleSheet\\NativeOrDynamicColorType.win32.js" + }, + { + "type": "derived", + "file": "Libraries\\StyleSheet\\normalizeColor.win32.js", + "baseFile": "Libraries\\StyleSheet\\normalizeColor.js", + "baseVersion": "0.62.0-rc.3", + "baseHash": "48265ddff91efb254176c02f8d40bc71acce3252", + "issue": 3990 + }, + { + "type": "platform", + "file": "Libraries\\StyleSheet\\normalizeColorObject.win32.js" + }, { "type": "patch", "file": "Libraries\\StyleSheet\\processColor.win32.js", "baseFile": "Libraries\\StyleSheet\\processColor.js", - "baseVersion": "0.61.5", - "baseHash": "9efad52529662cc8601b94d30c27fe8fe285255e", - "issue": "LEGACY_FIXME" + "baseVersion": "0.62.0-rc.3", + "baseHash": "c24356f7c86e22d2d52ce2d7cded979509ad931c", + "issue": 3990 }, { "type": "patch", @@ -371,7 +425,7 @@ "baseFile": "Libraries\\StyleSheet\\processColorArray.js", "baseVersion": "0.61.5", "baseHash": "66b19d011a777ed38e5513eda9da2d61c9045595", - "issue": "LEGACY_FIXME" + "issue": 3990 }, { "type": "platform", @@ -381,16 +435,16 @@ "type": "patch", "file": "Libraries\\StyleSheet\\StyleSheet.win32.js", "baseFile": "Libraries\\StyleSheet\\StyleSheet.js", - "baseVersion": "0.61.5", - "baseHash": "cd76d00373696522aa0088b2ce57bbd686e09e3d", + "baseVersion": "0.62.0-rc.3", + "baseHash": "87b211c7221c858271123d6d306ffb51f881e512", "issue": "LEGACY_FIXME" }, { "type": "derived", "file": "Libraries\\Utilities\\BackHandler.win32.ts", "baseFile": "Libraries\\Utilities\\BackHandler.android.js", - "baseVersion": "0.61.5", - "baseHash": "39ba8bec264b8b576a212b2da4f14da390f0b42b", + "baseVersion": "0.62.0-rc.3", + "baseHash": "b1633b6bb5e3dc842011b09f778626c39bf6b654", "issue": "LEGACY_FIXME" }, { @@ -403,10 +457,10 @@ }, { "type": "derived", - "file": "Libraries\\Utilities\\Dimensions.win32.ts", + "file": "Libraries\\Utilities\\Dimensions.win32.js", "baseFile": "Libraries\\Utilities\\Dimensions.js", - "baseVersion": "0.61.5", - "baseHash": "2c7524091064411ed37220671aee34c86a7f6398", + "baseVersion": "0.62.0-rc.3", + "baseHash": "c8752f2624a836e0b4eb7ef1b24be76ef1ba8731", "issue": "LEGACY_FIXME" }, { @@ -421,24 +475,24 @@ "type": "derived", "file": "Libraries\\Utilities\\Platform.win32.js", "baseFile": "Libraries\\Utilities\\Platform.android.js", - "baseVersion": "0.61.5", - "baseHash": "725d90afef2dc0acc032f9c9f9b9dfc18a40d71d", + "baseVersion": "0.62.0-rc.3", + "baseHash": "d3a3db6cba034363c2544e6da13d7eac1f9cddfb", "issue": "LEGACY_FIXME" }, { "type": "derived", "file": "Libraries\\YellowBox\\UI\\YellowBoxInspectorHeader.win32.js", "baseFile": "Libraries\\YellowBox\\UI\\YellowBoxInspectorHeader.js", - "baseVersion": "0.61.5", - "baseHash": "087bbae032d390578e2afd2e86474fbd4ad2a219", + "baseVersion": "0.62.2", + "baseHash": "80f52a83aa0b9750a8955bc79975d2b3914c664b", "issue": "LEGACY_FIXME" }, { "type": "derived", "file": "Libraries\\YellowBox\\UI\\YellowBoxInspectorSourceMapStatus.win32.js", "baseFile": "Libraries\\YellowBox\\UI\\YellowBoxInspectorSourceMapStatus.js", - "baseVersion": "0.61.5", - "baseHash": "1223d64f8f4189f7b359178eaca98d3f2b590664", + "baseVersion": "0.62.1", + "baseHash": "11d3fba8d2596ecb628ca1b6db3347f444920fb9", "issue": "LEGACY_FIXME" }, { @@ -473,33 +527,37 @@ "type": "patch", "file": "RNTester\\js\\components\\ListExampleShared.win32.js", "baseFile": "RNTester\\js\\components\\ListExampleShared.js", - "baseVersion": "0.61.5", - "baseHash": "200941a9f13b28f395f5a7569759278d4b41ac3c", + "baseVersion": "0.62.0-rc.3", + "baseHash": "d7be07e3fd8d9c1df8e23d5674ce3eb067d00865", "issue": "LEGACY_FIXME" }, { "type": "patch", "file": "RNTester\\js\\components\\RNTesterExampleFilter.win32.js", "baseFile": "RNTester\\js\\components\\RNTesterExampleFilter.js", - "baseVersion": "0.61.5", - "baseHash": "cc1dccf3c246a12281a627e2a21025af88c46db8", + "baseVersion": "0.62.0-rc.3", + "baseHash": "8a8182f7c36e8184b7bbfe1445263ceca622b2c1", "issue": "LEGACY_FIXME" }, { "type": "derived", "file": "RNTester\\js\\RNTesterApp.win32.tsx", "baseFile": "RNTester\\js\\RNTesterApp.android.js", - "baseVersion": "0.61.5", - "baseHash": "9cc102294d7ed366aff473f17e1caedfcc8ddb4c", + "baseVersion": "0.62.0-rc.3", + "baseHash": "53ddf0736fa7aba54191961066d2e934ba22dfa2", "issue": "LEGACY_FIXME" }, { "type": "derived", "file": "RNTester\\js\\utils\\RNTesterList.win32.ts", "baseFile": "RNTester\\js\\utils\\RNTesterList.android.js", - "baseVersion": "0.61.5", - "baseHash": "e1a725929fbf9b90245e9eddeb797f90b53b8ee9", + "baseVersion": "0.62.0-rc.3", + "baseHash": "f1e77952c292fe2898645f81f280b64f8ea17b90", "issue": "LEGACY_FIXME" + }, + { + "type": "platform", + "file": "typings-index.ts" } ] } \ No newline at end of file diff --git a/packages/react-native-win32/src/Libraries/react-native/typings-main.ts b/packages/react-native-win32/src/typings-index.ts similarity index 50% rename from packages/react-native-win32/src/Libraries/react-native/typings-main.ts rename to packages/react-native-win32/src/typings-index.ts index 42c63f2da2a..9f76d80bb57 100644 --- a/packages/react-native-win32/src/Libraries/react-native/typings-main.ts +++ b/packages/react-native-win32/src/typings-index.ts @@ -15,14 +15,14 @@ need to also be added to react-native-implementation.win32.ts */ -export * from '../../Libraries/Components/View/ViewWin32.Props'; -export * from '../../Libraries/Components/View/ViewWin32'; -export * from '../../Libraries/Components/Text/TextWin32.Props'; -export * from '../../Libraries/Components/Text/TextWin32'; -export * from '../../Libraries/Components/Button/ButtonWin32.Props'; -export * from '../../Libraries/Components/Button/ButtonWin32'; -export * from '../../Libraries/Components/Touchable/TouchableWin32.Props'; -export * from '../../Libraries/Components/Touchable/TouchableWin32.Types'; -export * from '../../Libraries/Components/Touchable/TouchableWin32'; -export * from '../../Libraries/PersonaCoin/PersonaCoin'; -export * from '../../Libraries/PersonaCoin/PersonaCoinTypes'; +export * from './Libraries/Components/View/ViewWin32.Props'; +export * from './Libraries/Components/View/ViewWin32'; +export * from './Libraries/Components/Text/TextWin32.Props'; +export * from './Libraries/Components/Text/TextWin32'; +export * from './Libraries/Components/Button/ButtonWin32.Props'; +export * from './Libraries/Components/Button/ButtonWin32'; +export * from './Libraries/Components/Touchable/TouchableWin32.Props'; +export * from './Libraries/Components/Touchable/TouchableWin32.Types'; +export * from './Libraries/Components/Touchable/TouchableWin32'; +export * from './Libraries/PersonaCoin/PersonaCoin'; +export * from './Libraries/PersonaCoin/PersonaCoinTypes'; diff --git a/vnext/.flowconfig b/vnext/.flowconfig index 6e68a5f20ad..a4b73ab4f67 100644 --- a/vnext/.flowconfig +++ b/vnext/.flowconfig @@ -10,25 +10,19 @@ ; initRNLibraries build step /Libraries/Alert/Alert.js /Libraries/Animated/src/nodes/AnimatedInterpolation.js -/Libraries/AppTheme/AppTheme.js -/Libraries/Color/normalizeColor.js -/Libraries/Components/ActivityIndicator/RCTActivityIndicatorViewNativeComponent.js /Libraries/Components/Button.js /Libraries/Components/DatePicker/DatePicker.js -/Libraries/Components/Flyout/Flyout.js -/Libraries/Components/Glyph/Glyph.js /Libraries/Components/Keyboard/KeyboardExt.js /Libraries/Components/Picker/Picker.js -/Libraries/Components/Picker/PickerWindows.js /Libraries/Components/Picker/RCTPickerNativeComponent.js -/Libraries/Components/Popup/Popup.js /Libraries/Components/RefreshControl/RefreshControl.js /Libraries/Components/SafeAreaView/SafeAreaView.js /Libraries/Components/ScrollView/ScrollView.js -/Libraries/Components/Switch/Switch.js +/Libraries/Components/StatusBar/NativeStatusBarManagerAndroid.js /Libraries/Components/Switch/SwitchNativeComponent.js /Libraries/Components/TextInput/TextInput.js /Libraries/Components/TextInput/TextInputState.js +/Libraries/Components/Touchable/TouchableBounce.js /Libraries/Components/Touchable/TouchableHighlight.js /Libraries/Components/Touchable/TouchableNativeFeedback.js /Libraries/Components/Touchable/TouchableOpacity.js @@ -36,12 +30,16 @@ /Libraries/Components/View/ReactNativeViewViewConfig.js /Libraries/Components/View/ViewAccessibility.js /Libraries/Components/View/ViewPropTypes.js +/Libraries/Core/setUpReactDevTools.js /Libraries/DeprecatedPropTypes/DeprecatedViewAccessibility.js /Libraries/Image/Image.js +/Libraries/Inspector/Inspector.js /Libraries/Lists/VirtualizedList.js /Libraries/Network/RCTNetworking.js /Libraries/NewAppScreen/components/DebugInstructions.js /Libraries/NewAppScreen/components/ReloadInstructions.js +/Libraries/Pressability/PressabilityDebug.js +/Libraries/StyleSheet/normalizeColor.js /Libraries/StyleSheet/processColor.js /Libraries/StyleSheet/processColorArray.js /Libraries/StyleSheet/StyleSheetTypes.js @@ -85,10 +83,6 @@ ; 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 ; These should not be required directly ; require from fbjs/lib instead: require('fbjs/lib/warning') @@ -107,7 +101,6 @@ /Libraries/DeprecatedPropTypes/.* .*/node_modules/@react-native-community/cli/.*/.* /Libraries/ActionSheetIOS/ActionSheetIOS.js -/Libraries/Components/StatusBar/StatusBar.js /Libraries/Share/Share.js [include] @@ -115,7 +108,7 @@ ../node_modules/ [libs] -Libraries/react-native/react-native-interface.js +interface.js flow/ [options] @@ -128,33 +121,10 @@ module.file_ext=.js module.file_ext=.json module.file_ext=.windows.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='^\(.*\)\.macos$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.windows$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.windesktop$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1' -module.system.haste.paths.blacklist=/src/.* -module.system.haste.paths.blacklist=.*/__tests__/.* -module.system.haste.paths.blacklist=.*/__mocks__/.* -module.system.haste.paths.whitelist=/Libraries/.* -module.system.haste.paths.whitelist=/RNTester/.* -module.system.haste.paths.whitelist=/IntegrationTests/.* -module.system.haste.paths.blacklist=/Libraries/react-native/react-native-implementation.js -module.system.haste.paths.blacklist=/Libraries/Animated/src/polyfills/.* - munge_underscores=true -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' -module.name_mapper='react-native$' -> '/Libraries/react-native/react-native-implementation.js' +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\)$' -> '/Libraries/Image/RelativeImageStub' +module.name_mapper='react-native$' -> '/index.js' module.name_mapper='react-native/\(.*\)' -> '/\1' suppress_type=$FlowIssue @@ -165,8 +135,14 @@ suppress_type=$FlowFixMeEmpty suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\) suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+ +suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native\\(_android\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\) +suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_android\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+ suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError +experimental.well_formed_exports=true +experimental.types_first=true +experimental.abstract_locations=true + [lints] sketchy-null-number=warn sketchy-null-mixed=warn @@ -190,4 +166,4 @@ untyped-import untyped-type-import [version] -^0.105.0 \ No newline at end of file +^0.113.0 \ No newline at end of file diff --git a/vnext/.gitignore b/vnext/.gitignore index b6b6994f050..6377e5c79c4 100644 --- a/vnext/.gitignore +++ b/vnext/.gitignore @@ -43,7 +43,6 @@ node_modules /bots/node_modules/ /flow -/flow-typed /dist /IntegrationTests/*.js /IntegrationTests/*.png @@ -53,6 +52,8 @@ node_modules /RNTester /RNTester.* /index.* +/interface.* +/typings-index.* # Visual Studio .vs/ diff --git a/vnext/DeforkingPatches/.clang-format b/vnext/DeforkingPatches/.clang-format index bc20b078f0e..ef2ae21fafa 100644 --- a/vnext/DeforkingPatches/.clang-format +++ b/vnext/DeforkingPatches/.clang-format @@ -1,91 +1,4 @@ --- -AccessModifierOffset: -1 -AlignAfterOpenBracket: AlwaysBreak -AlignConsecutiveAssignments: false -AlignConsecutiveDeclarations: false -AlignEscapedNewlinesLeft: true -AlignOperands: false -AlignTrailingComments: false -AllowAllParametersOfDeclarationOnNextLine: false -AllowShortBlocksOnASingleLine: false -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: Empty -AllowShortIfStatementsOnASingleLine: false -AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: true -AlwaysBreakTemplateDeclarations: true -BinPackArguments: false -BinPackParameters: false -BraceWrapping: - AfterClass: false - AfterControlStatement: false - AfterEnum: false - AfterFunction: false - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false - BeforeCatch: false - BeforeElse: false - IndentBraces: false -BreakBeforeBinaryOperators: None -BreakBeforeBraces: Attach -BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false -BreakAfterJavaFieldAnnotations: false -BreakStringLiterals: false -ColumnLimit: 80 -CommentPragmas: '^ IWYU pragma:' -ConstructorInitializerAllOnOneLineOrOnePerLine: true -ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 4 -Cpp11BracedListStyle: true -DerivePointerAlignment: false -DisableFormat: false -ForEachMacros: [ FOR_EACH_RANGE, FOR_EACH, ] -IncludeCategories: - - Regex: '^<.*\.h(pp)?>' - Priority: 1 - - Regex: '^<.*' - Priority: 2 - - Regex: '.*' - Priority: 3 -IndentCaseLabels: true -IndentWidth: 2 -IndentWrappedFunctionNames: false -KeepEmptyLinesAtTheStartOfBlocks: false -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ObjCBlockIndentWidth: 2 -ObjCSpaceAfterProperty: true -ObjCSpaceBeforeProtocolList: true -PenaltyBreakBeforeFirstCallParameter: 1 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakString: 1000 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 200 -PointerAlignment: Right -ReflowComments: true -SortIncludes: true -SpaceAfterCStyleCast: false -SpaceBeforeAssignmentOperators: true -SpaceBeforeParens: ControlStatements -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 1 -SpacesInAngles: false -SpacesInContainerLiterals: true -SpacesInCStyleCastParentheses: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -Standard: Cpp11 -TabWidth: 8 -UseTab: Never ---- -Language: ObjC -ColumnLimit: 120 -BreakBeforeBraces: WebKit +DisableFormat: true +SortIncludes: false ... diff --git a/vnext/DeforkingPatches/ReactCommon/cxxreact/NativeToJsBridge.h b/vnext/DeforkingPatches/ReactCommon/cxxreact/NativeToJsBridge.h deleted file mode 100644 index 9d9688142f2..00000000000 --- a/vnext/DeforkingPatches/ReactCommon/cxxreact/NativeToJsBridge.h +++ /dev/null @@ -1,120 +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. - -#pragma once - -#include -#include -#include -#include - -#include - -namespace folly { -struct dynamic; -} - -namespace facebook { -namespace react { - -struct InstanceCallback; -class JsToNativeBridge; -class MessageQueueThread; -class ModuleRegistry; -class RAMBundleRegistry; - -// This class manages calls from native code to JS. It also manages -// executors and their threads. All functions here can be called from -// any thread. -// -// Except for loadApplicationScriptSync(), all void methods will queue -// work to run on the jsQueue passed to the ctor, and return -// immediately. -class NativeToJsBridge { - public: - friend class JsToNativeBridge; - - /** - * This must be called on the main JS thread. - */ - NativeToJsBridge( - JSExecutorFactory *jsExecutorFactory, - std::shared_ptr registry, - std::shared_ptr jsQueue, - std::shared_ptr callback); - virtual ~NativeToJsBridge(); - - /** - * Executes a function with the module ID and method ID and any additional - * arguments in JS. - */ - void callFunction( - std::string &&module, - std::string &&method, - folly::dynamic &&args); - - /** - * Invokes a callback with the cbID, and optional additional arguments in JS. - */ - void invokeCallback(double callbackId, folly::dynamic &&args); - - /** - * Starts the JS application. If bundleRegistry is non-null, then it is - * used to fetch JavaScript modules as individual scripts. - * Otherwise, the script is assumed to include all the modules. - */ - void loadApplication( - std::unique_ptr bundleRegistry, - std::unique_ptr startupCode, - std::string sourceURL); - void loadApplicationSync( - std::unique_ptr bundleRegistry, - std::unique_ptr startupCode, - std::string sourceURL); - - void registerBundle(uint32_t bundleId, const std::string &bundlePath); - void setGlobalVariable( - std::string propName, - std::unique_ptr jsonValue); - void *getJavaScriptContext(); - bool isInspectable(); - bool isBatchActive(); - - void handleMemoryPressure(int pressureLevel); - - /** - * Synchronously tears down the bridge and the main executor. - */ - void destroy(); - - void runOnExecutorQueue(std::function task); - - private: - // This is used to avoid a race condition where a proxyCallback gets queued - // after ~NativeToJsBridge(), on the same thread. In that case, the callback - // will try to run the task on m_callback which will have been destroyed - // within ~NativeToJsBridge(), thus causing a SIGSEGV. - std::shared_ptr m_destroyed; - std::shared_ptr m_delegate; - std::unique_ptr m_executor; - std::shared_ptr m_executorMessageQueueThread; - - // Memoize this on the JS thread, so that it can be inspected from - // any thread later. This assumes inspectability doesn't change for - // a JSExecutor instance, which is true for all existing implementations. - bool m_inspectable; - - // Keep track of whether the JS bundle containing the application logic causes - // exception when evaluated initially. If so, more calls to JS will very - // likely fail as well, so this flag can help prevent them. - bool m_applicationScriptHasFailure = false; - -#ifdef WITH_FBSYSTRACE - std::atomic_uint_least32_t m_systraceCookie = ATOMIC_VAR_INIT(0); -#endif -}; - -} // namespace react -} // namespace facebook diff --git a/vnext/DeforkingPatches/ReactCommon/turbomodule/samples/SampleTurboCxxModule.cpp b/vnext/DeforkingPatches/ReactCommon/turbomodule/samples/SampleTurboCxxModule.cpp index 6715e537c5f..67c4a61c908 100644 --- a/vnext/DeforkingPatches/ReactCommon/turbomodule/samples/SampleTurboCxxModule.cpp +++ b/vnext/DeforkingPatches/ReactCommon/turbomodule/samples/SampleTurboCxxModule.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the @@ -15,8 +15,8 @@ namespace facebook { namespace react { SampleTurboCxxModule::SampleTurboCxxModule( - std::shared_ptr jsInvoker) - : NativeSampleTurboCxxModuleSpecJSI(jsInvoker) {} + std::shared_ptr callInvoker) + : NativeSampleTurboCxxModuleSpecJSI(callInvoker) {} void SampleTurboCxxModule::voidFunc(jsi::Runtime &rt) { // Nothing to do diff --git a/vnext/DeforkingPatches/ReactCommon/turbomodule/samples/SampleTurboCxxModule.h b/vnext/DeforkingPatches/ReactCommon/turbomodule/samples/SampleTurboCxxModule.h index 4b4cdce946e..6109c929f42 100644 --- a/vnext/DeforkingPatches/ReactCommon/turbomodule/samples/SampleTurboCxxModule.h +++ b/vnext/DeforkingPatches/ReactCommon/turbomodule/samples/SampleTurboCxxModule.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the @@ -21,7 +21,7 @@ namespace react { */ class SampleTurboCxxModule : public NativeSampleTurboCxxModuleSpecJSI { public: - SampleTurboCxxModule(std::shared_ptr jsInvoker); + SampleTurboCxxModule(std::shared_ptr callInvoker); void voidFunc(jsi::Runtime &rt) override; bool getBool(jsi::Runtime &rt, bool arg) override; diff --git a/vnext/DeforkingPatches/ReactCommon/yoga/yoga/.clang-format b/vnext/DeforkingPatches/ReactCommon/yoga/yoga/.clang-format deleted file mode 100644 index ef2ae21fafa..00000000000 --- a/vnext/DeforkingPatches/ReactCommon/yoga/yoga/.clang-format +++ /dev/null @@ -1,4 +0,0 @@ ---- -DisableFormat: true -SortIncludes: false -... diff --git a/vnext/DeforkingPatches/ReactCommon/yoga/yoga/Yoga.cpp b/vnext/DeforkingPatches/ReactCommon/yoga/yoga/Yoga.cpp index e352d7d050c..8568903310a 100644 --- a/vnext/DeforkingPatches/ReactCommon/yoga/yoga/Yoga.cpp +++ b/vnext/DeforkingPatches/ReactCommon/yoga/yoga/Yoga.cpp @@ -1,13 +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. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. */ + #include "Yoga.h" #include #include #include +#include #include #include "Utils.h" #include "YGNode.h" @@ -104,7 +106,7 @@ static int YGDefaultLog( #undef YG_UNUSED #endif -bool YGFloatIsUndefined(const float value) { +YOGA_EXPORT bool YGFloatIsUndefined(const float value) { return facebook::yoga::isUndefined(value); } @@ -138,77 +140,85 @@ detail::CompactValue YGComputedEdgeValue( return defaultValue; } -void *YGNodeGetContext(YGNodeRef node) { +YOGA_EXPORT void* YGNodeGetContext(YGNodeRef node) { return node->getContext(); } -void YGNodeSetContext(YGNodeRef node, void *context) { +YOGA_EXPORT void YGNodeSetContext(YGNodeRef node, void* context) { + return node->setContext(context); } -bool YGNodeHasMeasureFunc(YGNodeRef node) { +YOGA_EXPORT bool YGNodeHasMeasureFunc(YGNodeRef node) { return node->hasMeasureFunc(); } -void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc) { +YOGA_EXPORT void YGNodeSetMeasureFunc( + YGNodeRef node, + YGMeasureFunc measureFunc) { node->setMeasureFunc(measureFunc); } -bool YGNodeHasBaselineFunc(YGNodeRef node) { +YOGA_EXPORT bool YGNodeHasBaselineFunc(YGNodeRef node) { return node->hasBaselineFunc(); } -void YGNodeSetBaselineFunc(YGNodeRef node, YGBaselineFunc baselineFunc) { +YOGA_EXPORT void YGNodeSetBaselineFunc( + YGNodeRef node, + YGBaselineFunc baselineFunc) { node->setBaselineFunc(baselineFunc); } -YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeRef node) { +YOGA_EXPORT YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeRef node) { return node->getDirtied(); } -void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc) { +YOGA_EXPORT void YGNodeSetDirtiedFunc( + YGNodeRef node, + YGDirtiedFunc dirtiedFunc) { node->setDirtiedFunc(dirtiedFunc); } -void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc) { +YOGA_EXPORT void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc) { node->setPrintFunc(printFunc); } -bool YGNodeGetHasNewLayout(YGNodeRef node) { +YOGA_EXPORT bool YGNodeGetHasNewLayout(YGNodeRef node) { return node->getHasNewLayout(); } -void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled) { +YOGA_EXPORT void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled) { config->printTree = enabled; } -void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout) { +YOGA_EXPORT void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout) { node->setHasNewLayout(hasNewLayout); } -YGNodeType YGNodeGetNodeType(YGNodeRef node) { +YOGA_EXPORT YGNodeType YGNodeGetNodeType(YGNodeRef node) { return node->getNodeType(); } -void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType) { +YOGA_EXPORT void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType) { return node->setNodeType(nodeType); } -bool YGNodeIsDirty(YGNodeRef node) { +YOGA_EXPORT bool YGNodeIsDirty(YGNodeRef node) { return node->isDirty(); } -bool YGNodeLayoutGetDidUseLegacyFlag(const YGNodeRef node) { +YOGA_EXPORT bool YGNodeLayoutGetDidUseLegacyFlag(const YGNodeRef node) { return node->didUseLegacyFlag(); } -void YGNodeMarkDirtyAndPropogateToDescendants(const YGNodeRef node) { +YOGA_EXPORT void YGNodeMarkDirtyAndPropogateToDescendants( + const YGNodeRef node) { return node->markDirtyAndPropogateDownwards(); } int32_t gConfigInstanceCount = 0; -WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) { +YOGA_EXPORT WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) { const YGNodeRef node = new YGNode{config}; YGAssertWithConfig( config, node != nullptr, "Could not allocate memory for node"); @@ -217,16 +227,16 @@ WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) { return node; } -YGConfigRef YGConfigGetDefault() { +YOGA_EXPORT YGConfigRef YGConfigGetDefault() { static YGConfigRef defaultConfig = YGConfigNew(); return defaultConfig; } -YGNodeRef YGNodeNew(void) { +YOGA_EXPORT YGNodeRef YGNodeNew(void) { return YGNodeNewWithConfig(YGConfigGetDefault()); } -YGNodeRef YGNodeClone(YGNodeRef oldNode) { +YOGA_EXPORT YGNodeRef YGNodeClone(YGNodeRef oldNode) { YGNodeRef node = new YGNode(*oldNode); YGAssertWithConfig( oldNode->getConfig(), @@ -266,7 +276,7 @@ static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) { return node; } -void YGNodeFree(const YGNodeRef node) { +YOGA_EXPORT void YGNodeFree(const YGNodeRef node) { if (YGNodeRef owner = node->getOwner()) { owner->removeChild(node); node->setOwner(nullptr); @@ -294,7 +304,7 @@ static void YGConfigFreeRecursive(const YGNodeRef root) { } } -void YGNodeFreeRecursiveWithCleanupFunc( +YOGA_EXPORT void YGNodeFreeRecursiveWithCleanupFunc( const YGNodeRef root, YGNodeCleanupFunc cleanup) { uint32_t skipped = 0; @@ -314,11 +324,11 @@ void YGNodeFreeRecursiveWithCleanupFunc( YGNodeFree(root); } -void YGNodeFreeRecursive(const YGNodeRef root) { +YOGA_EXPORT void YGNodeFreeRecursive(const YGNodeRef root) { return YGNodeFreeRecursiveWithCleanupFunc(root, nullptr); } -void YGNodeReset(YGNodeRef node) { +YOGA_EXPORT void YGNodeReset(YGNodeRef node) { node->reset(); } @@ -326,7 +336,7 @@ int32_t YGConfigGetInstanceCount(void) { return gConfigInstanceCount; } -YGConfigRef YGConfigNew(void) { +YOGA_EXPORT YGConfigRef YGConfigNew(void) { #ifdef ANDROID const YGConfigRef config = new YGConfig(YGAndroidLog); #else @@ -336,7 +346,7 @@ YGConfigRef YGConfigNew(void) { return config; } -void YGConfigFree(const YGConfigRef config) { +YOGA_EXPORT void YGConfigFree(const YGConfigRef config) { delete config; gConfigInstanceCount--; } @@ -345,18 +355,20 @@ void YGConfigCopy(const YGConfigRef dest, const YGConfigRef src) { memcpy(dest, src, sizeof(YGConfig)); } -void YGNodeSetIsReferenceBaseline(YGNodeRef node, bool isReferenceBaseline) { +YOGA_EXPORT void YGNodeSetIsReferenceBaseline( + YGNodeRef node, + bool isReferenceBaseline) { if (node->isReferenceBaseline() != isReferenceBaseline) { node->setIsReferenceBaseline(isReferenceBaseline); node->markDirtyAndPropogate(); } } -bool YGNodeIsReferenceBaseline(YGNodeRef node) { +YOGA_EXPORT bool YGNodeIsReferenceBaseline(YGNodeRef node) { return node->isReferenceBaseline(); } -void YGNodeInsertChild( +YOGA_EXPORT void YGNodeInsertChild( const YGNodeRef owner, const YGNodeRef child, const uint32_t index) { @@ -375,7 +387,9 @@ void YGNodeInsertChild( owner->markDirtyAndPropogate(); } -void YGNodeRemoveChild(const YGNodeRef owner, const YGNodeRef excludedChild) { +YOGA_EXPORT void YGNodeRemoveChild( + const YGNodeRef owner, + const YGNodeRef excludedChild) { if (YGNodeGetChildCount(owner) == 0) { // This is an empty set. Nothing to remove. return; @@ -394,7 +408,7 @@ void YGNodeRemoveChild(const YGNodeRef owner, const YGNodeRef excludedChild) { } } -void YGNodeRemoveAllChildren(const YGNodeRef owner) { +YOGA_EXPORT void YGNodeRemoveAllChildren(const YGNodeRef owner) { const uint32_t childCount = YGNodeGetChildCount(owner); if (childCount == 0) { // This is an empty set already. Nothing to do. @@ -454,7 +468,7 @@ static void YGNodeSetChildrenInternal( } } -void YGNodeSetChildren( +YOGA_EXPORT void YGNodeSetChildren( const YGNodeRef owner, const YGNodeRef c[], const uint32_t count) { @@ -462,32 +476,33 @@ void YGNodeSetChildren( YGNodeSetChildrenInternal(owner, children); } -void YGNodeSetChildren( +YOGA_EXPORT void YGNodeSetChildren( YGNodeRef const owner, const std::vector &children) { YGNodeSetChildrenInternal(owner, children); } -YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index) { +YOGA_EXPORT YGNodeRef +YGNodeGetChild(const YGNodeRef node, const uint32_t index) { if (index < node->getChildren().size()) { return node->getChild(index); } return nullptr; } -uint32_t YGNodeGetChildCount(const YGNodeRef node) { +YOGA_EXPORT uint32_t YGNodeGetChildCount(const YGNodeRef node) { return static_cast(node->getChildren().size()); } -YGNodeRef YGNodeGetOwner(const YGNodeRef node) { +YOGA_EXPORT YGNodeRef YGNodeGetOwner(const YGNodeRef node) { return node->getOwner(); } -YGNodeRef YGNodeGetParent(const YGNodeRef node) { +YOGA_EXPORT YGNodeRef YGNodeGetParent(const YGNodeRef node) { return node->getOwner(); } -void YGNodeMarkDirty(const YGNodeRef node) { +YOGA_EXPORT void YGNodeMarkDirty(const YGNodeRef node) { YGAssertWithNode( node, node->hasMeasureFunc(), @@ -497,20 +512,22 @@ void YGNodeMarkDirty(const YGNodeRef node) { node->markDirtyAndPropogate(); } -void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode) { +YOGA_EXPORT void YGNodeCopyStyle( + const YGNodeRef dstNode, + const YGNodeRef srcNode) { if (!(dstNode->getStyle() == srcNode->getStyle())) { dstNode->setStyle(srcNode->getStyle()); dstNode->markDirtyAndPropogate(); } } -float YGNodeStyleGetFlexGrow(const YGNodeConstRef node) { +YOGA_EXPORT float YGNodeStyleGetFlexGrow(const YGNodeConstRef node) { return node->getStyle().flexGrow().isUndefined() ? kDefaultFlexGrow : node->getStyle().flexGrow().unwrap(); } -float YGNodeStyleGetFlexShrink(const YGNodeConstRef node) { +YOGA_EXPORT float YGNodeStyleGetFlexShrink(const YGNodeConstRef node) { return node->getStyle().flexShrink().isUndefined() ? (node->getConfig()->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink) @@ -563,113 +580,131 @@ void updateIndexedStyleProp( // decltype, MSVC will prefer the non-const version. #define MSVC_HINT(PROP) decltype(YGStyle{}.PROP()) -void YGNodeStyleSetDirection(const YGNodeRef node, const YGDirection value) { +YOGA_EXPORT void YGNodeStyleSetDirection( + const YGNodeRef node, + const YGDirection value) { updateStyle(node, &YGStyle::direction, value); } -YGDirection YGNodeStyleGetDirection(const YGNodeConstRef node) { +YOGA_EXPORT YGDirection YGNodeStyleGetDirection(const YGNodeConstRef node) { return node->getStyle().direction(); } -void YGNodeStyleSetFlexDirection( +YOGA_EXPORT void YGNodeStyleSetFlexDirection( const YGNodeRef node, const YGFlexDirection flexDirection) { updateStyle( node, &YGStyle::flexDirection, flexDirection); } -YGFlexDirection YGNodeStyleGetFlexDirection(const YGNodeConstRef node) { +YOGA_EXPORT YGFlexDirection +YGNodeStyleGetFlexDirection(const YGNodeConstRef node) { return node->getStyle().flexDirection(); } -void YGNodeStyleSetJustifyContent( +YOGA_EXPORT void YGNodeStyleSetJustifyContent( const YGNodeRef node, const YGJustify justifyContent) { updateStyle( node, &YGStyle::justifyContent, justifyContent); } -YGJustify YGNodeStyleGetJustifyContent(const YGNodeConstRef node) { +YOGA_EXPORT YGJustify YGNodeStyleGetJustifyContent(const YGNodeConstRef node) { return node->getStyle().justifyContent(); } -void YGNodeStyleSetAlignContent( +YOGA_EXPORT void YGNodeStyleSetAlignContent( const YGNodeRef node, const YGAlign alignContent) { updateStyle( node, &YGStyle::alignContent, alignContent); } -YGAlign YGNodeStyleGetAlignContent(const YGNodeConstRef node) { +YOGA_EXPORT YGAlign YGNodeStyleGetAlignContent(const YGNodeConstRef node) { return node->getStyle().alignContent(); } -void YGNodeStyleSetAlignItems(const YGNodeRef node, const YGAlign alignItems) { +YOGA_EXPORT void YGNodeStyleSetAlignItems( + const YGNodeRef node, + const YGAlign alignItems) { updateStyle(node, &YGStyle::alignItems, alignItems); } -YGAlign YGNodeStyleGetAlignItems(const YGNodeConstRef node) { +YOGA_EXPORT YGAlign YGNodeStyleGetAlignItems(const YGNodeConstRef node) { return node->getStyle().alignItems(); } -void YGNodeStyleSetAlignSelf(const YGNodeRef node, const YGAlign alignSelf) { +YOGA_EXPORT void YGNodeStyleSetAlignSelf( + const YGNodeRef node, + const YGAlign alignSelf) { updateStyle(node, &YGStyle::alignSelf, alignSelf); } -YGAlign YGNodeStyleGetAlignSelf(const YGNodeConstRef node) { +YOGA_EXPORT YGAlign YGNodeStyleGetAlignSelf(const YGNodeConstRef node) { return node->getStyle().alignSelf(); } -void YGNodeStyleSetPositionType( +YOGA_EXPORT void YGNodeStyleSetPositionType( const YGNodeRef node, const YGPositionType positionType) { updateStyle( node, &YGStyle::positionType, positionType); } -YGPositionType YGNodeStyleGetPositionType(const YGNodeConstRef node) { +YOGA_EXPORT YGPositionType +YGNodeStyleGetPositionType(const YGNodeConstRef node) { return node->getStyle().positionType(); } -void YGNodeStyleSetFlexWrap(const YGNodeRef node, const YGWrap flexWrap) { +YOGA_EXPORT void YGNodeStyleSetFlexWrap( + const YGNodeRef node, + const YGWrap flexWrap) { updateStyle(node, &YGStyle::flexWrap, flexWrap); } -YGWrap YGNodeStyleGetFlexWrap(const YGNodeConstRef node) { +YOGA_EXPORT YGWrap YGNodeStyleGetFlexWrap(const YGNodeConstRef node) { return node->getStyle().flexWrap(); } -void YGNodeStyleSetOverflow(const YGNodeRef node, const YGOverflow overflow) { +YOGA_EXPORT void YGNodeStyleSetOverflow( + const YGNodeRef node, + const YGOverflow overflow) { updateStyle(node, &YGStyle::overflow, overflow); } -YGOverflow YGNodeStyleGetOverflow(const YGNodeConstRef node) { +YOGA_EXPORT YGOverflow YGNodeStyleGetOverflow(const YGNodeConstRef node) { return node->getStyle().overflow(); } -void YGNodeStyleSetDisplay(const YGNodeRef node, const YGDisplay display) { +YOGA_EXPORT void YGNodeStyleSetDisplay( + const YGNodeRef node, + const YGDisplay display) { updateStyle(node, &YGStyle::display, display); } -YGDisplay YGNodeStyleGetDisplay(const YGNodeConstRef node) { +YOGA_EXPORT YGDisplay YGNodeStyleGetDisplay(const YGNodeConstRef node) { return node->getStyle().display(); } // TODO(T26792433): Change the API to accept YGFloatOptional. -void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) { +YOGA_EXPORT void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) { updateStyle(node, &YGStyle::flex, YGFloatOptional{flex}); } // TODO(T26792433): Change the API to accept YGFloatOptional. -float YGNodeStyleGetFlex(const YGNodeConstRef node) { +YOGA_EXPORT float YGNodeStyleGetFlex(const YGNodeConstRef node) { return node->getStyle().flex().isUndefined() ? YGUndefined : node->getStyle().flex().unwrap(); } // TODO(T26792433): Change the API to accept YGFloatOptional. -void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) { +YOGA_EXPORT void YGNodeStyleSetFlexGrow( + const YGNodeRef node, + const float flexGrow) { updateStyle( node, &YGStyle::flexGrow, YGFloatOptional{flexGrow}); } // TODO(T26792433): Change the API to accept YGFloatOptional. -void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) { +YOGA_EXPORT void YGNodeStyleSetFlexShrink( + const YGNodeRef node, + const float flexShrink) { updateStyle( node, &YGStyle::flexShrink, YGFloatOptional{flexShrink}); } -YGValue YGNodeStyleGetFlexBasis(const YGNodeConstRef node) { +YOGA_EXPORT YGValue YGNodeStyleGetFlexBasis(const YGNodeConstRef node) { YGValue flexBasis = node->getStyle().flexBasis(); if (flexBasis.unit == YGUnitUndefined || flexBasis.unit == YGUnitAuto) { // TODO(T26792433): Get rid off the use of YGUndefined at client side @@ -678,71 +713,91 @@ YGValue YGNodeStyleGetFlexBasis(const YGNodeConstRef node) { return flexBasis; } -void YGNodeStyleSetFlexBasis(const YGNodeRef node, const float flexBasis) { +YOGA_EXPORT void YGNodeStyleSetFlexBasis( + const YGNodeRef node, + const float flexBasis) { auto value = detail::CompactValue::ofMaybe(flexBasis); updateStyle(node, &YGStyle::flexBasis, value); } -void YGNodeStyleSetFlexBasisPercent( +YOGA_EXPORT void YGNodeStyleSetFlexBasisPercent( const YGNodeRef node, const float flexBasisPercent) { auto value = detail::CompactValue::ofMaybe(flexBasisPercent); updateStyle(node, &YGStyle::flexBasis, value); } -void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) { +YOGA_EXPORT void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) { updateStyle( node, &YGStyle::flexBasis, detail::CompactValue::ofAuto()); } -void YGNodeStyleSetPosition(YGNodeRef node, YGEdge edge, float points) { +YOGA_EXPORT void YGNodeStyleSetPosition( + YGNodeRef node, + YGEdge edge, + float points) { auto value = detail::CompactValue::ofMaybe(points); updateIndexedStyleProp( node, &YGStyle::position, edge, value); } -void YGNodeStyleSetPositionPercent(YGNodeRef node, YGEdge edge, float percent) { +YOGA_EXPORT void YGNodeStyleSetPositionPercent( + YGNodeRef node, + YGEdge edge, + float percent) { auto value = detail::CompactValue::ofMaybe(percent); updateIndexedStyleProp( node, &YGStyle::position, edge, value); } -YGValue YGNodeStyleGetPosition(YGNodeConstRef node, YGEdge edge) { +YOGA_EXPORT YGValue YGNodeStyleGetPosition(YGNodeConstRef node, YGEdge edge) { return node->getStyle().position()[edge]; } -void YGNodeStyleSetMargin(YGNodeRef node, YGEdge edge, float points) { +YOGA_EXPORT void YGNodeStyleSetMargin( + YGNodeRef node, + YGEdge edge, + float points) { auto value = detail::CompactValue::ofMaybe(points); updateIndexedStyleProp( node, &YGStyle::margin, edge, value); } -void YGNodeStyleSetMarginPercent(YGNodeRef node, YGEdge edge, float percent) { +YOGA_EXPORT void YGNodeStyleSetMarginPercent( + YGNodeRef node, + YGEdge edge, + float percent) { auto value = detail::CompactValue::ofMaybe(percent); updateIndexedStyleProp( node, &YGStyle::margin, edge, value); } -void YGNodeStyleSetMarginAuto(YGNodeRef node, YGEdge edge) { +YOGA_EXPORT void YGNodeStyleSetMarginAuto(YGNodeRef node, YGEdge edge) { updateIndexedStyleProp( node, &YGStyle::margin, edge, detail::CompactValue::ofAuto()); } -YGValue YGNodeStyleGetMargin(YGNodeConstRef node, YGEdge edge) { +YOGA_EXPORT YGValue YGNodeStyleGetMargin(YGNodeConstRef node, YGEdge edge) { return node->getStyle().margin()[edge]; } -void YGNodeStyleSetPadding(YGNodeRef node, YGEdge edge, float points) { +YOGA_EXPORT void YGNodeStyleSetPadding( + YGNodeRef node, + YGEdge edge, + float points) { auto value = detail::CompactValue::ofMaybe(points); updateIndexedStyleProp( node, &YGStyle::padding, edge, value); } -void YGNodeStyleSetPaddingPercent(YGNodeRef node, YGEdge edge, float percent) { +YOGA_EXPORT void YGNodeStyleSetPaddingPercent( + YGNodeRef node, + YGEdge edge, + float percent) { auto value = detail::CompactValue::ofMaybe(percent); updateIndexedStyleProp( node, &YGStyle::padding, edge, value); } -YGValue YGNodeStyleGetPadding(YGNodeConstRef node, YGEdge edge) { +YOGA_EXPORT YGValue YGNodeStyleGetPadding(YGNodeConstRef node, YGEdge edge) { return node->getStyle().padding()[edge]; } // TODO(T26792433): Change the API to accept YGFloatOptional. -void YGNodeStyleSetBorder( +YOGA_EXPORT void YGNodeStyleSetBorder( const YGNodeRef node, const YGEdge edge, const float border) { @@ -751,7 +806,9 @@ void YGNodeStyleSetBorder( node, &YGStyle::border, edge, value); } -float YGNodeStyleGetBorder(const YGNodeConstRef node, const YGEdge edge) { +YOGA_EXPORT float YGNodeStyleGetBorder( + const YGNodeConstRef node, + const YGEdge edge) { auto border = node->getStyle().border()[edge]; if (border.isUndefined() || border.isAuto()) { // TODO(T26792433): Rather than returning YGUndefined, change the api to @@ -765,126 +822,141 @@ float YGNodeStyleGetBorder(const YGNodeConstRef node, const YGEdge edge) { // Yoga specific properties, not compatible with flexbox specification // TODO(T26792433): Change the API to accept YGFloatOptional. -float YGNodeStyleGetAspectRatio(const YGNodeConstRef node) { +YOGA_EXPORT float YGNodeStyleGetAspectRatio(const YGNodeConstRef node) { const YGFloatOptional op = node->getStyle().aspectRatio(); return op.isUndefined() ? YGUndefined : op.unwrap(); } // TODO(T26792433): Change the API to accept YGFloatOptional. -void YGNodeStyleSetAspectRatio(const YGNodeRef node, const float aspectRatio) { +YOGA_EXPORT void YGNodeStyleSetAspectRatio( + const YGNodeRef node, + const float aspectRatio) { updateStyle( node, &YGStyle::aspectRatio, YGFloatOptional{aspectRatio}); } -void YGNodeStyleSetWidth(YGNodeRef node, float points) { +YOGA_EXPORT void YGNodeStyleSetWidth(YGNodeRef node, float points) { auto value = detail::CompactValue::ofMaybe(points); updateIndexedStyleProp( node, &YGStyle::dimensions, YGDimensionWidth, value); } -void YGNodeStyleSetWidthPercent(YGNodeRef node, float percent) { +YOGA_EXPORT void YGNodeStyleSetWidthPercent(YGNodeRef node, float percent) { auto value = detail::CompactValue::ofMaybe(percent); updateIndexedStyleProp( node, &YGStyle::dimensions, YGDimensionWidth, value); } -void YGNodeStyleSetWidthAuto(YGNodeRef node) { +YOGA_EXPORT void YGNodeStyleSetWidthAuto(YGNodeRef node) { updateIndexedStyleProp( node, &YGStyle::dimensions, YGDimensionWidth, detail::CompactValue::ofAuto()); } -YGValue YGNodeStyleGetWidth(YGNodeConstRef node) { +YOGA_EXPORT YGValue YGNodeStyleGetWidth(YGNodeConstRef node) { return node->getStyle().dimensions()[YGDimensionWidth]; } -void YGNodeStyleSetHeight(YGNodeRef node, float points) { +YOGA_EXPORT void YGNodeStyleSetHeight(YGNodeRef node, float points) { auto value = detail::CompactValue::ofMaybe(points); updateIndexedStyleProp( node, &YGStyle::dimensions, YGDimensionHeight, value); } -void YGNodeStyleSetHeightPercent(YGNodeRef node, float percent) { +YOGA_EXPORT void YGNodeStyleSetHeightPercent(YGNodeRef node, float percent) { auto value = detail::CompactValue::ofMaybe(percent); updateIndexedStyleProp( node, &YGStyle::dimensions, YGDimensionHeight, value); } -void YGNodeStyleSetHeightAuto(YGNodeRef node) { +YOGA_EXPORT void YGNodeStyleSetHeightAuto(YGNodeRef node) { updateIndexedStyleProp( node, &YGStyle::dimensions, YGDimensionHeight, detail::CompactValue::ofAuto()); } -YGValue YGNodeStyleGetHeight(YGNodeConstRef node) { +YOGA_EXPORT YGValue YGNodeStyleGetHeight(YGNodeConstRef node) { return node->getStyle().dimensions()[YGDimensionHeight]; } -void YGNodeStyleSetMinWidth(const YGNodeRef node, const float minWidth) { +YOGA_EXPORT void YGNodeStyleSetMinWidth( + const YGNodeRef node, + const float minWidth) { auto value = detail::CompactValue::ofMaybe(minWidth); updateIndexedStyleProp( node, &YGStyle::minDimensions, YGDimensionWidth, value); } -void YGNodeStyleSetMinWidthPercent(const YGNodeRef node, const float minWidth) { +YOGA_EXPORT void YGNodeStyleSetMinWidthPercent( + const YGNodeRef node, + const float minWidth) { auto value = detail::CompactValue::ofMaybe(minWidth); updateIndexedStyleProp( node, &YGStyle::minDimensions, YGDimensionWidth, value); } -YGValue YGNodeStyleGetMinWidth(const YGNodeConstRef node) { +YOGA_EXPORT YGValue YGNodeStyleGetMinWidth(const YGNodeConstRef node) { return node->getStyle().minDimensions()[YGDimensionWidth]; }; -void YGNodeStyleSetMinHeight(const YGNodeRef node, const float minHeight) { +YOGA_EXPORT void YGNodeStyleSetMinHeight( + const YGNodeRef node, + const float minHeight) { auto value = detail::CompactValue::ofMaybe(minHeight); updateIndexedStyleProp( node, &YGStyle::minDimensions, YGDimensionHeight, value); } -void YGNodeStyleSetMinHeightPercent( +YOGA_EXPORT void YGNodeStyleSetMinHeightPercent( const YGNodeRef node, const float minHeight) { auto value = detail::CompactValue::ofMaybe(minHeight); updateIndexedStyleProp( node, &YGStyle::minDimensions, YGDimensionHeight, value); } -YGValue YGNodeStyleGetMinHeight(const YGNodeConstRef node) { +YOGA_EXPORT YGValue YGNodeStyleGetMinHeight(const YGNodeConstRef node) { return node->getStyle().minDimensions()[YGDimensionHeight]; }; -void YGNodeStyleSetMaxWidth(const YGNodeRef node, const float maxWidth) { +YOGA_EXPORT void YGNodeStyleSetMaxWidth( + const YGNodeRef node, + const float maxWidth) { auto value = detail::CompactValue::ofMaybe(maxWidth); updateIndexedStyleProp( node, &YGStyle::maxDimensions, YGDimensionWidth, value); } -void YGNodeStyleSetMaxWidthPercent(const YGNodeRef node, const float maxWidth) { +YOGA_EXPORT void YGNodeStyleSetMaxWidthPercent( + const YGNodeRef node, + const float maxWidth) { auto value = detail::CompactValue::ofMaybe(maxWidth); updateIndexedStyleProp( node, &YGStyle::maxDimensions, YGDimensionWidth, value); } -YGValue YGNodeStyleGetMaxWidth(const YGNodeConstRef node) { +YOGA_EXPORT YGValue YGNodeStyleGetMaxWidth(const YGNodeConstRef node) { return node->getStyle().maxDimensions()[YGDimensionWidth]; }; -void YGNodeStyleSetMaxHeight(const YGNodeRef node, const float maxHeight) { +YOGA_EXPORT void YGNodeStyleSetMaxHeight( + const YGNodeRef node, + const float maxHeight) { auto value = detail::CompactValue::ofMaybe(maxHeight); updateIndexedStyleProp( node, &YGStyle::maxDimensions, YGDimensionHeight, value); } -void YGNodeStyleSetMaxHeightPercent( +YOGA_EXPORT void YGNodeStyleSetMaxHeightPercent( const YGNodeRef node, const float maxHeight) { auto value = detail::CompactValue::ofMaybe(maxHeight); updateIndexedStyleProp( node, &YGStyle::maxDimensions, YGDimensionHeight, value); } -YGValue YGNodeStyleGetMaxHeight(const YGNodeConstRef node) { +YOGA_EXPORT YGValue YGNodeStyleGetMaxHeight(const YGNodeConstRef node) { return node->getStyle().maxDimensions()[YGDimensionHeight]; }; -#define YG_NODE_LAYOUT_PROPERTY_IMPL(type, name, instanceName) \ - type YGNodeLayoutGet##name(const YGNodeRef node) { \ - return node->getLayout().instanceName; \ +#define YG_NODE_LAYOUT_PROPERTY_IMPL(type, name, instanceName) \ + YOGA_EXPORT type YGNodeLayoutGet##name(const YGNodeRef node) { \ + return node->getLayout().instanceName; \ } #define YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(type, name, instanceName) \ - type YGNodeLayoutGet##name(const YGNodeRef node, const YGEdge edge) { \ + YOGA_EXPORT type YGNodeLayoutGet##name( \ + const YGNodeRef node, const YGEdge edge) { \ YGAssertWithNode( \ node, \ edge <= YGEdgeEnd, \ @@ -922,11 +994,12 @@ YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Margin, margin); YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Border, border); YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Padding, padding); -bool YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(const YGNodeRef node) { +YOGA_EXPORT bool YGNodeLayoutGetDidLegacyStretchFlagAffectLayout( + const YGNodeRef node) { return node->getLayout().doesLegacyStretchFlagAffectsLayout(); } -uint32_t gCurrentGenerationCount = 0; +std::atomic gCurrentGenerationCount(0); bool YGLayoutNodeInternal( const YGNodeRef node, @@ -954,7 +1027,9 @@ static void YGNodePrintInternal( Log::log(node, YGLogLevelDebug, nullptr, str.c_str()); } -void YGNodePrint(const YGNodeRef node, const YGPrintOptions options) { +YOGA_EXPORT void YGNodePrint( + const YGNodeRef node, + const YGPrintOptions options) { YGNodePrintInternal(node, options); } #endif @@ -1595,13 +1670,13 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions( "Expected node to have custom measure function"); const float paddingAndBorderAxisRow = - YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, availableWidth); - const float paddingAndBorderAxisColumn = YGNodePaddingAndBorderForAxis( - node, YGFlexDirectionColumn, availableWidth); + YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, ownerWidth); + const float paddingAndBorderAxisColumn = + YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, ownerWidth); const float marginAxisRow = - node->getMarginForAxis(YGFlexDirectionRow, availableWidth).unwrap(); + node->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap(); const float marginAxisColumn = - node->getMarginForAxis(YGFlexDirectionColumn, availableWidth).unwrap(); + node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap(); // We want to make sure we don't call measure with negative size const float innerWidth = YGFloatIsUndefined(availableWidth) @@ -1793,15 +1868,17 @@ static float YGNodeCalculateAvailableInnerDim( const YGNodeConstRef node, YGFlexDirection axis, float availableDim, - float ownerDim) { + float ownerDim, + float ownerDimForMarginPadding) { YGFlexDirection direction = YGFlexDirectionIsRow(axis) ? YGFlexDirectionRow : YGFlexDirectionColumn; YGDimension dimension = YGFlexDirectionIsRow(axis) ? YGDimensionWidth : YGDimensionHeight; - const float margin = node->getMarginForAxis(direction, ownerDim).unwrap(); + const float margin = + node->getMarginForAxis(direction, ownerDimForMarginPadding).unwrap(); const float paddingAndBorder = - YGNodePaddingAndBorderForAxis(node, direction, ownerDim); + YGNodePaddingAndBorderForAxis(node, direction, ownerDimForMarginPadding); float availableInnerDim = availableDim - margin - paddingAndBorder; // Max dimension overrides predefined dimension value; Min dimension in turn @@ -1844,7 +1921,7 @@ static float YGNodeComputeFlexBasisForChildren( const uint32_t generationCount) { float totalOuterFlexBasis = 0.0f; YGNodeRef singleFlexChild = nullptr; - const YGVector &children = node->getChildren(); + const YGVector& children = node->getChildren(); YGMeasureMode measureModeMainDim = YGFlexDirectionIsRow(mainAxis) ? widthMeasureMode : heightMeasureMode; // If there is only one child with flexGrow + flexShrink it means we can set @@ -2819,9 +2896,9 @@ static void YGNodelayoutImpl( // STEP 2: DETERMINE AVAILABLE SIZE IN MAIN AND CROSS DIRECTIONS float availableInnerWidth = YGNodeCalculateAvailableInnerDim( - node, YGFlexDirectionRow, availableWidth, ownerWidth); + node, YGFlexDirectionRow, availableWidth, ownerWidth, ownerWidth); float availableInnerHeight = YGNodeCalculateAvailableInnerDim( - node, YGFlexDirectionColumn, availableHeight, ownerHeight); + node, YGFlexDirectionColumn, availableHeight, ownerHeight, ownerWidth); float availableInnerMainDim = isMainAxisRow ? availableInnerWidth : availableInnerHeight; @@ -3570,12 +3647,12 @@ static inline bool YGMeasureModeNewMeasureSizeIsStricterAndStillValid( (lastComputedSize <= size || YGFloatsEqual(size, lastComputedSize)); } -float YGRoundValueToPixelGrid( +YOGA_EXPORT float YGRoundValueToPixelGrid( const float value, const float pointScaleFactor, const bool forceCeil, const bool forceFloor) { - float scaledValue = value * pointScaleFactor; + double scaledValue = ((double) value) * pointScaleFactor; // We want to calculate `fractial` such that `floor(scaledValue) = scaledValue // - fractial`. float fractial = fmodf(scaledValue, 1.0f); @@ -3621,7 +3698,7 @@ float YGRoundValueToPixelGrid( : scaledValue / pointScaleFactor; } -bool YGNodeCanUseCachedMeasurement( +YOGA_EXPORT bool YGNodeCanUseCachedMeasurement( const YGMeasureMode widthMode, const float width, const YGMeasureMode heightMode, @@ -3967,7 +4044,7 @@ bool YGLayoutNodeInternal( return (needToVisitNode || cachedResults == nullptr); } -void YGConfigSetPointScaleFactor( +YOGA_EXPORT void YGConfigSetPointScaleFactor( const YGConfigRef config, const float pixelsInPoint) { YGAssertWithConfig( @@ -4064,7 +4141,7 @@ static void unsetUseLegacyFlagRecursively(YGNodeRef node) { } } -void YGNodeCalculateLayoutWithContext( +YOGA_EXPORT void YGNodeCalculateLayoutWithContext( const YGNodeRef node, const float ownerWidth, const float ownerHeight, @@ -4076,7 +4153,7 @@ void YGNodeCalculateLayoutWithContext( // Increment the generation count. This will force the recursive routine to // visit all dirty nodes at least once. Subsequent visits will be skipped if // the input parameters don't change. - gCurrentGenerationCount++; + gCurrentGenerationCount.fetch_add(1, std::memory_order_relaxed); node->resolveDimension(); float width = YGUndefined; YGMeasureMode widthMeasureMode = YGMeasureModeUndefined; @@ -4133,7 +4210,7 @@ void YGNodeCalculateLayoutWithContext( markerData, layoutContext, 0, // tree root - gCurrentGenerationCount)) { + gCurrentGenerationCount.load(std::memory_order_relaxed))) { node->setPosition( node->getLayout().direction(), ownerWidth, ownerHeight, ownerWidth); YGRoundToPixelGrid(node, node->getConfig()->pointScaleFactor, 0.0f, 0.0f); @@ -4164,7 +4241,7 @@ void YGNodeCalculateLayoutWithContext( nodeWithoutLegacyFlag->resolveDimension(); // Recursively mark nodes as dirty nodeWithoutLegacyFlag->markDirtyAndPropogateDownwards(); - gCurrentGenerationCount++; + gCurrentGenerationCount.fetch_add(1, std::memory_order_relaxed); // Rerun the layout, and calculate the diff unsetUseLegacyFlagRecursively(nodeWithoutLegacyFlag); LayoutData layoutMarkerData = {}; @@ -4183,7 +4260,7 @@ void YGNodeCalculateLayoutWithContext( layoutMarkerData, layoutContext, 0, // tree root - gCurrentGenerationCount)) { + gCurrentGenerationCount.load(std::memory_order_relaxed))) { nodeWithoutLegacyFlag->setPosition( nodeWithoutLegacyFlag->getLayout().direction(), ownerWidth, @@ -4215,7 +4292,7 @@ void YGNodeCalculateLayoutWithContext( } } -void YGNodeCalculateLayout( +YOGA_EXPORT void YGNodeCalculateLayout( const YGNodeRef node, const float ownerWidth, const float ownerHeight, @@ -4224,7 +4301,7 @@ void YGNodeCalculateLayout( node, ownerWidth, ownerHeight, ownerDirection, nullptr); } -void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) { +YOGA_EXPORT void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) { if (logger != nullptr) { config->setLogger(logger); } else { @@ -4236,7 +4313,7 @@ void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) { } } -void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour( +YOGA_EXPORT void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour( const YGConfigRef config, const bool shouldDiffLayout) { config->shouldDiffLayoutWithoutLegacyStretchBehaviour = shouldDiffLayout; @@ -4266,7 +4343,7 @@ void YGAssertWithConfig( } } -void YGConfigSetExperimentalFeatureEnabled( +YOGA_EXPORT void YGConfigSetExperimentalFeatureEnabled( const YGConfigRef config, const YGExperimentalFeature feature, const bool enabled) { @@ -4279,11 +4356,13 @@ inline bool YGConfigIsExperimentalFeatureEnabled( return config->experimentalFeatures[feature]; } -void YGConfigSetUseWebDefaults(const YGConfigRef config, const bool enabled) { +YOGA_EXPORT void YGConfigSetUseWebDefaults( + const YGConfigRef config, + const bool enabled) { config->useWebDefaults = enabled; } -void YGConfigSetUseLegacyStretchBehaviour( +YOGA_EXPORT void YGConfigSetUseLegacyStretchBehaviour( const YGConfigRef config, const bool useLegacyStretchBehaviour) { config->useLegacyStretchBehaviour = useLegacyStretchBehaviour; @@ -4293,15 +4372,15 @@ bool YGConfigGetUseWebDefaults(const YGConfigRef config) { return config->useWebDefaults; } -void YGConfigSetContext(const YGConfigRef config, void *context) { +YOGA_EXPORT void YGConfigSetContext(const YGConfigRef config, void* context) { config->context = context; } -void *YGConfigGetContext(const YGConfigRef config) { +YOGA_EXPORT void* YGConfigGetContext(const YGConfigRef config) { return config->context; } -void YGConfigSetCloneNodeFunc( +YOGA_EXPORT void YGConfigSetCloneNodeFunc( const YGConfigRef config, const YGCloneNodeFunc callback) { config->setCloneNodeCallback(callback); diff --git a/vnext/DeforkingPatches/overrides.json b/vnext/DeforkingPatches/overrides.json index 0d3e1231e05..dde93dd7c94 100644 --- a/vnext/DeforkingPatches/overrides.json +++ b/vnext/DeforkingPatches/overrides.json @@ -1,35 +1,27 @@ { "overrides": [ - { - "type": "patch", - "file": "ReactCommon\\cxxreact\\NativeToJsBridge.h", - "baseFile": "ReactCommon\\cxxreact\\NativeToJsBridge.h", - "baseVersion": "0.61.5", - "baseHash": "b499aa46b3ed91570f8cb0de60e3add6c48cdf12", - "issue": "LEGACY_FIXME" - }, { "type": "patch", "file": "ReactCommon\\turbomodule\\samples\\SampleTurboCxxModule.cpp", "baseFile": "ReactCommon\\turbomodule\\samples\\SampleTurboCxxModule.cpp", - "baseVersion": "0.61.5", - "baseHash": "32ede21afc7337f33184e0ce267b6fde32a6dcc1", + "baseVersion": "0.62.0-rc.3", + "baseHash": "b8840ecbf1d0a61d5e13d6f9690722e41cacb7ab", "issue": "LEGACY_FIXME" }, { "type": "patch", "file": "ReactCommon\\turbomodule\\samples\\SampleTurboCxxModule.h", "baseFile": "ReactCommon\\turbomodule\\samples\\SampleTurboCxxModule.h", - "baseVersion": "0.61.5", - "baseHash": "d4b1ccfd00c77d4a9dacf5f1e668119847895895", + "baseVersion": "0.62.0-rc.3", + "baseHash": "2e4e38798e5504d891342e46da17ef3b073123d8", "issue": "LEGACY_FIXME" }, { "type": "patch", "file": "ReactCommon\\yoga\\yoga\\Yoga.cpp", "baseFile": "ReactCommon\\yoga\\yoga\\Yoga.cpp", - "baseVersion": "0.61.5", - "baseHash": "73d61e0276175fd2c9649f4c4b390f6173d365ae", + "baseVersion": "0.62.0-rc.3", + "baseHash": "20b4e90cca3e5e5bfcaa5fda7bb322a7efee1fa9", "issue": 3994 } ] diff --git a/vnext/Desktop.IntegrationTests/DesktopTestRunner.cpp b/vnext/Desktop.IntegrationTests/DesktopTestRunner.cpp index ed8a1f11282..165942c7f99 100644 --- a/vnext/Desktop.IntegrationTests/DesktopTestRunner.cpp +++ b/vnext/Desktop.IntegrationTests/DesktopTestRunner.cpp @@ -30,6 +30,27 @@ using std::vector; namespace Microsoft::React::Test { +class StubNativeModule : public facebook::xplat::module::CxxModule { + public: + StubNativeModule(std::string name) : m_name(std::move(name)) {} + + std::string getName() override { + return m_name; + } + + std::map getConstants() override { + // CxxModules require a constant or method to register properly + return {{"Dummy", "Something"}}; + } + + std::vector getMethods() override { + return {}; + } + + private: + std::string m_name; +}; + shared_ptr TestRunner::GetInstance( string &&jsBundleFile, vector> &&cxxModules, @@ -73,6 +94,10 @@ shared_ptr TestRunner::GetInstance( make_tuple( TestDeviceInfoModule::name, []() -> unique_ptr { return make_unique(); }, + nativeQueue), + make_tuple( + "StatusBarManager", + []() -> unique_ptr { return make_unique("StatusBarManager"); }, nativeQueue)}; // <0> string diff --git a/vnext/Desktop.IntegrationTests/WebSocketJSExecutorIntegrationTest.cpp b/vnext/Desktop.IntegrationTests/WebSocketJSExecutorIntegrationTest.cpp index 3f17ddbd59d..f83e5e23c0e 100644 --- a/vnext/Desktop.IntegrationTests/WebSocketJSExecutorIntegrationTest.cpp +++ b/vnext/Desktop.IntegrationTests/WebSocketJSExecutorIntegrationTest.cpp @@ -51,6 +51,7 @@ TEST_CLASS (WebSocketJSExecutorIntegrationTest) { } BEGIN_TEST_METHOD_ATTRIBUTE(LoadApplicationScriptSucceeds) + TEST_IGNORE() END_TEST_METHOD_ATTRIBUTE() TEST_METHOD(LoadApplicationScriptSucceeds) { auto jsQueue = make_shared(); diff --git a/vnext/Desktop/React.Windows.Desktop.vcxproj b/vnext/Desktop/React.Windows.Desktop.vcxproj index bba67fbda8a..a95ef3c358f 100644 --- a/vnext/Desktop/React.Windows.Desktop.vcxproj +++ b/vnext/Desktop/React.Windows.Desktop.vcxproj @@ -57,7 +57,7 @@ - $(ReactNativeWindowsDir);$(ReactNativeWindowsDir)Common;$(FollyDir);$(ReactNativeWindowsDir)stubs;$(MSBuildProjectDirectory);$(ReactNativeWindowsDir)ReactWindowsCore;$(ReactNativeWindowsDir)\ReactWindowsCore\tracing;$(ReactNativeWindowsDir)include\ReactWindowsCore;$(ReactNativeDir)\ReactCommon;$(ReactNativeWindowsDir)JSI\Shared;$(JSI_Source);$(IncludePath) + $(ReactNativeWindowsDir);$(ReactNativeWindowsDir)Common;$(FollyDir);$(ReactNativeWindowsDir)stubs;$(MSBuildProjectDirectory);$(ReactNativeWindowsDir)ReactWindowsCore;$(ReactNativeWindowsDir)\ReactWindowsCore\tracing;$(ReactNativeWindowsDir)include\ReactWindowsCore;$(ReactNativeDir)\ReactCommon;$(ReactNativeWindowsDir)JSI\Shared;$(JSI_Source);$(ReactNativeDir)\ReactCommon\callinvoker;$(IncludePath) true diff --git a/vnext/IntegrationTests/DummyTest.js b/vnext/IntegrationTests/DummyTest.js deleted file mode 100644 index dfd5f691592..00000000000 --- a/vnext/IntegrationTests/DummyTest.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - * @format - */ - -'use strict'; - -const React = require('react'); -const ReactNative = require('react-native'); - -const {AppRegistry, StyleSheet, Text, View} = ReactNative; - -const {TestModule} = ReactNative.NativeModules; - -class DummyTest extends React.Component { - componentDidMount() { - TestModule.markTestPassed(true); - } - - render() { - return ( - - Some text - - ); - } -} - -var styles = StyleSheet.create({ - container: {}, - row: {}, -}); - -AppRegistry.registerComponent('DummyTest', () => DummyTest); - -module.exports = DummyTest; diff --git a/vnext/IntegrationTests/IntegrationTestsAppWin.js b/vnext/IntegrationTests/IntegrationTestsAppWin.js deleted file mode 100644 index cd687c70c7f..00000000000 --- a/vnext/IntegrationTests/IntegrationTestsAppWin.js +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - * @format - */ - -require('react-native/IntegrationTests/IntegrationTestsApp'); diff --git a/vnext/IntegrationTests/LoggingTest.js b/vnext/IntegrationTests/LoggingTest.js deleted file mode 100644 index dcfda397354..00000000000 --- a/vnext/IntegrationTests/LoggingTest.js +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - * @format - */ - -'use strict'; - -const React = require('react'); -const ReactNative = require('react-native'); - -const {AppRegistry, StyleSheet, Text, View} = ReactNative; - -const {TestModule} = ReactNative.NativeModules; - -class LoggingTest extends React.Component { - componentDidMount() { - // Test the supported console logging methods - console.trace('This is from console.trace'); // trace - console.debug('This is from console.debug'); // trace - console.info('This is from console.info'); // info - console.log('This is from console.log'); // info - console.warn('This is from console.warn'); // warn - console.error('This is from console.error'); // error - - TestModule.markTestPassed(true); - } - - render() { - return ( - - Some text - - ); - } -} - -var styles = StyleSheet.create({ - container: {}, - row: {}, -}); - -AppRegistry.registerComponent('LoggingTest', () => LoggingTest); - -module.exports = LoggingTest; diff --git a/vnext/IntegrationTests/XHRTest.js b/vnext/IntegrationTests/XHRTest.js deleted file mode 100644 index 97f12b8b60d..00000000000 --- a/vnext/IntegrationTests/XHRTest.js +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - * @format - * @flow - */ -'use strict'; - -const React = require('react'); -const ReactNative = require('react-native'); - -const {Alert, AppRegistry, View} = ReactNative; - -const {TestModule} = ReactNative.NativeModules; - -class XHRTest extends React.Component<{}, Object> { - state: Object = { - downloading: false, - // set by onreadystatechange - contentLength: 1, - responseLength: 0, - // set by onprogress - progressTotal: 1, - progressLoaded: 0, - - readystateHandler: false, - progressHandler: true, - arraybuffer: false, - }; - - xhr: ?XMLHttpRequest = null; - - _download = () => { - let xhr; - if (this.xhr) { - xhr = this.xhr; - xhr.abort(); - } else { - xhr = this.xhr = new XMLHttpRequest(); - } - - const onreadystatechange = () => { - if (xhr.readyState === xhr.HEADERS_RECEIVED) { - const contentLength = parseInt( - xhr.getResponseHeader('Content-Length'), - 10, - ); - this.setState({ - contentLength, - responseLength: 0, - }); - } else if (xhr.readyState === xhr.LOADING && xhr.response) { - this.setState({ - responseLength: xhr.response.length, - }); - } - }; - - if (this.state.readystateHandler) { - xhr.onreadystatechange = onreadystatechange; - } - //ISS:2306365 - Uncomment when native module is complete. - //if (this.state.progressHandler) { - // xhr.onprogress = onprogress; - //} - if (this.state.arraybuffer) { - xhr.responseType = 'arraybuffer'; - } - xhr.onload = () => { - this.setState({downloading: false}); - if (xhr.status === 200) { - let responseType = `Response is a string, ${ - xhr.response.length - } characters long.`; - if (xhr.response instanceof ArrayBuffer) { - responseType = `Response is an ArrayBuffer, ${ - xhr.response.byteLength - } bytes long.`; - } - Alert.alert('Download complete!', responseType); - } else if (xhr.status !== 0) { - Alert.alert( - 'Error', - `Server returned HTTP status of ${xhr.status}: ${xhr.responseText}`, - ); - } else { - Alert.alert('Error', xhr.responseText); - } - }; - xhr.open('GET', 'http://aleph.gutenberg.org/cache/epub/100/pg100.txt.utf8'); - // Avoid gzip so we can actually show progress - xhr.setRequestHeader('Accept-Encoding', ''); - xhr.send(); - - this.setState({downloading: true}); - }; - - componentDidMount() { - try { - this._download(); - } catch (e) { - console.error(e); - } - - TestModule.markTestPassed(true); - } - - render() { - return ; - } -} - -AppRegistry.registerComponent('XHRTest', () => XHRTest); - -module.exports = XHRTest; diff --git a/vnext/JSI.Desktop.UnitTests/JSI.Desktop.UnitTests.vcxproj b/vnext/JSI.Desktop.UnitTests/JSI.Desktop.UnitTests.vcxproj index 6d2c43c82ac..84023b07da8 100644 --- a/vnext/JSI.Desktop.UnitTests/JSI.Desktop.UnitTests.vcxproj +++ b/vnext/JSI.Desktop.UnitTests/JSI.Desktop.UnitTests.vcxproj @@ -36,7 +36,7 @@ - $(ReactNativeWindowsDir);$(ReactNativeWindowsDir)Common;$(ReactNativeWindowsDir)stubs;$(FollyDir);$(ReactNativeDir)\ReactCommon;$(JSI_Source);$(ReactNativeWindowsDir)ReactWindowsCore;$(ReactNativeWindowsDir)\ReactWindowsCore\tracing;$(ReactNativeWindowsDir)include\ReactWindowsCore;$(ReactNativeWindowsDir)Desktop;$(ReactNativeWindowsDir)IntegrationTests;$(ReactNativeWindowsDir)JSI\Shared;$(MSBuildProjectDirectory);$(IncludePath) + $(ReactNativeWindowsDir);$(ReactNativeWindowsDir)Common;$(ReactNativeWindowsDir)stubs;$(FollyDir);$(ReactNativeDir)\ReactCommon;$(JSI_Source);$(ReactNativeWindowsDir)ReactWindowsCore;$(ReactNativeWindowsDir)\ReactWindowsCore\tracing;$(ReactNativeWindowsDir)include\ReactWindowsCore;$(ReactNativeWindowsDir)Desktop;$(ReactNativeWindowsDir)IntegrationTests;$(ReactNativeWindowsDir)JSI\Shared;$(MSBuildProjectDirectory);$(ReactNativeDir)\ReactCommon\callinvoker;$(IncludePath) true diff --git a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj index 642446ab750..359c92e5501 100644 --- a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +++ b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj @@ -106,6 +106,7 @@ $(FollyDir); $(JSI_SourcePath); $(ReactNativeDir)ReactCommon; + $(ReactNativeDir)\ReactCommon\callinvoker; $(ReactNativeDir)ReactCommon\jsi; $(ReactNativeWindowsDir); $(ReactNativeWindowsDir)Common; diff --git a/vnext/ReactCommon/ReactCommon.vcxproj b/vnext/ReactCommon/ReactCommon.vcxproj index bece6ce84aa..846b89deded 100644 --- a/vnext/ReactCommon/ReactCommon.vcxproj +++ b/vnext/ReactCommon/ReactCommon.vcxproj @@ -68,7 +68,15 @@ NotUsing false true - $(ReactNativeDir)\ReactCommon;$(JSI_SourcePath);$(JSI_Source);$(ReactNativeDir)\ReactCommon\jscallinvoker;$(ReactNativeDir)\ReactCommon\jsiexecutor;$(FollyDir);$(ReactNativeWindowsDir)stubs;$(ReactNativeWindowsDir)\ReactWindowsCore\tracing;%(AdditionalIncludeDirectories) + + $(ReactNativeDir)\ReactCommon; + $(JSI_SourcePath);$(JSI_Source); + $(ReactNativeDir)\ReactCommon\callinvoker; + $(ReactNativeDir)\ReactCommon\jsiexecutor; + $(FollyDir);$(ReactNativeWindowsDir)stubs; + $(ReactNativeWindowsDir)\ReactWindowsCore\tracing; + %(AdditionalIncludeDirectories); + _WIN32;_CRT_SECURE_NO_WARNINGS;FOLLY_NO_CONFIG;NOMINMAX;RN_EXPORT=;JSI_EXPORT=;WIN32;_WINDLL;%(PreprocessorDefinitions) 4715;4146;4251;4800;4804;4305;4722;%(DisableSpecificWarnings) @@ -138,25 +146,25 @@ true - - + + - - - - - + + + + + - + - - + + - + diff --git a/vnext/ReactCopies/IntegrationTests/AccessibilityManagerTest.js b/vnext/ReactCopies/IntegrationTests/AccessibilityManagerTest.js index 313b8990346..dd155cec22c 100644 --- a/vnext/ReactCopies/IntegrationTests/AccessibilityManagerTest.js +++ b/vnext/ReactCopies/IntegrationTests/AccessibilityManagerTest.js @@ -18,7 +18,7 @@ const {TestModule} = ReactNative.NativeModules; import NativeAccessibilityManager from 'react-native/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager'; import invariant from 'invariant'; -class AccessibilityManagerTest extends React.Component<{}> { +class AccessibilityManagerTest extends React.Component<{...}> { componentDidMount() { invariant( NativeAccessibilityManager, diff --git a/vnext/ReactCopies/IntegrationTests/AppEventsTest.js b/vnext/ReactCopies/IntegrationTests/AppEventsTest.js index 4bc0b0649c1..650203ed233 100644 --- a/vnext/ReactCopies/IntegrationTests/AppEventsTest.js +++ b/vnext/ReactCopies/IntegrationTests/AppEventsTest.js @@ -19,14 +19,19 @@ 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() { diff --git a/vnext/ReactCopies/IntegrationTests/AsyncStorageTest.js b/vnext/ReactCopies/IntegrationTests/AsyncStorageTest.js index 5df923c7f67..e33cedfdd82 100644 --- a/vnext/ReactCopies/IntegrationTests/AsyncStorageTest.js +++ b/vnext/ReactCopies/IntegrationTests/AsyncStorageTest.js @@ -171,8 +171,8 @@ function testOptimizedMultiGet() { }); } -class AsyncStorageTest extends React.Component<{}, $FlowFixMeState> { - state: any | $TEMPORARY$object<{|done: boolean, messages: string|}> = { +class AsyncStorageTest extends React.Component<{...}, $FlowFixMeState> { + state: any | {|done: boolean, messages: string|} = { messages: 'Initializing...', done: false, }; diff --git a/vnext/ReactCopies/IntegrationTests/GlobalEvalWithSourceUrlTest.js b/vnext/ReactCopies/IntegrationTests/GlobalEvalWithSourceUrlTest.js index 0fd59bc2644..52fbe0e2fa8 100644 --- a/vnext/ReactCopies/IntegrationTests/GlobalEvalWithSourceUrlTest.js +++ b/vnext/ReactCopies/IntegrationTests/GlobalEvalWithSourceUrlTest.js @@ -17,7 +17,7 @@ const {View} = ReactNative; const {TestModule} = ReactNative.NativeModules; -class GlobalEvalWithSourceUrlTest extends React.Component<{}> { +class GlobalEvalWithSourceUrlTest extends React.Component<{...}> { componentDidMount() { if (typeof global.globalEvalWithSourceUrl !== 'function') { throw new Error( diff --git a/vnext/ReactCopies/IntegrationTests/ImageCachePolicyTest.js b/vnext/ReactCopies/IntegrationTests/ImageCachePolicyTest.js index d25e6c2b86e..03857091072 100644 --- a/vnext/ReactCopies/IntegrationTests/ImageCachePolicyTest.js +++ b/vnext/ReactCopies/IntegrationTests/ImageCachePolicyTest.js @@ -27,16 +27,17 @@ 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 { - state: $FlowFixMe | $TEMPORARY$object<{||}> = {}; + state: $FlowFixMe | {...} = {}; shouldComponentUpdate(nextProps: Props, nextState: State): boolean { const results: Array = TESTS.map(x => nextState[x]); @@ -63,7 +64,7 @@ class ImageCachePolicyTest extends React.Component { { { { { +class ImageSnapshotTest extends React.Component<{...}> { componentDidMount() { if (!TestModule.verifySnapshot) { throw new Error('TestModule.verifySnapshot not defined.'); diff --git a/vnext/ReactCopies/IntegrationTests/IntegrationTestsApp.js b/vnext/ReactCopies/IntegrationTests/IntegrationTestsApp.js index c8af81bf126..c52fe515221 100644 --- a/vnext/ReactCopies/IntegrationTests/IntegrationTestsApp.js +++ b/vnext/ReactCopies/IntegrationTests/IntegrationTestsApp.js @@ -51,7 +51,7 @@ require('./LoggingTestModule'); type Test = any; -class IntegrationTestsApp extends React.Component<{}, $FlowFixMeState> { +class IntegrationTestsApp extends React.Component<{...}, $FlowFixMeState> { state = { test: (null: ?Test), }; diff --git a/vnext/ReactCopies/IntegrationTests/LayoutEventsTest.js b/vnext/ReactCopies/IntegrationTests/LayoutEventsTest.js index 42def2c419b..c86592a600b 100644 --- a/vnext/ReactCopies/IntegrationTests/LayoutEventsTest.js +++ b/vnext/ReactCopies/IntegrationTests/LayoutEventsTest.js @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @format - * @flow + * @flow strict-local */ 'use strict'; @@ -38,6 +38,7 @@ type State = { viewLayout?: Layout, viewStyle?: ViewStyleProp, containerStyle?: ViewStyleProp, + ... }; class LayoutEventsTest extends React.Component { diff --git a/vnext/ReactCopies/IntegrationTests/PromiseTest.js b/vnext/ReactCopies/IntegrationTests/PromiseTest.js index b35c971fc34..809f6eb873d 100644 --- a/vnext/ReactCopies/IntegrationTests/PromiseTest.js +++ b/vnext/ReactCopies/IntegrationTests/PromiseTest.js @@ -15,7 +15,7 @@ const ReactNative = require('react-native'); const {View} = ReactNative; const {TestModule} = ReactNative.NativeModules; -class PromiseTest extends React.Component<{}> { +class PromiseTest extends React.Component<{...}> { shouldResolve: boolean = false; shouldReject: boolean = false; shouldSucceedAsync: boolean = false; diff --git a/vnext/ReactCopies/IntegrationTests/ReactContentSizeUpdateTest.js b/vnext/ReactCopies/IntegrationTests/ReactContentSizeUpdateTest.js index 47373d6f2a8..eefb6681b25 100644 --- a/vnext/ReactCopies/IntegrationTests/ReactContentSizeUpdateTest.js +++ b/vnext/ReactCopies/IntegrationTests/ReactContentSizeUpdateTest.js @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @format - * @flow + * @flow strict-local */ 'use strict'; diff --git a/vnext/ReactCopies/IntegrationTests/SimpleSnapshotTest.js b/vnext/ReactCopies/IntegrationTests/SimpleSnapshotTest.js index 90cb3f1e17c..db50c75e2fa 100644 --- a/vnext/ReactCopies/IntegrationTests/SimpleSnapshotTest.js +++ b/vnext/ReactCopies/IntegrationTests/SimpleSnapshotTest.js @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @format - * @flow + * @flow strict-local */ 'use strict'; @@ -18,7 +18,7 @@ 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.'); diff --git a/vnext/ReactCopies/IntegrationTests/SizeFlexibilityUpdateTest.js b/vnext/ReactCopies/IntegrationTests/SizeFlexibilityUpdateTest.js index 419083c57a3..fe7a2944853 100644 --- a/vnext/ReactCopies/IntegrationTests/SizeFlexibilityUpdateTest.js +++ b/vnext/ReactCopies/IntegrationTests/SizeFlexibilityUpdateTest.js @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @format - * @flow + * @flow strict-local */ 'use strict'; @@ -54,7 +54,8 @@ class SizeFlexibilityUpdateTest extends React.Component { rootViewDidChangeIntrinsicSize: (intrinsicSize: { height: number, width: number, - }) => void = (intrinsicSize: {width: number, height: number}) => { + ... + }) => void = (intrinsicSize: {width: number, height: number, ...}) => { if (finalState) { // If a test reaches its final state, it is not expected to do anything more TestModule.markTestPassed(false); diff --git a/vnext/ReactCopies/IntegrationTests/SyncMethodTest.js b/vnext/ReactCopies/IntegrationTests/SyncMethodTest.js index 8dbb5b94ad7..077884256d2 100644 --- a/vnext/ReactCopies/IntegrationTests/SyncMethodTest.js +++ b/vnext/ReactCopies/IntegrationTests/SyncMethodTest.js @@ -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' diff --git a/vnext/ReactCopies/IntegrationTests/WebSocketTest.js b/vnext/ReactCopies/IntegrationTests/WebSocketTest.js index fcc2d74cb8d..3435feabb11 100644 --- a/vnext/ReactCopies/IntegrationTests/WebSocketTest.js +++ b/vnext/ReactCopies/IntegrationTests/WebSocketTest.js @@ -28,9 +28,10 @@ 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, diff --git a/vnext/ReactCopies/IntegrationTests/websocket_integration_test_server.js b/vnext/ReactCopies/IntegrationTests/websocket_integration_test_server.js index 6d4c2d27731..36c73bed65e 100644 --- a/vnext/ReactCopies/IntegrationTests/websocket_integration_test_server.js +++ b/vnext/ReactCopies/IntegrationTests/websocket_integration_test_server.js @@ -1,5 +1,4 @@ #!/usr/bin/env node - /** * Copyright (c) Facebook, Inc. and its affiliates. * @@ -9,6 +8,7 @@ * @flow * @format */ + 'use strict'; /* eslint-env node */ diff --git a/vnext/ReactCopies/RNTester/js/RNTesterApp.android.js b/vnext/ReactCopies/RNTester/js/RNTesterApp.android.js index bd5201d86af..fd3655deec2 100644 --- a/vnext/ReactCopies/RNTester/js/RNTesterApp.android.js +++ b/vnext/ReactCopies/RNTester/js/RNTesterApp.android.js @@ -10,7 +10,16 @@ 'use strict'; +const RNTesterActions = require('./utils/RNTesterActions'); +const RNTesterExampleContainer = require('./components/RNTesterExampleContainer'); +const RNTesterExampleList = require('./components/RNTesterExampleList'); +const RNTesterList = require('./utils/RNTesterList'); +const RNTesterNavigationReducer = require('./utils/RNTesterNavigationReducer'); const React = require('react'); +const URIActionMap = require('./utils/URIActionMap'); + +const nativeImageSource = require('../../Libraries/Image/nativeImageSource'); + const { AppRegistry, AsyncStorage, @@ -24,26 +33,19 @@ const { Text, TouchableWithoutFeedback, UIManager, + useColorScheme, View, } = require('react-native'); -const RNTesterActions = require('./utils/RNTesterActions'); -const RNTesterExampleContainer = require('./components/RNTesterExampleContainer'); -const RNTesterExampleList = require('./components/RNTesterExampleList'); -const RNTesterList = require('./utils/RNTesterList'); -const RNTesterNavigationReducer = require('./utils/RNTesterNavigationReducer'); -const URIActionMap = require('./utils/URIActionMap'); - -const nativeImageSource = require('../../Libraries/Image/nativeImageSource'); +import type {RNTesterExample} from './types/RNTesterTypes'; import type {RNTesterNavigationState} from './utils/RNTesterNavigationReducer'; +import {RNTesterThemeContext, themes} from './components/RNTesterTheme'; UIManager.setLayoutAnimationEnabledExperimental(true); const DRAWER_WIDTH_LEFT = 56; -type Props = { - exampleFromAppetizeParams?: ?string, -}; +type Props = {exampleFromAppetizeParams?: ?string, ...}; const APP_STATE_KEY = 'RNTesterAppState.v2'; @@ -53,18 +55,115 @@ const HEADER_NAV_ICON = nativeImageSource({ height: 48, }); -const Header = ({title, onPressDrawer}) => { +const Header = ({ + onPressDrawer, + title, +}: { + onPressDrawer?: () => mixed, + title: string, + ... +}) => ( + + {theme => { + return ( + + + + {title} + + + + + + + + + ); + }} + +); + +const RNTesterExampleContainerViaHook = ({ + onPressDrawer, + title, + module, + exampleRef, +}: { + onPressDrawer?: () => mixed, + title: string, + module: RNTesterExample, + exampleRef: () => void, + ... +}) => { + const colorScheme = useColorScheme(); + const theme = colorScheme === 'dark' ? themes.dark : themes.light; return ( - - - {title} + + +
+ - - - - + + ); +}; + +const RNTesterDrawerContentViaHook = ({ + onNavigate, + list, +}: { + onNavigate?: () => mixed, + list: { + ComponentExamples: Array, + APIExamples: Array, + ... + }, + ... +}) => { + const colorScheme = useColorScheme(); + const theme = colorScheme === 'dark' ? themes.dark : themes.light; + return ( + + + - + + ); +}; + +const RNTesterExampleListViaHook = ({ + title, + onPressDrawer, + onNavigate, + list, +}: { + title: string, + onPressDrawer?: () => mixed, + onNavigate?: () => mixed, + list: { + ComponentExamples: Array, + APIExamples: Array, + ... + }, + ... +}) => { + const colorScheme = useColorScheme(); + const theme = colorScheme === 'dark' ? themes.dark : themes.light; + return ( + + +
+ + + ); }; @@ -99,7 +198,7 @@ class RNTesterApp extends React.Component { }); } - render() { + render(): React.Node { if (!this.state) { return null; } @@ -132,14 +231,10 @@ class RNTesterApp extends React.Component { _renderDrawerContent = () => { return ( - - - + ); }; @@ -163,39 +258,31 @@ class RNTesterApp extends React.Component { ); } else if (ExampleModule) { return ( - -
=0.78.0 site=react_native_android_fb) This issue was found + * when making Flow check .android.js files. */ + onPressDrawer={() => this.drawer.openDrawer()} + title={ExampleModule.title} + module={ExampleModule} + exampleRef={example => { /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue * was found when making Flow check .android.js files. */ - onPressDrawer={() => this.drawer.openDrawer()} - /> - { - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue - * was found when making Flow check .android.js files. */ - this._exampleRef = example; - }} - /> - + this._exampleRef = example; + }} + /> ); } } return ( - -
=0.78.0 site=react_native_android_fb) This issue - * was found when making Flow check .android.js files. */ - onPressDrawer={() => this.drawer.openDrawer()} - /> - - + =0.78.0 site=react_native_android_fb) This issue was found + * when making Flow check .android.js files. */ + onPressDrawer={() => this.drawer.openDrawer()} + onNavigate={this._handleAction} + list={RNTesterList} + /> ); } @@ -245,7 +332,6 @@ const styles = StyleSheet.create({ flex: 1, }, toolbar: { - backgroundColor: '#E9EAED', height: 56, }, toolbarLeft: { @@ -267,7 +353,6 @@ const styles = StyleSheet.create({ drawerContentWrapper: { flex: 1, paddingTop: StatusBar.currentHeight, - backgroundColor: 'white', }, }); diff --git a/vnext/ReactCopies/RNTester/js/RNTesterApp.ios.js b/vnext/ReactCopies/RNTester/js/RNTesterApp.ios.js index 646b33920c9..8245a68d12b 100644 --- a/vnext/ReactCopies/RNTester/js/RNTesterApp.ios.js +++ b/vnext/ReactCopies/RNTester/js/RNTesterApp.ios.js @@ -25,9 +25,11 @@ const { BackHandler, Button, Linking, + Platform, SafeAreaView, StyleSheet, Text, + useColorScheme, View, YellowBox, } = require('react-native'); @@ -35,10 +37,10 @@ const { import type {RNTesterExample} from './types/RNTesterTypes'; import type {RNTesterAction} from './utils/RNTesterActions'; import type {RNTesterNavigationState} from './utils/RNTesterNavigationReducer'; +import {RNTesterThemeContext, themes} from './components/RNTesterTheme'; +import type {ColorSchemeName} from '../../Libraries/Utilities/NativeAppearance'; -type Props = { - exampleFromAppetizeParams?: ?string, -}; +type Props = {exampleFromAppetizeParams?: ?string, ...}; YellowBox.ignoreWarnings([ 'Module RCTImagePickerManager requires main queue setup', @@ -46,21 +48,96 @@ YellowBox.ignoreWarnings([ const APP_STATE_KEY = 'RNTesterAppState.v2'; -const Header = ({onBack, title}: {onBack?: () => mixed, title: string}) => ( - - - - {title} - - {onBack && ( - -