diff --git a/.ado/bumpFileVersions.js b/.ado/bumpFileVersions.js deleted file mode 100644 index 717d48eecf6..00000000000 --- a/.ado/bumpFileVersions.js +++ /dev/null @@ -1,8 +0,0 @@ -// @ts-check -// Just bump the local version numbers in the files... - -const { - updateVersionsInFiles, -} = require("./versionUtils"); - -updateVersionsInFiles(); diff --git a/.ado/publish.yml b/.ado/publish.yml index 5e891d30f42..3fcf1c341bc 100644 --- a/.ado/publish.yml +++ b/.ado/publish.yml @@ -37,17 +37,11 @@ jobs: - task: CmdLine@2 displayName: Update package version + name: updateVersionTask inputs: script: node ../.ado/updateVersion.js workingDirectory: vnext - # since the above task will update the package.json, we want to ensure that we use the correct version for the nuget - - task: PublishBuildArtifacts@1 - displayName: 'Publish updated package.json for nuget' - inputs: - PathtoPublish: 'vnext\package.json' - ArtifactName: 'UpdatedPackageJson' - - task: Npm@1 displayName: npm public publish (vnext) inputs: @@ -61,6 +55,8 @@ jobs: - job: RnwNativeBuild displayName: React-Native-Windows Native Build dependsOn: RnwNpmPublish + variables: + publishCommitId: $[ dependencies.RnwNpmPublish.outputs['updateVersionTask.publishCommitId'] ] strategy: matrix: X64Debug: @@ -90,13 +86,11 @@ jobs: steps: - # The RnwNpmPublish task does this too before publishing the npm package, - # but when each slice checks out code, its not going to have those changes + # Sync to point where the version numbers have been updated - task: CmdLine@2 - displayName: Update version numbers to align with publishing version inputs: - script: node ../.ado/bumpFileVersions.js - workingDirectory: vnext + script: git checkout $(publishCommitId) + - template: templates/npm-install-and-build.yml @@ -115,20 +109,28 @@ jobs: - job: RNWNuget - dependsOn: RnwNativeBuild + dependsOn: + - RnwNpmPublish + - RnwNativeBuild displayName: React-Native-Windows Build and Publish Nuget pool: name: OE Standard Pool + variables: + publishCommitId: $[ dependencies.RnwNpmPublish.outputs['updateVersionTask.publishCommitId'] ] + npmVersion: $[ dependencies.RnwNpmPublish.outputs['updateVersionTask.npmVersion'] ] + steps: - checkout: none #skip checking out the default repository resource - - task: DownloadBuildArtifacts@0 - displayName: 'Download source Artifact' + # The commit tag in the nuspec requires that we use at least nuget 4.6 + - task: NuGetToolInstaller@0 inputs: - artifactName: UpdatedPackageJson - downloadPath: $(System.DefaultWorkingDirectory) + versionSpec: '>=4.6.0' - template: templates/prep-and-pack-nuget.yml + parameters: + publishCommitId: $(publishCommitId) + npmVersion: $(npmVersion) - task: NuGetCommand@2 displayName: 'NuGet push' diff --git a/.ado/templates/prep-and-pack-nuget.yml b/.ado/templates/prep-and-pack-nuget.yml index b7ce2fcb293..5a0ce0b1da3 100644 --- a/.ado/templates/prep-and-pack-nuget.yml +++ b/.ado/templates/prep-and-pack-nuget.yml @@ -1,3 +1,6 @@ +parameters: + publishCommitId: '0' + npmVersion: '0.0.1-pr' steps: - task: DownloadBuildArtifacts@0 @@ -50,23 +53,10 @@ steps: robocopy $(System.DefaultWorkingDirectory)\ReactWindows-debug-arm $(System.DefaultWorkingDirectory)\NugetRoot\target\arm\debug /E /MOVE /NP robocopy $(System.DefaultWorkingDirectory)\ReactWindows-ship-arm $(System.DefaultWorkingDirectory)\NugetRoot\target\arm\ship /E /MOVE /NP - - task: PowerShell@2 - displayName: Extract version from package.json, and put it in nuspec - inputs: - targetType: inline # filePath | inline - script: | - if (Test-Path $env:SYSTEM_DEFAULTWORKINGDIRECTORY/UpdatedPackageJson/package.json) { - $lines = Get-Content $env:SYSTEM_DEFAULTWORKINGDIRECTORY/UpdatedPackageJson/package.json | Where {$_ -match '^\s*"version":.*'} - $npmVersion = $lines.Trim().Split()[1].Trim('",'); - } else { - $npmVersion = "0.0.1-pr" - } - (Get-Content $env:SYSTEM_DEFAULTWORKINGDIRECTORY/NugetRoot/ReactWin32.nuspec).replace('__BuildBuildNumber__', $npmVersion) | Set-Content $env:SYSTEM_DEFAULTWORKINGDIRECTORY/NugetRoot/ReactWin32.nuspec - (Get-Content $env:SYSTEM_DEFAULTWORKINGDIRECTORY/NugetRoot/ReactUwp.nuspec).replace('__BuildBuildNumber__', $npmVersion) | Set-Content $env:SYSTEM_DEFAULTWORKINGDIRECTORY/NugetRoot/ReactUwp.nuspec - - task: NuGetCommand@2 displayName: 'NuGet pack' inputs: command: pack packagesToPack: '$(System.DefaultWorkingDirectory)/NugetRoot/React*.nuspec' - packDestination: '$(System.DefaultWorkingDirectory)/NugetRoot/' \ No newline at end of file + packDestination: '$(System.DefaultWorkingDirectory)/NugetRoot/' + buildProperties: CommitId=${{parameters.publishCommitId}};npmVersion=${{parameters.npmVersion}} \ No newline at end of file diff --git a/.ado/templates/vs-build.yml b/.ado/templates/vs-build.yml index 273025ef7b6..2501c60cf67 100644 --- a/.ado/templates/vs-build.yml +++ b/.ado/templates/vs-build.yml @@ -14,7 +14,7 @@ steps: feedsToUse: config #vstsFeed: # Required when feedsToUse == Select #includeNuGetOrg: true # Required when feedsToUse == Select - nugetConfigPath: vnext/NuGet.config + nugetConfigPath: vnext/NuGet.config #externalFeedCredentials: # Optional #noCache: false #disableParallelProcessing: false diff --git a/.ado/updateVersion.js b/.ado/updateVersion.js index 970c278be2c..859d84f8ba5 100644 --- a/.ado/updateVersion.js +++ b/.ado/updateVersion.js @@ -65,6 +65,11 @@ function updateVersion() { exec(`git push origin HEAD:${tempPublishBranch} --follow-tags --verbose`); exec(`git push origin tag ${tagName}`); + // Record the updated npmVersion and commitId so that later build tasks can use it (to record in the nuget for instance) + const publishCommitId = execSync(`git rev-list -n 1 ${tagName}`); + console.log(`##vso[task.setvariable variable=publishCommitId;isOutput=true]${publishCommitId}`); + console.log(`##vso[task.setvariable variable=npmVersion;isOutput=true]${releaseVersion}`); + exec(`git checkout ${publishBranchName}`); exec(`git pull origin ${publishBranchName}`); exec(`git merge ${tempPublishBranch} --no-edit`); diff --git a/.ado/windows-vs-pr.yml b/.ado/windows-vs-pr.yml index c2d30c526a3..8227039782a 100644 --- a/.ado/windows-vs-pr.yml +++ b/.ado/windows-vs-pr.yml @@ -132,6 +132,90 @@ jobs: script: del SampleApp.uwp.bundle workingDirectory: vnext + - job: CliInit + displayName: Verify react-native init + pool: + vmImage: vs2017-win2016 + timeoutInMinutes: 60 # how long to run the job before automatically cancelling + cancelTimeoutInMinutes: 5 # how much time to give 'run always even if cancelled tasks' before killing them + steps: + - checkout: self # self represents the repo where the initial Pipelines YAML file was found + clean: true # whether to fetch clean each time + # fetchDepth: 2 # the depth of commits to ask Git to fetch + lfs: false # whether to download Git-LFS files + submodules: false # set to 'true' for a single level of submodules or 'recursive' to get submodules of submodules + persistCredentials: false # set to 'true' to leave the OAuth token in the Git config after the initial fetch + + # First do a build of the local package, since we point the cli at the local files, it needs to be pre-built + - task: CmdLine@2 + displayName: yarn install (local react-native-windows) + inputs: + script: yarn install --frozen-lockfile + workingDirectory: vnext + + - task: CmdLine@2 + displayName: yarn build (local react-native-windows) + inputs: + script: yarn build + workingDirectory: vnext + + # yarn ends up copying the whole node_modules folder when doing an install of a file package + # Delete node_modules, so that resolution is more like when installing from a published npm package + - task: CmdLine@2 + displayName: Remove node_modules + inputs: + script: rd /S /Q node_modules + workingDirectory: vnext + + - task: CmdLine@2 + displayName: Install react-native cli + inputs: + script: npm install -g react-native-cli + + - task: CmdLine@2 + displayName: Init new project + inputs: + script: react-native init testcli + workingDirectory: $(Agent.BuildDirectory) + + - task: CmdLine@2 + displayName: Install rnpm-plugin-windows + inputs: + script: yarn add rnpm-plugin-windows@file:$(Build.SourcesDirectory)\current\local-cli\rnpm\windows + workingDirectory: $(Agent.BuildDirectory)\testcli + + - task: CmdLine@2 + displayName: Apply windows template + inputs: + script: react-native windows --template vnext --windowsVersion file:$(Build.SourcesDirectory)\vnext + workingDirectory: $(Agent.BuildDirectory)\testcli + + - template: templates/install-SDK.yml + + - task: NuGetCommand@2 + displayName: NuGet restore + inputs: + command: restore + restoreSolution: $(Agent.BuildDirectory)\testcli\windows\testcli.sln + + - task: MSBuild@1 + displayName: MSBuild - Build the project + inputs: + solution: $(Agent.BuildDirectory)\testcli\windows\testcli.sln + msbuildVersion: '15.0' # Optional. Options: latest, 16.0, 15.0, 14.0, 12.0, 4.0 + msbuildArchitecture: 'x86' # Optional. Options: x86, x64 + platform: x64 # Optional + configuration: Debug # Optional + restoreNugetPackages: true + msbuildArguments: '/p:PreferredToolArchitecture=x64' # Optional + clean: true # Optional + + - task: CmdLine@2 + displayName: Create bundle + inputs: + script: react-native bundle --entry-file App.windows.js platform uwp --bundle-output test.bundle + workingDirectory: $(Agent.BuildDirectory)\testcli + - job: RnwNativePRBuild displayName: Windows Visual Studio with Win32 PR strategy: @@ -296,4 +380,9 @@ jobs: steps: - checkout: none #skip checking out the default repository resource + # The commit tag in the nuspec requires that we use at least nuget 4.6 + - task: NuGetToolInstaller@0 + inputs: + versionSpec: '>=4.6.0' + - template: templates/prep-and-pack-nuget.yml diff --git a/vnext/.editorconfig b/vnext/.editorconfig index e0bfb830ed3..8079f513337 100644 --- a/vnext/.editorconfig +++ b/vnext/.editorconfig @@ -14,10 +14,13 @@ indent_size = 2 end_of_line = crlf # Xml project files -[*.{csproj,vcxproj,pssproj,vcxproj.filters,targets,props}] +[*.{config,csproj,props,targets,vcxitems,vcxproj,vcxproj.filters}] end_of_line = crlf insert_final_newline = false [*.ps1] indent_style = tab indent_size = 4 + +[package.json] +insert_final_newline = false diff --git a/vnext/CHANGELOG.json b/vnext/CHANGELOG.json deleted file mode 100644 index 23cfa26759e..00000000000 --- a/vnext/CHANGELOG.json +++ /dev/null @@ -1,2666 +0,0 @@ -{ - "name": "react-native-win", - "entries": [ - { - "version": "0.6.4", - "tag": "react-native-win_v0.6.4", - "date": "Wed, 13 Mar 2019 07:16:37 GMT", - "comments": { - "patch": [ - { - "comment": "Update react-native to 0.57.0-microsoft.4", - "author": "Andrew Coates (REDMOND) ", - "commit": "bb4c115c0eaa35eb6d965c5b69f598bdfc7d8377" - } - ] - } - }, - { - "version": "0.6.3", - "tag": "react-native-win_v0.6.3", - "date": "Tue, 12 Mar 2019 20:22:42 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - expose more helpers & cleanup for customViewmanagers support", - "author": "Andy Himberger ", - "commit": "b0c5d67c1ea0cf3ca0a093345e75f9aef2d4c493" - } - ] - } - }, - { - "version": "0.6.2", - "tag": "react-native-win_v0.6.2", - "date": "Tue, 12 Mar 2019 02:41:20 GMT", - "comments": { - "patch": [ - { - "comment": "Update react-native to 0.57.0-microsoft.2", - "author": "Project Collection Build Service (office) ", - "commit": "1e4816dd96fa986da096b76879a4d8065df460b7" - } - ] - } - }, - { - "version": "0.6.1", - "tag": "react-native-win_v0.6.1", - "date": "Sat, 09 Mar 2019 21:28:30 GMT", - "comments": { - "patch": [ - { - "comment": "fix nuget packaging", - "author": "Andy Himberger ", - "commit": "a8d52e79bc74b6974882e1bc7108fb469ca2d1ee" - } - ] - } - }, - { - "version": "0.6.0", - "tag": "react-native-win_v0.6.0", - "date": "Sat, 09 Mar 2019 18:32:03 GMT", - "comments": { - "minor": [ - { - "comment": "added back SourceCodeModule", - "author": "Lena Hong ", - "commit": "6d3c5d83b76e4994e69b2d4741ace92bb81c2c15" - } - ] - } - }, - { - "version": "0.5.93", - "tag": "react-native-win_v0.5.93", - "date": "Fri, 08 Mar 2019 09:15:31 GMT", - "comments": { - "patch": [ - { - "comment": "Update to react-native@0.57.0-microsoft.1", - "author": "Andrew Coates (REDMOND) ", - "commit": "8b94d830c5cc789d58670aa597703daa29a43431" - } - ] - } - }, - { - "version": "0.5.92", - "tag": "react-native-win_v0.5.92", - "date": "Fri, 08 Mar 2019 00:33:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"react-native\" from `0.0.5` to `0.0.6`" - } - ] - } - }, - { - "version": "0.5.91", - "tag": "react-native-win_v0.5.91", - "date": "Thu, 07 Mar 2019 23:21:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"react-native\" from `0.0.4` to `0.0.5`" - } - ] - } - }, - { - "version": "0.5.90", - "tag": "react-native-win_v0.5.90", - "date": "Thu, 07 Mar 2019 22:02:00 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"react-native\" from `0.0.3` to `0.0.4`" - } - ] - } - }, - { - "version": "0.5.89", - "tag": "react-native-win_v0.5.89", - "date": "Thu, 07 Mar 2019 20:47:48 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - add tabIndex support", - "author": "Andy Himberger ", - "commit": "c520d53ddba253592ae1c68fac3d8a19b80a1aa3" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"react-native\" from `0.0.2` to `0.0.3`" - } - ] - } - }, - { - "version": "0.5.88", - "tag": "react-native-win_v0.5.88", - "date": "Thu, 07 Mar 2019 01:08:42 GMT", - "comments": { - "patch": [ - { - "comment": "devmain build fix", - "author": "Andy Himberger ", - "commit": "ff199ac1c5e7bc17d12b74ca34a5fd82bcf013ab" - }, - { - "comment": "rename start.js to cli.js, take args to enable bundle in addition to start", - "author": "Andy Himberger ", - "commit": "6d8c3f27e505b30db368aedd8788f3b71a47e789" - } - ] - } - }, - { - "version": "0.5.87", - "tag": "react-native-win_v0.5.87", - "date": "Wed, 06 Mar 2019 06:56:23 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - add support for custom ViewManagers", - "author": "Andy Himberger ", - "commit": "4a7c4684c65d5db61c89a1855c84394d8c6059b9" - } - ] - } - }, - { - "version": "0.5.86", - "tag": "react-native-win_v0.5.86", - "date": "Wed, 06 Mar 2019 05:43:46 GMT", - "comments": { - "patch": [ - { - "comment": "Rename microsoft react-native", - "author": "Andrew Coates (REDMOND) ", - "commit": "0c0c2e0fa8762dda21b96ec3031a90450a45607f" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"react-native\" from `0.0.1` to `0.0.2`" - } - ] - } - }, - { - "version": "0.5.85", - "tag": "react-native-win_v0.5.85", - "date": "Tue, 05 Mar 2019 20:54:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.3.8` to `0.3.9`" - } - ] - } - }, - { - "version": "0.5.84", - "tag": "react-native-win_v0.5.84", - "date": "Tue, 05 Mar 2019 07:11:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.3.7` to `0.3.8`" - } - ] - } - }, - { - "version": "0.5.83", - "tag": "react-native-win_v0.5.83", - "date": "Tue, 05 Mar 2019 05:02:15 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - keep instance alive longer in live reload/shutdown", - "author": "Andy Himberger ", - "commit": "88cb1615988f6c46c3aff45bf28ce052529facf7" - } - ] - } - }, - { - "version": "0.5.82", - "tag": "react-native-win_v0.5.82", - "date": "Tue, 05 Mar 2019 02:31:33 GMT", - "comments": { - "patch": [ - { - "comment": "Fix color properties of CalendarView plus enable null values for all properties but callbacks (resetting to defaults via ClearValue)", - "author": "Sasha Gil ", - "commit": "0dee528765b661c12c6cd00657231d546bd9b686" - }, - { - "comment": "uwp - add editable support to PickerUWP, fix DatePicker export", - "author": "Andy Himberger ", - "commit": "31cc1455bff826e173976ce4b1f22968578ab237" - }, - { - "comment": "Introduce CalendarView for UWP only (no Android, no JS, no Apple updates)", - "author": "Sasha Gil ", - "commit": "c200088828a6b8318fe74cd56694c4051acdb7d9" - }, - { - "comment": "Fix OnDateChanged event for DatePicker", - "author": "Ashita Khetan ", - "commit": "d4905a87b09738883ca766052b5385bbcf0e6c10" - }, - { - "comment": "Popup positioning", - "author": "Ashita Khetan ", - "commit": "6a095df7fa540900f7bb873c67d12ec33f5a5bce" - }, - { - "comment": "Fire onClick for View on SPACE or ENTER.", - "author": "Randy Flynn ", - "commit": "4f71d0f128dcd9c39908394b21d2fdf1cecc469f" - }, - { - "comment": "JSICore (react-free) libraries", - "author": "Tudor Mihai ", - "commit": "7692fb3852df570233ec890e21861ac0e804880b" - }, - { - "comment": "Stop writing to console in logMarker", - "author": "Vladimir Morozov (REDMOND) ", - "commit": "be04078deba465473c3ecbb71232544eb81ee3ed" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.3.6` to `0.3.7`" - } - ] - } - }, - { - "version": "0.5.80", - "tag": "react-native-win_v0.5.80", - "date": "Thu, 28 Feb 2019 04:47:08 GMT", - "comments": { - "patch": [ - { - "comment": "Turn off OnContent/OffContent for Switch view.", - "author": "Randy Flynn ", - "commit": "72e93afc48e273255e85790bcfbc480c6e2d33e5" - } - ] - } - }, - { - "version": "0.5.79", - "tag": "react-native-win_v0.5.79", - "date": "Thu, 28 Feb 2019 03:36:47 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - fix WebSocketModuleUwp build against non-final RS5 SDK", - "author": "Andy Himberger ", - "commit": "230b7b62162ec82f60a25bef802a6f641163d895" - }, - { - "comment": "uwp - fix ViewPanel leak", - "author": "Andy Himberger ", - "commit": "6c7a1802d6da70672f8bb00762f48abafd31d617" - } - ] - } - }, - { - "version": "0.5.78", - "tag": "react-native-win_v0.5.78", - "date": "Wed, 27 Feb 2019 20:16:40 GMT", - "comments": { - "patch": [ - { - "comment": "Implement acceptsKeyboardFocus on View.", - "author": "Randy Flynn ", - "commit": "d64338b7437415e1e9f616938694281c1635e33a" - } - ] - } - }, - { - "version": "0.5.77", - "tag": "react-native-win_v0.5.77", - "date": "Tue, 26 Feb 2019 20:40:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.3.4` to `0.3.5`" - } - ] - } - }, - { - "version": "0.5.76", - "tag": "react-native-win_v0.5.76", - "date": "Tue, 26 Feb 2019 08:18:38 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - avoid exceptions being thrown in WebSocketModule connect", - "author": "Andy Himberger ", - "commit": "44324bc6db6a9554e1b577200289949c9144a943" - }, - { - "comment": "Add DatePicker uwp component", - "author": "Ashita Khetan ", - "commit": "821c08e4eba70327a9d26a9369f9d4453f4d6bfe" - }, - { - "comment": "Merge with master and resolve review comments for datepicker", - "author": "Ashita Khetan ", - "commit": "821c08e4eba70327a9d26a9369f9d4453f4d6bfe" - } - ] - } - }, - { - "version": "0.5.75", - "tag": "react-native-win_v0.5.75", - "date": "Tue, 26 Feb 2019 05:55:00 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.3.3` to `0.3.4`" - } - ] - } - }, - { - "version": "0.5.74", - "tag": "react-native-win_v0.5.74", - "date": "Tue, 26 Feb 2019 03:39:43 GMT", - "comments": { - "patch": [ - { - "comment": "fix move case in UIManager::manageChildren", - "author": "Ethan Bernstein ", - "commit": "596d82c8329927130ddb3c554f2e389ea396dd3b" - }, - { - "comment": "TextInput onScroll onKeyPress", - "author": "Ravi Teja Koganti ", - "commit": "249a4a621c5623caa3c244b1dbc7c1297d3f444c" - } - ] - } - }, - { - "version": "0.5.73", - "tag": "react-native-win_v0.5.73", - "date": "Sat, 23 Feb 2019 22:42:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.3.2` to `0.3.3`" - } - ] - } - }, - { - "version": "0.5.72", - "tag": "react-native-win_v0.5.72", - "date": "Sat, 23 Feb 2019 01:53:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.3.1` to `0.3.2`" - } - ] - } - }, - { - "version": "0.5.71", - "tag": "react-native-win_v0.5.71", - "date": "Sat, 23 Feb 2019 00:46:26 GMT", - "comments": { - "patch": [ - { - "comment": "Pinned 'just-task' to \"0.7.6\" so that we stop picking up the latest version", - "author": "Tom Underhill ", - "commit": "e40e54e9df58b3cdd04cbe939121092dbf23485a" - } - ] - } - }, - { - "version": "0.5.70", - "tag": "react-native-win_v0.5.70", - "date": "Thu, 21 Feb 2019 13:47:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.3.0` to `0.3.1`" - } - ] - } - }, - { - "version": "0.5.69", - "tag": "react-native-win_v0.5.69", - "date": "Thu, 21 Feb 2019 12:43:12 GMT", - "comments": { - "patch": [ - { - "comment": "move react to peerDependencies", - "author": "Andy Himberger ", - "commit": "8511787b4e9da71ec2aa0194e693ca632cd31951" - } - ] - } - }, - { - "version": "0.5.68", - "tag": "react-native-win_v0.5.68", - "date": "Wed, 20 Feb 2019 23:15:50 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - implement unsetting for most properties that were missing it", - "author": "Andy Himberger ", - "commit": "17be3c9ac4f6e6e0a1222427998aecaceeec6118" - } - ] - } - }, - { - "version": "0.5.67", - "tag": "react-native-win_v0.5.67", - "date": "Wed, 20 Feb 2019 18:10:08 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.2.8` to `0.3.0`" - } - ] - } - }, - { - "version": "0.5.66", - "tag": "react-native-win_v0.5.66", - "date": "Tue, 19 Feb 2019 20:49:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.2.7` to `0.2.8`" - } - ] - } - }, - { - "version": "0.5.65", - "tag": "react-native-win_v0.5.65", - "date": "Tue, 19 Feb 2019 13:29:59 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.2.6` to `0.2.7`" - } - ] - } - }, - { - "version": "0.5.64", - "tag": "react-native-win_v0.5.64", - "date": "Tue, 19 Feb 2019 09:40:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.2.5` to `0.2.6`" - } - ] - } - }, - { - "version": "0.5.63", - "tag": "react-native-win_v0.5.63", - "date": "Tue, 19 Feb 2019 08:29:15 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.2.4` to `0.2.5`" - } - ] - } - }, - { - "version": "0.5.62", - "tag": "react-native-win_v0.5.62", - "date": "Mon, 18 Feb 2019 03:12:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.2.3` to `0.2.4`" - } - ] - } - }, - { - "version": "0.5.61", - "tag": "react-native-win_v0.5.61", - "date": "Sat, 16 Feb 2019 20:22:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.2.2` to `0.2.3`" - } - ] - } - }, - { - "version": "0.5.60", - "tag": "react-native-win_v0.5.60", - "date": "Sat, 16 Feb 2019 19:08:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.2.1` to `0.2.2`" - } - ] - } - }, - { - "version": "0.5.59", - "tag": "react-native-win_v0.5.59", - "date": "Sat, 16 Feb 2019 00:19:15 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - fix devmain break from pch change", - "author": "Andy Himberger ", - "commit": "e8c191272d598783eab09a1f718e08b603efcc5c" - } - ] - } - }, - { - "version": "0.5.58", - "tag": "react-native-win_v0.5.58", - "date": "Fri, 15 Feb 2019 14:47:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.2.0` to `0.2.1`" - } - ] - } - }, - { - "version": "0.5.57", - "tag": "react-native-win_v0.5.57", - "date": "Fri, 15 Feb 2019 04:26:38 GMT", - "comments": { - "patch": [ - { - "comment": "Fix Live Reload", - "author": "Nikolai Aristov ", - "commit": "0bc917ad22f6fb6bb8857c9ccc38ff37fb56d72b" - } - ] - } - }, - { - "version": "0.5.56", - "tag": "react-native-win_v0.5.56", - "date": "Fri, 15 Feb 2019 01:52:14 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - implement AppState state change events, tooltip prop, rename asyncstorage folder to react-native", - "author": "Andy Himberger ", - "commit": "ae22a3ff41257d61c61da90f28ff78cd9210abed" - } - ] - } - }, - { - "version": "0.5.55", - "tag": "react-native-win_v0.5.55", - "date": "Thu, 14 Feb 2019 23:44:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.1.2` to `0.2.0`" - } - ] - } - }, - { - "version": "0.5.54", - "tag": "react-native-win_v0.5.54", - "date": "Thu, 14 Feb 2019 22:36:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.1.1` to `0.1.2`" - } - ] - } - }, - { - "version": "0.5.53", - "tag": "react-native-win_v0.5.53", - "date": "Thu, 14 Feb 2019 21:21:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.1.0` to `0.1.1`" - } - ] - } - }, - { - "version": "0.5.52", - "tag": "react-native-win_v0.5.52", - "date": "Thu, 14 Feb 2019 03:07:44 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - create ControlViewManager base class for Xaml IControl's to share", - "author": "Andy Himberger ", - "commit": "66819ee06b3d37612d855e94c575760ee9430e34" - } - ] - } - }, - { - "version": "0.5.51", - "tag": "react-native-win_v0.5.51", - "date": "Wed, 13 Feb 2019 23:20:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.0.12` to `0.1.0`" - } - ] - } - }, - { - "version": "0.5.50", - "tag": "react-native-win_v0.5.50", - "date": "Wed, 13 Feb 2019 20:29:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.0.11` to `0.0.12`" - } - ] - } - }, - { - "version": "0.5.49", - "tag": "react-native-win_v0.5.49", - "date": "Wed, 13 Feb 2019 01:52:33 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - add accessibilityHint support, initial accessibilityexample in RNTester", - "author": "Andy Himberger ", - "commit": "cfeb82cf75fcc5472dfd9c0928df2f61ba66c015" - }, - { - "comment": "uwp - fix mouse/touch input after live reload", - "author": "Andy Himberger ", - "commit": "25c6d86526a064a8c455e0a1a83811334bbd46e6" - } - ] - } - }, - { - "version": "0.5.48", - "tag": "react-native-win_v0.5.48", - "date": "Tue, 12 Feb 2019 19:53:26 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - update version checks for disabling compiler optimizations", - "author": "Andy Himberger ", - "commit": "58992f15061da1065ce345c4b17f6b2ee02dd8e3" - } - ] - } - }, - { - "version": "0.5.47", - "tag": "react-native-win_v0.5.47", - "date": "Tue, 12 Feb 2019 04:48:47 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.0.10` to `0.0.11`" - } - ] - } - }, - { - "version": "0.5.46", - "tag": "react-native-win_v0.5.46", - "date": "Tue, 12 Feb 2019 03:23:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.0.9` to `0.0.10`" - } - ] - } - }, - { - "version": "0.5.45", - "tag": "react-native-win_v0.5.45", - "date": "Tue, 12 Feb 2019 02:09:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.0.8` to `0.0.9`" - } - ] - } - }, - { - "version": "0.5.44", - "tag": "react-native-win_v0.5.44", - "date": "Mon, 11 Feb 2019 23:42:33 GMT", - "comments": { - "patch": [ - { - "comment": "Adding shadow nodes to text input ", - "author": "Ravi Teja Koganti ", - "commit": "d6d9c4a2e8ffe570f69fcabee6ba0227e0871df5" - } - ] - } - }, - { - "version": "0.5.43", - "tag": "react-native-win_v0.5.43", - "date": "Sat, 09 Feb 2019 08:08:20 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.0.7` to `0.0.8`" - } - ] - } - }, - { - "version": "0.5.42", - "tag": "react-native-win_v0.5.42", - "date": "Fri, 08 Feb 2019 18:49:59 GMT", - "comments": { - "patch": [ - { - "comment": "Add Popup interactions", - "author": "Ashita Khetan ", - "commit": "f25a25ea4d22ab080330e76b9ec60d9cf5d2413d" - } - ] - } - }, - { - "version": "0.5.41", - "tag": "react-native-win_v0.5.41", - "date": "Thu, 07 Feb 2019 20:51:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.0.6` to `0.0.7`" - } - ] - } - }, - { - "version": "0.5.40", - "tag": "react-native-win_v0.5.40", - "date": "Thu, 07 Feb 2019 15:45:23 GMT", - "comments": { - "patch": [ - { - "comment": "OACR fixes", - "author": "Andrew Coates (REDMOND) ", - "commit": "27e4dc618a130737817ba27361259f14a6cb4a13" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.0.5` to `0.0.6`" - } - ] - } - }, - { - "version": "0.5.39", - "tag": "react-native-win_v0.5.39", - "date": "Thu, 07 Feb 2019 01:27:00 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - fix Picker bug with selection getting lost on items change", - "author": "Andy Himberger ", - "commit": "0e0ef4bdf39ade01121759370b55d9c433a0f735" - } - ] - } - }, - { - "version": "0.5.38", - "tag": "react-native-win_v0.5.38", - "date": "Wed, 06 Feb 2019 22:26:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.0.4` to `0.0.5`" - } - ] - } - }, - { - "version": "0.5.37", - "tag": "react-native-win_v0.5.37", - "date": "Wed, 06 Feb 2019 02:28:07 GMT", - "comments": { - "patch": [ - { - "comment": "Support pnpm", - "author": "Andrew Coates (REDMOND) ", - "commit": "1170eff0e47fb3980b375f9d0380b7f78e9fe79d" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.0.3` to `0.0.4`" - } - ] - } - }, - { - "version": "0.5.36", - "tag": "react-native-win_v0.5.36", - "date": "Tue, 05 Feb 2019 22:12:35 GMT", - "comments": { - "patch": [ - { - "comment": "Export popup correctly", - "author": "Ashita Khetan ", - "commit": "b779b3184f5f7e71cae7e20d1153ccf11c9618e3" - } - ] - } - }, - { - "version": "0.5.35", - "tag": "react-native-win_v0.5.35", - "date": "Tue, 05 Feb 2019 06:23:14 GMT", - "comments": { - "patch": [ - { - "comment": "Minor readme update for opensource", - "author": "Andrew Coates (REDMOND) ", - "commit": "6b2c0b397b221fc551de65de57b9766ce4b41597" - }, - { - "comment": "Rename @offce-iss/react-native to @microsoft/react-native", - "author": "Andrew Coates (REDMOND) ", - "commit": "a7ea3733408eee4db88a1a1a7a7b0c6c89654c56" - }, - { - "comment": "uwp - RNTester", - "author": "Andy Himberger ", - "commit": "0462eb78a2195d92905e8088b9e9d039d538a44c" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/react-native\" from `0.0.2` to `0.0.3`" - } - ] - } - }, - { - "version": "0.5.33", - "tag": "react-native-win_v0.5.33", - "date": "Mon, 04 Feb 2019 23:50:17 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - add Logging, JsExceptionCallback to ReactInstanceSettings", - "author": "Andy Himberger ", - "commit": "ad0f0da4611c885d6f3526cf9161801276f88038" - } - ] - } - }, - { - "version": "0.5.32", - "tag": "react-native-win_v0.5.32", - "date": "Mon, 04 Feb 2019 21:42:11 GMT", - "comments": { - "patch": [ - { - "comment": "Add copyright comments at the top of react-native-win source files", - "author": "Andrew Coates (REDMOND) ", - "commit": "aa61ddaaff48d006169a72f59dc5047dd6c5bd2f" - } - ] - } - }, - { - "version": "0.5.31", - "tag": "react-native-win_v0.5.31", - "date": "Mon, 04 Feb 2019 13:08:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3013.18` to `0.3013.19`" - } - ] - } - }, - { - "version": "0.5.30", - "tag": "react-native-win_v0.5.30", - "date": "Sat, 02 Feb 2019 18:07:56 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - testID support, other cleanup", - "author": "Andy Himberger ", - "commit": "d93cf89d636ffce2172c0c3e5b0a9ec952a33ed7" - } - ] - } - }, - { - "version": "0.5.29", - "tag": "react-native-win_v0.5.29", - "date": "Sat, 02 Feb 2019 07:52:04 GMT", - "comments": { - "patch": [ - { - "comment": "Minor policheck fixes", - "author": "Andrew Coates (REDMOND) ", - "commit": "74aea87e02affdd44db10974599a608f3cd23c7a" - } - ] - } - }, - { - "version": "0.5.28", - "tag": "react-native-win_v0.5.28", - "date": "Fri, 01 Feb 2019 23:50:46 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - fix Switch to be correctly controlled", - "author": "Andy Himberger ", - "commit": "d4a997475d1279b1462cfbc8c1a75d9635323873" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3013.17` to `0.3013.18`" - } - ] - } - }, - { - "version": "0.5.27", - "tag": "react-native-win_v0.5.27", - "date": "Fri, 01 Feb 2019 21:37:51 GMT", - "comments": { - "patch": [ - { - "comment": "Make react-native-win not depend on sdx-platform build scripts", - "author": "Andrew Coates (REDMOND) ", - "commit": "4c5caea239369966bf4cb3377cd6d5101350cedf" - }, - { - "comment": "uwp - Add back pressed event firing from View temporarily", - "author": "Andy Himberger ", - "commit": "273ff605b8f821a7e30e4a1dbf7374747eeccead" - }, - { - "comment": "uwp - update SDK dependency to RS5, runtime target RS3+, permissive-", - "author": "Andy Himberger ", - "commit": "7416bb3b0e9d0123766bce3813487685c7ec7f33" - }, - { - "comment": "Add popup component for uwp", - "author": "Ashita Khetan ", - "commit": "c6aa56c1d5d12c824cff82d1180f8d4206638fe1" - }, - { - "comment": "autosync", - "author": "Tudor Mihai ", - "commit": "453ce286fa048f58afdc77107e427d360240b86e" - }, - { - "comment": "V8 Inspector", - "author": "Anandraj Govindan ", - "commit": "8b239114edbeafdc051243e2b2e28475448ec492" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3013.16` to `0.3013.17`" - } - ] - } - }, - { - "version": "0.5.25", - "tag": "react-native-win_v0.5.25", - "date": "Tue, 29 Jan 2019 05:41:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3013.14` to `0.3013.15`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.31` to `0.5.32`" - } - ] - } - }, - { - "version": "0.5.24", - "tag": "react-native-win_v0.5.24", - "date": "Tue, 29 Jan 2019 04:34:55 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - fix CheckBox, Picker eventing outside of sample", - "author": "Andy Himberger ", - "commit": "4bcbd7c163653e17c83a1812d07439fa9c7feb76" - } - ] - } - }, - { - "version": "0.5.23", - "tag": "react-native-win_v0.5.23", - "date": "Tue, 29 Jan 2019 03:24:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3013.13` to `0.3013.14`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.30` to `0.5.31`" - } - ] - } - }, - { - "version": "0.5.22", - "tag": "react-native-win_v0.5.22", - "date": "Tue, 29 Jan 2019 02:13:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.29` to `0.5.30`" - } - ] - } - }, - { - "version": "0.5.21", - "tag": "react-native-win_v0.5.21", - "date": "Tue, 29 Jan 2019 01:03:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.28` to `0.5.29`" - } - ] - } - }, - { - "version": "0.5.20", - "tag": "react-native-win_v0.5.20", - "date": "Mon, 28 Jan 2019 23:55:36 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - add Picker control", - "author": "Andy Himberger ", - "commit": "99ce60dfcfe19d08da15720d2901093ba28cfa67" - } - ] - } - }, - { - "version": "0.5.19", - "tag": "react-native-win_v0.5.19", - "date": "Sun, 27 Jan 2019 22:31:27 GMT", - "comments": { - "patch": [ - { - "comment": "V8Platform & V8Runtime improvements", - "author": "Anandraj Govindan ", - "commit": "70b9e3c85e8657d572f963df756505bbddbeb232" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3013.12` to `0.3013.13`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.27` to `0.5.28`" - } - ] - } - }, - { - "version": "0.5.18", - "tag": "react-native-win_v0.5.18", - "date": "Sat, 26 Jan 2019 00:40:56 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - add onMouseEnter/onMouseLeave events to View", - "author": "Andy Himberger ", - "commit": "a48d29e9cdb63937d16e5f97b9d2264a70c355e8" - } - ] - } - }, - { - "version": "0.5.17", - "tag": "react-native-win_v0.5.17", - "date": "Fri, 25 Jan 2019 22:25:12 GMT", - "comments": { - "patch": [ - { - "comment": "Switch build to use just-task", - "author": "Andrew Coates (REDMOND) ", - "commit": "d384d9c78b006220e9d945520e286971ecaff3ff" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.26` to `0.5.27`" - } - ] - } - }, - { - "version": "0.5.16", - "tag": "react-native-win_v0.5.16", - "date": "Fri, 25 Jan 2019 16:15:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.25` to `0.5.26`" - } - ] - } - }, - { - "version": "0.5.15", - "tag": "react-native-win_v0.5.15", - "date": "Thu, 24 Jan 2019 01:00:18 GMT", - "comments": { - "patch": [ - { - "comment": "Building JSI shared sources in devmain", - "author": "Anandraj Govindan ", - "commit": "7a7712ad4b29ffb6705c9dcacfaca3156526ab80" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3013.11` to `0.3013.12`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.24` to `0.5.25`" - } - ] - } - }, - { - "version": "0.5.14", - "tag": "react-native-win_v0.5.14", - "date": "Wed, 23 Jan 2019 23:16:49 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - export CheckBox via react-native-win in a typescript friendly way", - "author": "Andy Himberger ", - "commit": "4dd4081d98f8e399c77a3ab161592ce6a0ec8e1d" - } - ] - } - }, - { - "version": "0.5.13", - "tag": "react-native-win_v0.5.13", - "date": "Wed, 23 Jan 2019 21:29:40 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - add SourceCode, AsyncStorage native modules", - "author": "Andy Himberger ", - "commit": "afa57745999cbb260fc6992a8479f37d951b6588" - } - ] - } - }, - { - "version": "0.5.12", - "tag": "react-native-win_v0.5.12", - "date": "Wed, 23 Jan 2019 19:37:07 GMT", - "comments": { - "patch": [ - { - "comment": "Update typescript, @types/r+rn versions", - "author": "Andrew Coates (REDMOND) ", - "commit": "fded495cba82a20fa2dae31e025fc373b226eec0" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.23` to `0.5.24`" - } - ] - } - }, - { - "version": "0.5.11", - "tag": "react-native-win_v0.5.11", - "date": "Wed, 23 Jan 2019 02:13:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.22` to `0.5.23`" - } - ] - } - }, - { - "version": "0.5.10", - "tag": "react-native-win_v0.5.10", - "date": "Tue, 22 Jan 2019 23:21:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.21` to `0.5.22`" - } - ] - } - }, - { - "version": "0.5.9", - "tag": "react-native-win_v0.5.9", - "date": "Tue, 22 Jan 2019 20:57:59 GMT", - "comments": { - "patch": [ - { - "comment": "Allow Multiple Js Bundles", - "author": "Nikolai Aristov ", - "commit": "5c8473a3bf711a58c64e8529832276340ceb5244" - } - ] - } - }, - { - "version": "0.5.8", - "tag": "react-native-win_v0.5.8", - "date": "Tue, 22 Jan 2019 17:34:37 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - restore changes lost in 0.57 upgrade", - "author": "Andy Himberger ", - "commit": "ae8cc5144c1bcf7d1255cd58998ee49cfed5d502" - } - ] - } - }, - { - "version": "0.5.7", - "tag": "react-native-win_v0.5.7", - "date": "Mon, 21 Jan 2019 22:59:18 GMT", - "comments": { - "patch": [ - { - "comment": "Integrating JSI ChakraRuntime on Windows", - "author": "Anandraj Govindan ", - "commit": "7b08fda4dbe8209aeb13fe1b383d67ab3119ec09" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3013.10` to `0.3013.11`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.20` to `0.5.21`" - } - ] - } - }, - { - "version": "0.5.6", - "tag": "react-native-win_v0.5.6", - "date": "Fri, 18 Jan 2019 05:54:33 GMT", - "comments": { - "patch": [ - { - "comment": "Update to RN 0.57", - "author": "Andrew Coates (REDMOND) ", - "commit": "5e74531ee1a9274a20783c1799d989794130c8f0" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3013.9` to `0.3013.10`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.19` to `0.5.20`" - } - ] - } - }, - { - "version": "0.5.5", - "tag": "react-native-win_v0.5.5", - "date": "Thu, 17 Jan 2019 03:44:30 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.18` to `0.5.19`" - } - ] - } - }, - { - "version": "0.5.4", - "tag": "react-native-win_v0.5.4", - "date": "Thu, 17 Jan 2019 00:07:23 GMT", - "comments": { - "patch": [ - { - "comment": "Get uwp livereload working again", - "author": "Andrew Coates (REDMOND) ", - "commit": "bd311cf8958bc42d651c48f2d4fe546940b395c8" - } - ] - } - }, - { - "version": "0.5.3", - "tag": "react-native-win_v0.5.3", - "date": "Wed, 16 Jan 2019 23:13:26 GMT", - "comments": { - "patch": [ - { - "comment": "Implement View clipping for overflow value of 'hidden'.", - "author": "Randy Flynn ", - "commit": "9f29d8f843ade4b0761587878f0eba962591f33d" - } - ] - } - }, - { - "version": "0.5.2", - "tag": "react-native-win_v0.5.2", - "date": "Wed, 16 Jan 2019 19:59:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.17` to `0.5.18`" - } - ] - } - }, - { - "version": "0.5.1", - "tag": "react-native-win_v0.5.1", - "date": "Wed, 16 Jan 2019 06:51:10 GMT", - "comments": { - "patch": [ - { - "comment": "fix nuget package - add NativeModuleProvider.h", - "author": "Andy Himberger ", - "commit": "0c7585519d83b33153c5da78fb8905dcde7efd46" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3013.8` to `0.3013.9`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.16` to `0.5.17`" - } - ] - } - }, - { - "version": "0.5.0", - "tag": "react-native-win_v0.5.0", - "date": "Sat, 12 Jan 2019 00:52:10 GMT", - "comments": { - "minor": [ - { - "comment": "[UWP] Implement handling of most props on UWP's TextInput", - "author": "Ruriko Araki ", - "commit": "d2ff753ec34520a4dd0e47e5db9c84d6a2cf5f08" - } - ] - } - }, - { - "version": "0.4.4", - "tag": "react-native-win_v0.4.4", - "date": "Fri, 11 Jan 2019 19:30:59 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.15` to `0.5.16`" - } - ] - } - }, - { - "version": "0.4.3", - "tag": "react-native-win_v0.4.3", - "date": "Fri, 11 Jan 2019 17:43:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.14` to `0.5.15`" - } - ] - } - }, - { - "version": "0.4.2", - "tag": "react-native-win_v0.4.2", - "date": "Fri, 11 Jan 2019 10:09:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3013.7` to `0.3013.8`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.13` to `0.5.14`" - } - ] - } - }, - { - "version": "0.4.1", - "tag": "react-native-win_v0.4.1", - "date": "Thu, 10 Jan 2019 22:13:25 GMT", - "comments": { - "patch": [ - { - "comment": "Move windesktop files from react-native", - "author": "Andrew Coates (REDMOND) ", - "commit": "c8217449454ae72ee5463a506fc1e7f4af5a9528" - }, - { - "comment": "update vcx projects to more closely match devmain warning levels", - "author": "Andy Himberger ", - "commit": "c48a9bf44f5218be20d9490fe14a3e5e51cf562c" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3013.6` to `0.3013.7`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.12` to `0.5.13`" - } - ] - } - }, - { - "version": "0.4.0", - "tag": "react-native-win_v0.4.0", - "date": "Sat, 05 Jan 2019 06:28:36 GMT", - "comments": { - "minor": [ - { - "comment": "Implement focus(), blur(), and clear() on UWP TextInput", - "author": "Ruriko Araki ", - "commit": "7d1680cf077cb379381176bcc9a6f265e2590be5" - } - ] - } - }, - { - "version": "0.3.30", - "tag": "react-native-win_v0.3.30", - "date": "Fri, 04 Jan 2019 23:12:26 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - additional Socket error handling", - "author": "Andy Himberger ", - "commit": "aacd047eeaf8d1ffdeef728fcaa2be6bbd2d683b" - } - ] - } - }, - { - "version": "0.3.29", - "tag": "react-native-win_v0.3.29", - "date": "Fri, 04 Jan 2019 16:38:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3013.4` to `0.3013.5`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.10` to `0.5.11`" - } - ] - } - }, - { - "version": "0.3.28", - "tag": "react-native-win_v0.3.28", - "date": "Fri, 04 Jan 2019 11:02:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3013.3` to `0.3013.4`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.9` to `0.5.10`" - } - ] - } - }, - { - "version": "0.3.27", - "tag": "react-native-win_v0.3.27", - "date": "Fri, 04 Jan 2019 06:24:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3013.2` to `0.3013.3`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.8` to `0.5.9`" - } - ] - } - }, - { - "version": "0.3.26", - "tag": "react-native-win_v0.3.26", - "date": "Fri, 04 Jan 2019 03:55:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.7` to `0.5.8`" - } - ] - } - }, - { - "version": "0.3.25", - "tag": "react-native-win_v0.3.25", - "date": "Fri, 04 Jan 2019 01:59:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.6` to `0.5.7`" - } - ] - } - }, - { - "version": "0.3.24", - "tag": "react-native-win_v0.3.24", - "date": "Thu, 03 Jan 2019 01:32:30 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.5` to `0.5.6`" - } - ] - } - }, - { - "version": "0.3.23", - "tag": "react-native-win_v0.3.23", - "date": "Wed, 02 Jan 2019 20:44:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.4` to `0.5.5`" - } - ] - } - }, - { - "version": "0.3.22", - "tag": "react-native-win_v0.3.22", - "date": "Wed, 02 Jan 2019 08:29:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3013.1` to `0.3013.2`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.3` to `0.5.4`" - } - ] - } - }, - { - "version": "0.3.21", - "tag": "react-native-win_v0.3.21", - "date": "Fri, 21 Dec 2018 20:50:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.2` to `0.5.3`" - } - ] - } - }, - { - "version": "0.3.20", - "tag": "react-native-win_v0.3.20", - "date": "Thu, 20 Dec 2018 02:24:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "0.3.19", - "tag": "react-native-win_v0.3.19", - "date": "Thu, 20 Dec 2018 01:27:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "0.3.18", - "tag": "react-native-win_v0.3.18", - "date": "Wed, 19 Dec 2018 23:31:00 GMT", - "comments": { - "none": [ - { - "comment": "Restore filters to ReactCommon vcxproj.", - "author": "Yichen Yao ", - "commit": "c35eee10120eaa99f4dfba193bbd5be4b483cf62" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3013.0` to `0.3013.1`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.32` to `0.5.0`" - } - ] - } - }, - { - "version": "0.3.17", - "tag": "react-native-win_v0.3.17", - "date": "Wed, 19 Dec 2018 20:45:31 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - improved Touch handling", - "author": "Andy Himberger ", - "commit": "48abf2055cb3576a8c46b067a41f2138b012afbb" - } - ] - } - }, - { - "version": "0.3.16", - "tag": "react-native-win_v0.3.16", - "date": "Fri, 14 Dec 2018 21:06:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.31` to `0.4.32`" - } - ] - } - }, - { - "version": "0.3.15", - "tag": "react-native-win_v0.3.15", - "date": "Fri, 14 Dec 2018 02:55:08 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.30` to `0.4.31`" - } - ] - } - }, - { - "version": "0.3.14", - "tag": "react-native-win_v0.3.14", - "date": "Fri, 14 Dec 2018 00:59:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3012.7` to `0.3013.0`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.29` to `0.4.30`" - } - ] - } - }, - { - "version": "0.3.13", - "tag": "react-native-win_v0.3.13", - "date": "Thu, 13 Dec 2018 23:59:11 GMT", - "comments": { - "patch": [ - { - "comment": "Removing beast types from IWebSocket interface", - "author": "Khalef Hosany ", - "commit": "697aa2e227cad87009c93a3a9fa3927393db38a3" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3012.6` to `0.3012.7`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.28` to `0.4.29`" - } - ] - } - }, - { - "version": "0.3.12", - "tag": "react-native-win_v0.3.12", - "date": "Thu, 13 Dec 2018 22:15:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3012.5` to `0.3012.6`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.27` to `0.4.28`" - } - ] - } - }, - { - "version": "0.3.11", - "tag": "react-native-win_v0.3.11", - "date": "Thu, 13 Dec 2018 16:57:46 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - fix WebSocket.close", - "author": "Andy Himberger ", - "commit": "b87a151c205b2fbc4df15b8d394403897afba1de" - } - ] - } - }, - { - "version": "0.3.10", - "tag": "react-native-win_v0.3.10", - "date": "Thu, 13 Dec 2018 09:04:29 GMT", - "comments": { - "patch": [ - { - "comment": "Remove std::terminate from updateExceptionMessage", - "author": "Khalef Hosany ", - "commit": "cd7315b7c9981304abe78964d500f359c0d77dcb" - } - ] - } - }, - { - "version": "0.3.9", - "tag": "react-native-win_v0.3.9", - "date": "Thu, 13 Dec 2018 02:37:28 GMT", - "comments": { - "patch": [ - { - "comment": "uwp - devmain build fix", - "author": "Andy Himberger ", - "commit": "1ec8a02bb1e939e7ef0f259ccd9ed0652cac2e7b" - } - ] - } - }, - { - "version": "0.3.8", - "tag": "react-native-win_v0.3.8", - "date": "Wed, 12 Dec 2018 23:39:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3012.4` to `0.3012.5`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.26` to `0.4.27`" - } - ] - } - }, - { - "version": "0.3.7", - "tag": "react-native-win_v0.3.7", - "date": "Wed, 12 Dec 2018 21:17:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3012.3` to `0.3012.4`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.25` to `0.4.26`" - } - ] - } - }, - { - "version": "0.3.6", - "tag": "react-native-win_v0.3.6", - "date": "Wed, 12 Dec 2018 00:51:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.24` to `0.4.25`" - } - ] - } - }, - { - "version": "0.3.5", - "tag": "react-native-win_v0.3.5", - "date": "Tue, 11 Dec 2018 22:59:34 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3012.2` to `0.3012.3`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.23` to `0.4.24`" - } - ] - } - }, - { - "version": "0.3.4", - "tag": "react-native-win_v0.3.4", - "date": "Tue, 11 Dec 2018 19:48:20 GMT", - "comments": { - "patch": [ - { - "comment": "uwp: fix unset of color style props, LinkingManager improvements", - "author": "Andy Himberger ", - "commit": "d7089c86b0ec15ef724610714bd8c1c34ccdfaff" - } - ] - } - }, - { - "version": "0.3.3", - "tag": "react-native-win_v0.3.3", - "date": "Mon, 10 Dec 2018 21:52:13 GMT", - "comments": { - "patch": [ - { - "comment": "mirror changes made to devmain", - "author": "Adam Foxman ", - "commit": "9b2fcbef90631d3e3702904f3f12652cebdbe26c" - } - ] - } - }, - { - "version": "0.3.2", - "tag": "react-native-win_v0.3.2", - "date": "Mon, 10 Dec 2018 12:32:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3012.1` to `0.3012.2`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.22` to `0.4.23`" - } - ] - } - }, - { - "version": "0.3.1", - "tag": "react-native-win_v0.3.1", - "date": "Fri, 07 Dec 2018 01:44:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3012.0` to `0.3012.1`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.21` to `0.4.22`" - } - ] - } - }, - { - "version": "0.3.0", - "tag": "react-native-win_v0.3.0", - "date": "Thu, 06 Dec 2018 20:08:03 GMT", - "comments": { - "minor": [ - { - "comment": "JSI Runtime implementation for Chakra", - "author": "Anandraj Govindan ", - "commit": "87d89c20852c1ca6948ca8ef41ebbaddd6c52dd2" - }, - { - "comment": "JSI Runtime implementation for V8", - "author": "Anandraj Govindan ", - "commit": "d4e71dd22ef933539b28592692e7eabae559d733" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3011.4` to `0.3012.0`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.20` to `0.4.21`" - } - ] - } - }, - { - "version": "0.2.5", - "tag": "react-native-win_v0.2.5", - "date": "Thu, 06 Dec 2018 18:33:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3011.3` to `0.3011.4`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.19` to `0.4.20`" - } - ] - } - }, - { - "version": "0.2.4", - "tag": "react-native-win_v0.2.4", - "date": "Thu, 06 Dec 2018 02:54:35 GMT", - "comments": { - "patch": [ - { - "comment": "uwp: send onLayout events", - "author": "Andy Himberger ", - "commit": "4eea40120b1182a05b6bee1d2ad730469af3c93f" - } - ] - } - }, - { - "version": "0.2.3", - "tag": "react-native-win_v0.2.3", - "date": "Wed, 05 Dec 2018 22:13:30 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3011.2` to `0.3011.3`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.18` to `0.4.19`" - } - ] - } - }, - { - "version": "0.2.2", - "tag": "react-native-win_v0.2.2", - "date": "Wed, 05 Dec 2018 19:09:20 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3011.1` to `0.3011.2`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.17` to `0.4.18`" - } - ] - } - }, - { - "version": "0.2.1", - "tag": "react-native-win_v0.2.1", - "date": "Wed, 05 Dec 2018 02:02:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3011.0` to `0.3011.1`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.16` to `0.4.17`" - } - ] - } - }, - { - "version": "0.2.0", - "tag": "react-native-win_v0.2.0", - "date": "Wed, 05 Dec 2018 00:48:46 GMT", - "comments": { - "minor": [ - { - "comment": "Bringing the JSI sources from Github", - "author": "Anandraj Govindan ", - "commit": "2129257c8273364ceb0fa8dc85c36447620a9928" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3010.24` to `0.3011.0`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.15` to `0.4.16`" - } - ] - } - }, - { - "version": "0.1.13", - "tag": "react-native-win_v0.1.13", - "date": "Tue, 04 Dec 2018 01:31:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3010.23` to `0.3010.24`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.14` to `0.4.15`" - } - ] - } - }, - { - "version": "0.1.12", - "tag": "react-native-win_v0.1.12", - "date": "Mon, 03 Dec 2018 23:22:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.13` to `0.4.14`" - } - ] - } - }, - { - "version": "0.1.11", - "tag": "react-native-win_v0.1.11", - "date": "Mon, 03 Dec 2018 20:04:57 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3010.22` to `0.3010.23`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.12` to `0.4.13`" - } - ] - } - }, - { - "version": "0.1.10", - "tag": "react-native-win_v0.1.10", - "date": "Sat, 01 Dec 2018 22:51:42 GMT", - "comments": { - "patch": [ - { - "comment": "uwp Clipboard NativeModule", - "author": "Andy Himberger ", - "commit": "744d9dfc8e898ebfe94547b6de9bce1738fd8061" - } - ] - } - }, - { - "version": "0.1.9", - "tag": "react-native-win_v0.1.9", - "date": "Fri, 30 Nov 2018 20:39:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.11` to `0.4.12`" - } - ] - } - }, - { - "version": "0.1.8", - "tag": "react-native-win_v0.1.8", - "date": "Thu, 29 Nov 2018 13:46:58 GMT", - "comments": { - "patch": [ - { - "comment": "Auto sync from tenantreactnativewin", - "author": "Xuan Mo ", - "commit": "72869fdc61ba395506f7081525c21e9203ad5284" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3010.21` to `0.3010.22`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.10` to `0.4.11`" - } - ] - } - }, - { - "version": "0.1.7", - "tag": "react-native-win_v0.1.7", - "date": "Thu, 29 Nov 2018 11:45:37 GMT", - "comments": { - "patch": [ - { - "comment": "Move windesktop files from react-native", - "author": "Andrew Coates (REDMOND) ", - "commit": "9b9e29a23096a121fcfd735f450f558cbc61173f" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3010.20` to `0.3010.21`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.9` to `0.4.10`" - } - ] - } - }, - { - "version": "0.1.6", - "tag": "react-native-win_v0.1.6", - "date": "Sat, 17 Nov 2018 00:23:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.8` to `0.4.9`" - } - ] - } - }, - { - "version": "0.1.5", - "tag": "react-native-win_v0.1.5", - "date": "Thu, 15 Nov 2018 22:37:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.7` to `0.4.8`" - } - ] - } - }, - { - "version": "0.1.4", - "tag": "react-native-win_v0.1.4", - "date": "Thu, 15 Nov 2018 20:12:15 GMT", - "comments": { - "patch": [ - { - "comment": "Applying feedback from github PR", - "author": "Andrew Coates (REDMOND) ", - "commit": "ae3414a882e9663de5542f78ebf17288d2b1b9c0" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3010.19` to `0.3010.20`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.6` to `0.4.7`" - } - ] - } - }, - { - "version": "0.1.3", - "tag": "react-native-win_v0.1.3", - "date": "Thu, 15 Nov 2018 02:47:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.5` to `0.4.6`" - } - ] - } - }, - { - "version": "0.1.2", - "tag": "react-native-win_v0.1.2", - "date": "Wed, 14 Nov 2018 00:03:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.4` to `0.4.5`" - } - ] - } - }, - { - "version": "0.1.1", - "tag": "react-native-win_v0.1.1", - "date": "Tue, 13 Nov 2018 23:04:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.3` to `0.4.4`" - } - ] - } - }, - { - "version": "0.1.0", - "tag": "react-native-win_v0.1.0", - "date": "Tue, 13 Nov 2018 22:05:29 GMT", - "comments": { - "minor": [ - { - "comment": "Auto-sync CL 18022008 from tenantreactnativewin to ISS sdx-platform", - "author": "Xuan Mo ", - "commit": "752b0b96fe50da8b96fc2a10485b6297824e4254" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3010.18` to `0.3010.19`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.2` to `0.4.3`" - } - ] - } - }, - { - "version": "0.0.25", - "tag": "react-native-win_v0.0.25", - "date": "Tue, 13 Nov 2018 20:51:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "0.0.24", - "tag": "react-native-win_v0.0.24", - "date": "Tue, 13 Nov 2018 19:52:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.4.0` to `0.4.1`" - } - ] - } - }, - { - "version": "0.0.23", - "tag": "react-native-win_v0.0.23", - "date": "Sat, 10 Nov 2018 03:32:39 GMT", - "comments": { - "patch": [ - { - "comment": "Adding ExceptionManager for windows platforms", - "author": "Khalef Hosany ", - "commit": "0667a701ea16f8cc7f5642ea196b8836ded0e061" - } - ] - } - }, - { - "version": "0.0.22", - "tag": "react-native-win_v0.0.22", - "date": "Sat, 10 Nov 2018 00:21:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.3.21` to `0.4.0`" - } - ] - } - }, - { - "version": "0.0.21", - "tag": "react-native-win_v0.0.21", - "date": "Fri, 09 Nov 2018 22:37:07 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.3.20` to `0.3.21`" - } - ] - } - }, - { - "version": "0.0.20", - "tag": "react-native-win_v0.0.20", - "date": "Thu, 08 Nov 2018 01:57:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3010.17` to `0.3010.18`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.3.19` to `0.3.20`" - } - ] - } - }, - { - "version": "0.0.19", - "tag": "react-native-win_v0.0.19", - "date": "Wed, 07 Nov 2018 22:27:17 GMT", - "comments": { - "patch": [ - { - "comment": "uwp: add textDecorationLine support", - "author": "Andy Himberger ", - "commit": "008921ec9b5d69fb87a7282b917e41fd8211e4e0" - } - ] - } - }, - { - "version": "0.0.18", - "tag": "react-native-win_v0.0.18", - "date": "Wed, 07 Nov 2018 20:32:53 GMT", - "comments": { - "patch": [ - { - "comment": "Stop compiling JSC in any flavor for win32", - "author": "Andrew Coates (REDMOND) ", - "commit": "a81e969835eb42e89025c99be20434d7dc11e92f" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3010.16` to `0.3010.17`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.3.18` to `0.3.19`" - } - ] - } - }, - { - "version": "0.0.17", - "tag": "react-native-win_v0.0.17", - "date": "Wed, 07 Nov 2018 00:51:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3010.15` to `0.3010.16`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.3.17` to `0.3.18`" - } - ] - } - }, - { - "version": "0.0.16", - "tag": "react-native-win_v0.0.16", - "date": "Tue, 06 Nov 2018 18:21:48 GMT", - "comments": { - "patch": [ - { - "comment": "Move CxxMessageQueue to react-native-win", - "author": "Andrew Coates (REDMOND) ", - "commit": "10bca1384c6f92127da932d7811f8162176f2d60" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3010.14` to `0.3010.15`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.3.16` to `0.3.17`" - } - ] - } - }, - { - "version": "0.0.15", - "tag": "react-native-win_v0.0.15", - "date": "Tue, 06 Nov 2018 16:27:53 GMT", - "comments": { - "patch": [ - { - "comment": "uwp: networking, border radius, position, layout property fixes", - "author": "Andy Himberger ", - "commit": "ddfb217e6114d3fc6ad17b007557588dca901f1f" - } - ] - } - }, - { - "version": "0.0.14", - "tag": "react-native-win_v0.0.14", - "date": "Tue, 06 Nov 2018 03:11:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.3.15` to `0.3.16`" - } - ] - } - }, - { - "version": "0.0.13", - "tag": "react-native-win_v0.0.13", - "date": "Tue, 06 Nov 2018 01:01:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3010.13` to `0.3010.14`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.3.14` to `0.3.15`" - } - ] - } - }, - { - "version": "0.0.12", - "tag": "react-native-win_v0.0.12", - "date": "Sat, 03 Nov 2018 00:50:05 GMT", - "comments": { - "patch": [ - { - "comment": "Move windesktop modules from react-native", - "author": "REDMOND\\acoates ", - "commit": "a249bc68c94a38a9185502ed6f8406ba80252aa9" - } - ] - } - }, - { - "version": "0.0.11", - "tag": "react-native-win_v0.0.11", - "date": "Fri, 02 Nov 2018 22:11:47 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.3.13` to `0.3.14`" - } - ] - } - }, - { - "version": "0.0.10", - "tag": "react-native-win_v0.0.10", - "date": "Fri, 02 Nov 2018 21:15:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.3.12` to `0.3.13`" - } - ] - } - }, - { - "version": "0.0.9", - "tag": "react-native-win_v0.0.9", - "date": "Fri, 02 Nov 2018 20:18:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.3.11` to `0.3.12`" - } - ] - } - }, - { - "version": "0.0.8", - "tag": "react-native-win_v0.0.8", - "date": "Fri, 02 Nov 2018 18:27:14 GMT", - "comments": { - "patch": [ - { - "comment": "Move more modules from react-native", - "author": "Andrew Coates (REDMOND) ", - "commit": "c5ee6f6ba585e8f8fc669c1265b330d6c60f53f2" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.3.10` to `0.3.11`" - } - ] - } - }, - { - "version": "0.0.7", - "tag": "react-native-win_v0.0.7", - "date": "Fri, 02 Nov 2018 11:55:51 GMT", - "comments": { - "patch": [ - { - "comment": "ChakraCore process command queue", - "author": "Adam Krantz ", - "commit": "9ae911fa84545ec12d0d0b9b3004c680f40072e8" - } - ] - } - }, - { - "version": "0.0.6", - "tag": "react-native-win_v0.0.6", - "date": "Fri, 02 Nov 2018 02:33:39 GMT", - "comments": { - "patch": [ - { - "comment": "uwp: rename Icon prop foregroundColor to color", - "author": "Andy Himberger ", - "commit": "1749fc48c82be5f4b2987facbf2897c475881e19" - } - ] - } - }, - { - "version": "0.0.5", - "tag": "react-native-win_v0.0.5", - "date": "Thu, 01 Nov 2018 22:30:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3010.9` to `0.3010.10`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.3.9` to `0.3.10`" - } - ] - } - }, - { - "version": "0.0.4", - "tag": "react-native-win_v0.0.4", - "date": "Thu, 01 Nov 2018 17:44:48 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3010.8` to `0.3010.9`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.3.8` to `0.3.9`" - } - ] - } - }, - { - "version": "0.0.3", - "tag": "react-native-win_v0.0.3", - "date": "Thu, 01 Nov 2018 14:41:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3010.7` to `0.3010.8`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.3.7` to `0.3.8`" - } - ] - } - }, - { - "version": "0.0.2", - "tag": "react-native-win_v0.0.2", - "date": "Thu, 01 Nov 2018 01:51:23 GMT", - "comments": { - "patch": [ - { - "comment": "Start moving JS files for UWP into react-native-win", - "author": "Andrew Coates (REDMOND) ", - "commit": "cf81b8ed520fa725b3e7ba5ccc5a101fea071fd5" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@office-iss/react-native\" from `0.3010.6` to `0.3010.7`" - }, - { - "comment": "Updating dependency \"@office-iss/sdx-build-tools\" from `0.3.6` to `0.3.7`" - } - ] - } - } - ] -} diff --git a/vnext/CHANGELOG.md b/vnext/CHANGELOG.md deleted file mode 100644 index 78c07a0ea77..00000000000 --- a/vnext/CHANGELOG.md +++ /dev/null @@ -1,1074 +0,0 @@ -# Change Log - react-native-win - -This log was last generated on Wed, 13 Mar 2019 07:16:37 GMT and should not be manually modified. - -## 0.6.4 -Wed, 13 Mar 2019 07:16:37 GMT - -### Patches - -- Update react-native to 0.57.0-microsoft.4 - -## 0.6.3 -Tue, 12 Mar 2019 20:22:42 GMT - -### Patches - -- uwp - expose more helpers & cleanup for customViewmanagers support - -## 0.6.2 -Tue, 12 Mar 2019 02:41:20 GMT - -### Patches - -- Update react-native to 0.57.0-microsoft.2 - -## 0.6.1 -Sat, 09 Mar 2019 21:28:30 GMT - -### Patches - -- fix nuget packaging - -## 0.6.0 -Sat, 09 Mar 2019 18:32:03 GMT - -### Minor changes - -- added back SourceCodeModule - -## 0.5.93 -Fri, 08 Mar 2019 09:15:31 GMT - -### Patches - -- Update to react-native@0.57.0-microsoft.1 - -## 0.5.92 -Fri, 08 Mar 2019 00:33:25 GMT - -*Version update only* - -## 0.5.91 -Thu, 07 Mar 2019 23:21:01 GMT - -*Version update only* - -## 0.5.90 -Thu, 07 Mar 2019 22:02:00 GMT - -*Version update only* - -## 0.5.89 -Thu, 07 Mar 2019 20:47:48 GMT - -### Patches - -- uwp - add tabIndex support - -## 0.5.88 -Thu, 07 Mar 2019 01:08:42 GMT - -### Patches - -- devmain build fix -- rename start.js to cli.js, take args to enable bundle in addition to start - -## 0.5.87 -Wed, 06 Mar 2019 06:56:23 GMT - -### Patches - -- uwp - add support for custom ViewManagers - -## 0.5.86 -Wed, 06 Mar 2019 05:43:46 GMT - -### Patches - -- Rename microsoft react-native - -## 0.5.85 -Tue, 05 Mar 2019 20:54:55 GMT - -*Version update only* - -## 0.5.84 -Tue, 05 Mar 2019 07:11:26 GMT - -*Version update only* - -## 0.5.83 -Tue, 05 Mar 2019 05:02:15 GMT - -### Patches - -- uwp - keep instance alive longer in live reload/shutdown - -## 0.5.82 -Tue, 05 Mar 2019 02:31:33 GMT - -### Patches - -- Fix color properties of CalendarView plus enable null values for all properties but callbacks (resetting to defaults via ClearValue) -- uwp - add editable support to PickerUWP, fix DatePicker export -- Introduce CalendarView for UWP only (no Android, no JS, no Apple updates) -- Fix OnDateChanged event for DatePicker -- Popup positioning -- Fire onClick for View on SPACE or ENTER. -- JSICore (react-free) libraries -- Stop writing to console in logMarker - -## 0.5.80 -Thu, 28 Feb 2019 04:47:08 GMT - -### Patches - -- Turn off OnContent/OffContent for Switch view. - -## 0.5.79 -Thu, 28 Feb 2019 03:36:47 GMT - -### Patches - -- uwp - fix WebSocketModuleUwp build against non-final RS5 SDK -- uwp - fix ViewPanel leak - -## 0.5.78 -Wed, 27 Feb 2019 20:16:40 GMT - -### Patches - -- Implement acceptsKeyboardFocus on View. - -## 0.5.77 -Tue, 26 Feb 2019 20:40:42 GMT - -*Version update only* - -## 0.5.76 -Tue, 26 Feb 2019 08:18:38 GMT - -### Patches - -- uwp - avoid exceptions being thrown in WebSocketModule connect -- Add DatePicker uwp component -- Merge with master and resolve review comments for datepicker - -## 0.5.75 -Tue, 26 Feb 2019 05:55:00 GMT - -*Version update only* - -## 0.5.74 -Tue, 26 Feb 2019 03:39:43 GMT - -### Patches - -- fix move case in UIManager::manageChildren -- TextInput onScroll onKeyPress - -## 0.5.73 -Sat, 23 Feb 2019 22:42:46 GMT - -*Version update only* - -## 0.5.72 -Sat, 23 Feb 2019 01:53:38 GMT - -*Version update only* - -## 0.5.71 -Sat, 23 Feb 2019 00:46:26 GMT - -### Patches - -- Pinned 'just-task' to "0.7.6" so that we stop picking up the latest version - -## 0.5.70 -Thu, 21 Feb 2019 13:47:23 GMT - -*Version update only* - -## 0.5.69 -Thu, 21 Feb 2019 12:43:12 GMT - -### Patches - -- move react to peerDependencies - -## 0.5.68 -Wed, 20 Feb 2019 23:15:50 GMT - -### Patches - -- uwp - implement unsetting for most properties that were missing it - -## 0.5.67 -Wed, 20 Feb 2019 18:10:08 GMT - -*Version update only* - -## 0.5.66 -Tue, 19 Feb 2019 20:49:32 GMT - -*Version update only* - -## 0.5.65 -Tue, 19 Feb 2019 13:29:59 GMT - -*Version update only* - -## 0.5.64 -Tue, 19 Feb 2019 09:40:39 GMT - -*Version update only* - -## 0.5.63 -Tue, 19 Feb 2019 08:29:15 GMT - -*Version update only* - -## 0.5.62 -Mon, 18 Feb 2019 03:12:33 GMT - -*Version update only* - -## 0.5.61 -Sat, 16 Feb 2019 20:22:10 GMT - -*Version update only* - -## 0.5.60 -Sat, 16 Feb 2019 19:08:58 GMT - -*Version update only* - -## 0.5.59 -Sat, 16 Feb 2019 00:19:15 GMT - -### Patches - -- uwp - fix devmain break from pch change - -## 0.5.58 -Fri, 15 Feb 2019 14:47:27 GMT - -*Version update only* - -## 0.5.57 -Fri, 15 Feb 2019 04:26:38 GMT - -### Patches - -- Fix Live Reload - -## 0.5.56 -Fri, 15 Feb 2019 01:52:14 GMT - -### Patches - -- uwp - implement AppState state change events, tooltip prop, rename asyncstorage folder to react-native - -## 0.5.55 -Thu, 14 Feb 2019 23:44:36 GMT - -*Version update only* - -## 0.5.54 -Thu, 14 Feb 2019 22:36:25 GMT - -*Version update only* - -## 0.5.53 -Thu, 14 Feb 2019 21:21:36 GMT - -*Version update only* - -## 0.5.52 -Thu, 14 Feb 2019 03:07:44 GMT - -### Patches - -- uwp - create ControlViewManager base class for Xaml IControl's to share - -## 0.5.51 -Wed, 13 Feb 2019 23:20:09 GMT - -*Version update only* - -## 0.5.50 -Wed, 13 Feb 2019 20:29:56 GMT - -*Version update only* - -## 0.5.49 -Wed, 13 Feb 2019 01:52:33 GMT - -### Patches - -- uwp - add accessibilityHint support, initial accessibilityexample in RNTester -- uwp - fix mouse/touch input after live reload - -## 0.5.48 -Tue, 12 Feb 2019 19:53:26 GMT - -### Patches - -- uwp - update version checks for disabling compiler optimizations - -## 0.5.47 -Tue, 12 Feb 2019 04:48:47 GMT - -*Version update only* - -## 0.5.46 -Tue, 12 Feb 2019 03:23:22 GMT - -*Version update only* - -## 0.5.45 -Tue, 12 Feb 2019 02:09:18 GMT - -*Version update only* - -## 0.5.44 -Mon, 11 Feb 2019 23:42:33 GMT - -### Patches - -- Adding shadow nodes to text input - -## 0.5.43 -Sat, 09 Feb 2019 08:08:20 GMT - -*Version update only* - -## 0.5.42 -Fri, 08 Feb 2019 18:49:59 GMT - -### Patches - -- Add Popup interactions - -## 0.5.41 -Thu, 07 Feb 2019 20:51:50 GMT - -*Version update only* - -## 0.5.40 -Thu, 07 Feb 2019 15:45:23 GMT - -### Patches - -- OACR fixes - -## 0.5.39 -Thu, 07 Feb 2019 01:27:00 GMT - -### Patches - -- uwp - fix Picker bug with selection getting lost on items change - -## 0.5.38 -Wed, 06 Feb 2019 22:26:22 GMT - -*Version update only* - -## 0.5.37 -Wed, 06 Feb 2019 02:28:07 GMT - -### Patches - -- Support pnpm - -## 0.5.36 -Tue, 05 Feb 2019 22:12:35 GMT - -### Patches - -- Export popup correctly - -## 0.5.35 -Tue, 05 Feb 2019 06:23:14 GMT - -### Patches - -- Minor readme update for opensource -- Rename @offce-iss/react-native to @microsoft/react-native -- uwp - RNTester - -## 0.5.33 -Mon, 04 Feb 2019 23:50:17 GMT - -### Patches - -- uwp - add Logging, JsExceptionCallback to ReactInstanceSettings - -## 0.5.32 -Mon, 04 Feb 2019 21:42:11 GMT - -### Patches - -- Add copyright comments at the top of react-native-win source files - -## 0.5.31 -Mon, 04 Feb 2019 13:08:38 GMT - -*Version update only* - -## 0.5.30 -Sat, 02 Feb 2019 18:07:56 GMT - -### Patches - -- uwp - testID support, other cleanup - -## 0.5.29 -Sat, 02 Feb 2019 07:52:04 GMT - -### Patches - -- Minor policheck fixes - -## 0.5.28 -Fri, 01 Feb 2019 23:50:46 GMT - -### Patches - -- uwp - fix Switch to be correctly controlled - -## 0.5.27 -Fri, 01 Feb 2019 21:37:51 GMT - -### Patches - -- Make react-native-win not depend on sdx-platform build scripts -- uwp - Add back pressed event firing from View temporarily -- uwp - update SDK dependency to RS5, runtime target RS2+, permissive- -- Add popup component for uwp -- autosync -- V8 Inspector - -## 0.5.25 -Tue, 29 Jan 2019 05:41:37 GMT - -*Version update only* - -## 0.5.24 -Tue, 29 Jan 2019 04:34:55 GMT - -### Patches - -- uwp - fix CheckBox, Picker eventing outside of sample - -## 0.5.23 -Tue, 29 Jan 2019 03:24:42 GMT - -*Version update only* - -## 0.5.22 -Tue, 29 Jan 2019 02:13:27 GMT - -*Version update only* - -## 0.5.21 -Tue, 29 Jan 2019 01:03:23 GMT - -*Version update only* - -## 0.5.20 -Mon, 28 Jan 2019 23:55:36 GMT - -### Patches - -- uwp - add Picker control - -## 0.5.19 -Sun, 27 Jan 2019 22:31:27 GMT - -### Patches - -- V8Platform & V8Runtime improvements - -## 0.5.18 -Sat, 26 Jan 2019 00:40:56 GMT - -### Patches - -- uwp - add onMouseEnter/onMouseLeave events to View - -## 0.5.17 -Fri, 25 Jan 2019 22:25:12 GMT - -### Patches - -- Switch build to use just-task - -## 0.5.16 -Fri, 25 Jan 2019 16:15:56 GMT - -*Version update only* - -## 0.5.15 -Thu, 24 Jan 2019 01:00:18 GMT - -### Patches - -- Building JSI shared sources in devmain - -## 0.5.14 -Wed, 23 Jan 2019 23:16:49 GMT - -### Patches - -- uwp - export CheckBox via react-native-win in a typescript friendly way - -## 0.5.13 -Wed, 23 Jan 2019 21:29:40 GMT - -### Patches - -- uwp - add SourceCode, AsyncStorage native modules - -## 0.5.12 -Wed, 23 Jan 2019 19:37:07 GMT - -### Patches - -- Update typescript, @types/r+rn versions - -## 0.5.11 -Wed, 23 Jan 2019 02:13:09 GMT - -*Version update only* - -## 0.5.10 -Tue, 22 Jan 2019 23:21:50 GMT - -*Version update only* - -## 0.5.9 -Tue, 22 Jan 2019 20:57:59 GMT - -### Patches - -- Allow Multiple Js Bundles - -## 0.5.8 -Tue, 22 Jan 2019 17:34:37 GMT - -### Patches - -- uwp - restore changes lost in 0.57 upgrade - -## 0.5.7 -Mon, 21 Jan 2019 22:59:18 GMT - -### Patches - -- Integrating JSI ChakraRuntime on Windows - -## 0.5.6 -Fri, 18 Jan 2019 05:54:33 GMT - -### Patches - -- Update to RN 0.57 - -## 0.5.5 -Thu, 17 Jan 2019 03:44:30 GMT - -*Version update only* - -## 0.5.4 -Thu, 17 Jan 2019 00:07:23 GMT - -### Patches - -- Get uwp livereload working again - -## 0.5.3 -Wed, 16 Jan 2019 23:13:26 GMT - -### Patches - -- Implement View clipping for overflow value of 'hidden'. - -## 0.5.2 -Wed, 16 Jan 2019 19:59:46 GMT - -*Version update only* - -## 0.5.1 -Wed, 16 Jan 2019 06:51:10 GMT - -### Patches - -- fix nuget package - add NativeModuleProvider.h - -## 0.5.0 -Sat, 12 Jan 2019 00:52:10 GMT - -### Minor changes - -- [UWP] Implement handling of most props on UWP's TextInput - -## 0.4.4 -Fri, 11 Jan 2019 19:30:59 GMT - -*Version update only* - -## 0.4.3 -Fri, 11 Jan 2019 17:43:09 GMT - -*Version update only* - -## 0.4.2 -Fri, 11 Jan 2019 10:09:36 GMT - -*Version update only* - -## 0.4.1 -Thu, 10 Jan 2019 22:13:25 GMT - -### Patches - -- Move windesktop files from react-native -- update vcx projects to more closely match devmain warning levels - -## 0.4.0 -Sat, 05 Jan 2019 06:28:36 GMT - -### Minor changes - -- Implement focus(), blur(), and clear() on UWP TextInput - -## 0.3.30 -Fri, 04 Jan 2019 23:12:26 GMT - -### Patches - -- uwp - additional Socket error handling - -## 0.3.29 -Fri, 04 Jan 2019 16:38:35 GMT - -*Version update only* - -## 0.3.28 -Fri, 04 Jan 2019 11:02:12 GMT - -*Version update only* - -## 0.3.27 -Fri, 04 Jan 2019 06:24:23 GMT - -*Version update only* - -## 0.3.26 -Fri, 04 Jan 2019 03:55:44 GMT - -*Version update only* - -## 0.3.25 -Fri, 04 Jan 2019 01:59:16 GMT - -*Version update only* - -## 0.3.24 -Thu, 03 Jan 2019 01:32:30 GMT - -*Version update only* - -## 0.3.23 -Wed, 02 Jan 2019 20:44:26 GMT - -*Version update only* - -## 0.3.22 -Wed, 02 Jan 2019 08:29:29 GMT - -*Version update only* - -## 0.3.21 -Fri, 21 Dec 2018 20:50:13 GMT - -*Version update only* - -## 0.3.20 -Thu, 20 Dec 2018 02:24:26 GMT - -*Version update only* - -## 0.3.19 -Thu, 20 Dec 2018 01:27:17 GMT - -*Version update only* - -## 0.3.18 -Wed, 19 Dec 2018 23:31:00 GMT - -*Version update only* - -## 0.3.17 -Wed, 19 Dec 2018 20:45:31 GMT - -### Patches - -- uwp - improved Touch handling - -## 0.3.16 -Fri, 14 Dec 2018 21:06:28 GMT - -*Version update only* - -## 0.3.15 -Fri, 14 Dec 2018 02:55:08 GMT - -*Version update only* - -## 0.3.14 -Fri, 14 Dec 2018 00:59:11 GMT - -*Version update only* - -## 0.3.13 -Thu, 13 Dec 2018 23:59:11 GMT - -### Patches - -- Removing beast types from IWebSocket interface - -## 0.3.12 -Thu, 13 Dec 2018 22:15:51 GMT - -*Version update only* - -## 0.3.11 -Thu, 13 Dec 2018 16:57:46 GMT - -### Patches - -- uwp - fix WebSocket.close - -## 0.3.10 -Thu, 13 Dec 2018 09:04:29 GMT - -### Patches - -- Remove std::terminate from updateExceptionMessage - -## 0.3.9 -Thu, 13 Dec 2018 02:37:28 GMT - -### Patches - -- uwp - devmain build fix - -## 0.3.8 -Wed, 12 Dec 2018 23:39:58 GMT - -*Version update only* - -## 0.3.7 -Wed, 12 Dec 2018 21:17:24 GMT - -*Version update only* - -## 0.3.6 -Wed, 12 Dec 2018 00:51:21 GMT - -*Version update only* - -## 0.3.5 -Tue, 11 Dec 2018 22:59:34 GMT - -*Version update only* - -## 0.3.4 -Tue, 11 Dec 2018 19:48:20 GMT - -### Patches - -- uwp: fix unset of color style props, LinkingManager improvements - -## 0.3.3 -Mon, 10 Dec 2018 21:52:13 GMT - -### Patches - -- mirror changes made to devmain - -## 0.3.2 -Mon, 10 Dec 2018 12:32:16 GMT - -*Version update only* - -## 0.3.1 -Fri, 07 Dec 2018 01:44:44 GMT - -*Version update only* - -## 0.3.0 -Thu, 06 Dec 2018 20:08:03 GMT - -### Minor changes - -- JSI Runtime implementation for Chakra -- JSI Runtime implementation for V8 - -## 0.2.5 -Thu, 06 Dec 2018 18:33:58 GMT - -*Version update only* - -## 0.2.4 -Thu, 06 Dec 2018 02:54:35 GMT - -### Patches - -- uwp: send onLayout events - -## 0.2.3 -Wed, 05 Dec 2018 22:13:30 GMT - -*Version update only* - -## 0.2.2 -Wed, 05 Dec 2018 19:09:20 GMT - -*Version update only* - -## 0.2.1 -Wed, 05 Dec 2018 02:02:42 GMT - -*Version update only* - -## 0.2.0 -Wed, 05 Dec 2018 00:48:46 GMT - -### Minor changes - -- Bringing the JSI sources from Github - -## 0.1.13 -Tue, 04 Dec 2018 01:31:45 GMT - -*Version update only* - -## 0.1.12 -Mon, 03 Dec 2018 23:22:14 GMT - -*Version update only* - -## 0.1.11 -Mon, 03 Dec 2018 20:04:57 GMT - -*Version update only* - -## 0.1.10 -Sat, 01 Dec 2018 22:51:42 GMT - -### Patches - -- uwp Clipboard NativeModule - -## 0.1.9 -Fri, 30 Nov 2018 20:39:50 GMT - -*Version update only* - -## 0.1.8 -Thu, 29 Nov 2018 13:46:58 GMT - -### Patches - -- Auto sync from tenantreactnativewin - -## 0.1.7 -Thu, 29 Nov 2018 11:45:37 GMT - -### Patches - -- Move windesktop files from react-native - -## 0.1.6 -Sat, 17 Nov 2018 00:23:17 GMT - -*Version update only* - -## 0.1.5 -Thu, 15 Nov 2018 22:37:42 GMT - -*Version update only* - -## 0.1.4 -Thu, 15 Nov 2018 20:12:15 GMT - -### Patches - -- Applying feedback from github PR - -## 0.1.3 -Thu, 15 Nov 2018 02:47:45 GMT - -*Version update only* - -## 0.1.2 -Wed, 14 Nov 2018 00:03:29 GMT - -*Version update only* - -## 0.1.1 -Tue, 13 Nov 2018 23:04:06 GMT - -*Version update only* - -## 0.1.0 -Tue, 13 Nov 2018 22:05:29 GMT - -### Minor changes - -- Auto-sync CL 18022008 from tenantreactnativewin to ISS sdx-platform - -## 0.0.25 -Tue, 13 Nov 2018 20:51:05 GMT - -*Version update only* - -## 0.0.24 -Tue, 13 Nov 2018 19:52:39 GMT - -*Version update only* - -## 0.0.23 -Sat, 10 Nov 2018 03:32:39 GMT - -### Patches - -- Adding ExceptionManager for windows platforms - -## 0.0.22 -Sat, 10 Nov 2018 00:21:40 GMT - -*Version update only* - -## 0.0.21 -Fri, 09 Nov 2018 22:37:07 GMT - -*Version update only* - -## 0.0.20 -Thu, 08 Nov 2018 01:57:36 GMT - -*Version update only* - -## 0.0.19 -Wed, 07 Nov 2018 22:27:17 GMT - -### Patches - -- uwp: add textDecorationLine support - -## 0.0.18 -Wed, 07 Nov 2018 20:32:53 GMT - -### Patches - -- Stop compiling JSC in any flavor for win32 - -## 0.0.17 -Wed, 07 Nov 2018 00:51:38 GMT - -*Version update only* - -## 0.0.16 -Tue, 06 Nov 2018 18:21:48 GMT - -### Patches - -- Move CxxMessageQueue to react-native-win - -## 0.0.15 -Tue, 06 Nov 2018 16:27:53 GMT - -### Patches - -- uwp: networking, border radius, position, layout property fixes - -## 0.0.14 -Tue, 06 Nov 2018 03:11:27 GMT - -*Version update only* - -## 0.0.13 -Tue, 06 Nov 2018 01:01:52 GMT - -*Version update only* - -## 0.0.12 -Sat, 03 Nov 2018 00:50:05 GMT - -### Patches - -- Move windesktop modules from react-native - -## 0.0.11 -Fri, 02 Nov 2018 22:11:47 GMT - -*Version update only* - -## 0.0.10 -Fri, 02 Nov 2018 21:15:28 GMT - -*Version update only* - -## 0.0.9 -Fri, 02 Nov 2018 20:18:56 GMT - -*Version update only* - -## 0.0.8 -Fri, 02 Nov 2018 18:27:14 GMT - -### Patches - -- Move more modules from react-native - -## 0.0.7 -Fri, 02 Nov 2018 11:55:51 GMT - -### Patches - -- ChakraCore process command queue - -## 0.0.6 -Fri, 02 Nov 2018 02:33:39 GMT - -### Patches - -- uwp: rename Icon prop foregroundColor to color - -## 0.0.5 -Thu, 01 Nov 2018 22:30:32 GMT - -*Version update only* - -## 0.0.4 -Thu, 01 Nov 2018 17:44:48 GMT - -*Version update only* - -## 0.0.3 -Thu, 01 Nov 2018 14:41:19 GMT - -*Version update only* - -## 0.0.2 -Thu, 01 Nov 2018 01:51:23 GMT - -### Patches - -- Start moving JS files for UWP into react-native-win - diff --git a/vnext/CMakeLists.txt b/vnext/CMakeLists.txt index a976749f15c..e90cd8e3601 100644 --- a/vnext/CMakeLists.txt +++ b/vnext/CMakeLists.txt @@ -4,12 +4,12 @@ add_subdirectory(Shared) if(WINRT) add_subdirectory(ReactUWP) - add_subdirectory(Universal.UnitTests) + # add_subdirectory(Universal.UnitTests) else() #TODO: Should we build all of these for WINRT too? The unit tests may provide extra validation add_subdirectory(Desktop) add_subdirectory(Desktop.DLL) - add_subdirectory(Desktop.IntegrationTests) - add_subdirectory(Desktop.UnitTests) - add_subdirectory(IntegrationTests) + # add_subdirectory(Desktop.IntegrationTests) + # add_subdirectory(Desktop.UnitTests) + # add_subdirectory(IntegrationTests) endif() diff --git a/vnext/Chakra/Chakra.vcxitems b/vnext/Chakra/Chakra.vcxitems index 77407eeee17..2900888981e 100644 --- a/vnext/Chakra/Chakra.vcxitems +++ b/vnext/Chakra/Chakra.vcxitems @@ -14,14 +14,26 @@ - - + + + NOJSC;%(PreprocessorDefinitions) + + + + NOJSC;%(PreprocessorDefinitions) + - + + + NOJSC;%(PreprocessorDefinitions) + - + + + NOJSC;%(PreprocessorDefinitions) + diff --git a/vnext/Chakra/ChakraExecutor.cpp b/vnext/Chakra/ChakraExecutor.cpp index 3b80de0660d..e28808d9824 100644 --- a/vnext/Chakra/ChakraExecutor.cpp +++ b/vnext/Chakra/ChakraExecutor.cpp @@ -242,10 +242,10 @@ const char* script = "for (var fn in console) {\n" "if (typeof console[fn] === \"function\") {\n" "(function(name) {\n" - "obj[name] = function(...rest) {\n" - "console[name](rest);\n" + "obj[name] = function(...args) {\n" + "console[name](...args);\n" "if (name in debugConsole && typeof debugConsole[name] === \"function\") {\n" - "debugConsole[name](rest);\n" + "debugConsole[name](...args);\n" "}\n" "}\n" "})(fn);\n" diff --git a/vnext/Chakra/ChakraHelpers.cpp b/vnext/Chakra/ChakraHelpers.cpp index 85913a95744..fda7f3fe436 100644 --- a/vnext/Chakra/ChakraHelpers.cpp +++ b/vnext/Chakra/ChakraHelpers.cpp @@ -49,6 +49,7 @@ bool fwrite(const T& val, FILE* file) noexcept return fwrite(&val, 1, file) == 1; } +#if !defined(CHAKRACORE_UWP) struct FileVersionInfoResource { uint16_t len; @@ -59,7 +60,7 @@ struct FileVersionInfoResource VS_FIXEDFILEINFO fixedFileInfo; uint32_t padding2; }; - +#endif class ChakraVersionInfo { public: @@ -73,6 +74,7 @@ class ChakraVersionInfo bool initialize() noexcept { +#if !defined(CHAKRACORE_UWP) // This code is win32 only at the moment. We will need to change this // line if we want to support UWP. constexpr wchar_t chakraDllName[] = L"ChakraCore.dll"; @@ -107,7 +109,7 @@ class ChakraVersionInfo m_fileVersionLS = chakraVersionInfo->fixedFileInfo.dwFileVersionLS; m_productVersionMS = chakraVersionInfo->fixedFileInfo.dwProductVersionMS; m_productVersionLS = chakraVersionInfo->fixedFileInfo.dwProductVersionLS; - +#endif return true; } diff --git a/vnext/Chakra/ChakraJsiRuntime_core.cpp b/vnext/Chakra/ChakraJsiRuntime_core.cpp index 0d0ddca8456..285d09dbee1 100644 --- a/vnext/Chakra/ChakraJsiRuntime_core.cpp +++ b/vnext/Chakra/ChakraJsiRuntime_core.cpp @@ -179,6 +179,7 @@ void ChakraJsiRuntime::setupNativePromiseContinuation() noexcept{ } } +#if !defined(CHAKRACORE_UWP) // This is very wierd. This should match with the definition of VS_VERSIONINFO as defined in https://docs.microsoft.com/en-us/windows/desktop/menurc/vs-versioninfo // I can't find a way to include the actual definition of VS_VERSIONINFO // TODO :: Re-evaluate this strategy. @@ -191,12 +192,14 @@ struct FileVersionInfoResource { VS_FIXEDFILEINFO fixedFileInfo; uint32_t padding2; }; +#endif // TODO :: This code is mostly copied from the old ChakraExecutor flow, and not verified for reliability yet. // TODO :: Re-evaluate this strategy of finding the dll version for versioning the runtime. /*static*/ void ChakraJsiRuntime::initRuntimeVersion() noexcept { // This code is win32 only at the moment. We will need to change this // line if we want to support UWP. +#if !defined(CHAKRACORE_UWP) constexpr wchar_t chakraDllName[] = L"ChakraCore.dll"; auto freeLibraryWrapper = [](void* p) { FreeLibrary((HMODULE)p); }; @@ -222,6 +225,7 @@ struct FileVersionInfoResource { s_runtimeVersion = chakraVersionInfo->fixedFileInfo.dwFileVersionMS; s_runtimeVersion <<= 32; s_runtimeVersion |= chakraVersionInfo->fixedFileInfo.dwFileVersionLS; +#endif } JsErrorCode ChakraJsiRuntime::enableDebugging(JsRuntimeHandle runtime, std::string const& runtimeName, bool breakOnNextLine, uint16_t port, diff --git a/vnext/Desktop.DLL/React.Windows.Desktop.DLL.vcxproj b/vnext/Desktop.DLL/React.Windows.Desktop.DLL.vcxproj index 8f91b57c4f8..c528d8d44cb 100644 --- a/vnext/Desktop.DLL/React.Windows.Desktop.DLL.vcxproj +++ b/vnext/Desktop.DLL/React.Windows.Desktop.DLL.vcxproj @@ -1,14 +1,6 @@ - - Debug - x86 - - - Release - x86 - Debug x64 @@ -17,7 +9,6 @@ Release x64 - Debug Win32 @@ -32,9 +23,6 @@ React.Windows.Desktop.DLL react-native-win32 - - true - @@ -60,10 +48,9 @@ BOOST_ASIO_HAS_IOCP - Force unique layout/size for boost::asio::basic_stream_socket<> subtypes. REACTWINDOWS_BUILD - building with REACTWINDOWS_API as dll exports --> - REACTWINDOWS_BUILD;BOOST_ASIO_HAS_IOCP;_WINSOCK_DEPRECATED_NO_WARNINGS;_WIN32_WINNT=_WIN32_WINNT_WIN7;WIN32;_WINDOWS;_USRDLL;REACTNATIVEWIN32_EXPORTS;FOLLY_NO_CONFIG;WIN32_LEAN_AND_MEAN;NOMINMAX;GLOG_NO_ABBREVIATED_SEVERITIES;_HAS_AUTO_PTR_ETC;CHAKRACORE;RN_EXPORT=;%(PreprocessorDefinitions) + REACTWINDOWS_BUILD;BOOST_ASIO_HAS_IOCP;_WINSOCK_DEPRECATED_NO_WARNINGS;_WIN32_WINNT=_WIN32_WINNT_WIN7;WIN32;_WINDOWS;_USRDLL;REACTNATIVEWIN32_EXPORTS;FOLLY_NO_CONFIG;NOMINMAX;GLOG_NO_ABBREVIATED_SEVERITIES;_HAS_AUTO_PTR_ETC;CHAKRACORE;RN_EXPORT=;%(PreprocessorDefinitions) ProgramDatabase %(AdditionalOptions) /Zc:strictStrings - ..\build\$(IntDir)\%(RelativeDir) Use pch.h @@ -74,21 +61,6 @@ DebugFull - - - NOJSC;%(PreprocessorDefinitions) - - - - - _DEBUG;DEBUG;%(PreprocessorDefinitions) - - - - - NDEBUG;%(PreprocessorDefinitions) - - react-native-win32.x64.def @@ -146,20 +118,20 @@ - - - - - + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - + + + + + \ No newline at end of file diff --git a/vnext/Desktop.DLL/Version.rc b/vnext/Desktop.DLL/Version.rc index 636949ea939..a4c6ab1c411 100644 --- a/vnext/Desktop.DLL/Version.rc +++ b/vnext/Desktop.DLL/Version.rc @@ -1,7 +1,7 @@ #include -#define VER_FILEVERSION 0,59,0,11 -#define VER_FILEVERSION_STR "0.59.0-vnext.11" +#define VER_FILEVERSION 0,59,0,51 +#define VER_FILEVERSION_STR "0.59.0-vnext.51" #ifndef DEBUG #define VER_DEBUG 0 diff --git a/vnext/Desktop.DLL/packages.config b/vnext/Desktop.DLL/packages.config index 108f4b4577d..1fb9d1a1956 100644 --- a/vnext/Desktop.DLL/packages.config +++ b/vnext/Desktop.DLL/packages.config @@ -2,7 +2,7 @@ - + - - \ No newline at end of file + + diff --git a/vnext/Desktop.IntegrationTests/CMakeLists.txt b/vnext/Desktop.IntegrationTests/CMakeLists.txt index b83ec2c5585..caf1296f6d6 100644 --- a/vnext/Desktop.IntegrationTests/CMakeLists.txt +++ b/vnext/Desktop.IntegrationTests/CMakeLists.txt @@ -7,6 +7,7 @@ set(SOURCES DesktopTestRunner.cpp WebSocketIntegrationTest.cpp WebSocketJSExecutorIntegrationTest.cpp + WebSocketServer.cpp WebSocketModuleIntegrationTest.cpp) add_library(ReactWindows.Desktop.IntegrationTests SHARED ${SOURCES}) diff --git a/vnext/Desktop.IntegrationTests/DesktopTestInstance.cpp b/vnext/Desktop.IntegrationTests/DesktopTestInstance.cpp index b3ed473309e..96596bb615d 100644 --- a/vnext/Desktop.IntegrationTests/DesktopTestInstance.cpp +++ b/vnext/Desktop.IntegrationTests/DesktopTestInstance.cpp @@ -35,6 +35,6 @@ shared_ptr DesktopTestInstance::GetInnerInstance() co return m_instanceWrapper->GetInstance(); } -#pragma endregion // DesktopTestInstance members +#pragma endregion DesktopTestInstance members } } } // namespace facebook::react::test diff --git a/vnext/Desktop.IntegrationTests/DesktopTestInstance.h b/vnext/Desktop.IntegrationTests/DesktopTestInstance.h index ed2d0541a8b..675808a9822 100644 --- a/vnext/Desktop.IntegrationTests/DesktopTestInstance.h +++ b/vnext/Desktop.IntegrationTests/DesktopTestInstance.h @@ -24,7 +24,7 @@ class DesktopTestInstance : public ITestInstance void DetachRootView() noexcept; std::shared_ptr GetInnerInstance() const noexcept override; - #pragma endregion // ITestInstance members + #pragma endregion ITestInstance members }; } } } // namespace facebook::react::test diff --git a/vnext/Desktop.IntegrationTests/RNTesterIntegrationTests.cpp b/vnext/Desktop.IntegrationTests/RNTesterIntegrationTests.cpp index de2729a3672..6b1fee811c9 100644 --- a/vnext/Desktop.IntegrationTests/RNTesterIntegrationTests.cpp +++ b/vnext/Desktop.IntegrationTests/RNTesterIntegrationTests.cpp @@ -7,9 +7,7 @@ using namespace facebook::react::test; using namespace Microsoft::VisualStudio::CppUnitTestFramework; -namespace Microsoft { -namespace VisualStudio { -namespace CppUnitTestFramework { +namespace Microsoft::VisualStudio::CppUnitTestFramework { template <> std::wstring ToString(const facebook::react::test::TestStatus& status) @@ -17,7 +15,7 @@ std::wstring ToString(const facebook::react:: return ToString(static_cast(status)); } -} } } // namespace Microsoft::VisualStudio::CppUnitTestFramework +} // namespace Microsoft::VisualStudio::CppUnitTestFramework TEST_CLASS(RNTesterIntegrationTests) { diff --git a/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj b/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj index 89cec84e31b..93fa96822fd 100644 --- a/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj +++ b/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj @@ -1,14 +1,6 @@ - - Debug - x86 - - - Release - x86 - Debug x64 @@ -17,7 +9,6 @@ Release x64 - Debug Win32 @@ -55,8 +46,9 @@ true - - BOOST_ASIO_HAS_IOCP;_WIN32_WINNT=_WIN32_WINNT_WIN7;WIN32;_WINDOWS;REACTNATIVEWIN32_EXPORTS;FOLLY_NO_CONFIG;WIN32_LEAN_AND_MEAN;NOMINMAX;GLOG_NO_ABBREVIATED_SEVERITIES;_HAS_AUTO_PTR_ETC;CHAKRACORE;RN_PLATFORM=windesktop;RN_EXPORT=;JSI_EXPORT=;NOJSC;%(PreprocessorDefinitions) + + BOOST_ASIO_HAS_IOCP;_WIN32_WINNT=_WIN32_WINNT_WIN7;WIN32;_WINDOWS;REACTNATIVEWIN32_EXPORTS;FOLLY_NO_CONFIG;NOMINMAX;GLOG_NO_ABBREVIATED_SEVERITIES;_HAS_AUTO_PTR_ETC;CHAKRACORE;RN_PLATFORM=windesktop;RN_EXPORT=;JSI_EXPORT=;%(PreprocessorDefinitions) + %(AdditionalOptions) /bigobj $(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories) ProgramDatabase true @@ -65,7 +57,6 @@ $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories) Shlwapi.lib;Version.lib;%(AdditionalDependencies) true - Console @@ -73,35 +64,30 @@ OSS_RN;FOLLY_MOBILE=1;ENUM_BITFIELDS_NOT_SUPPORTED;%(PreprocessorDefinitions) - - - _DEBUG;%(PreprocessorDefinitions) - /JMC- %(AdditionalOptions) - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - - - - + + + NOJSC;%(PreprocessorDefinitions) + + + + NOJSC;%(PreprocessorDefinitions) + - + + + NOJSC;%(PreprocessorDefinitions) + + + + NOJSC;%(PreprocessorDefinitions) + @@ -130,24 +116,25 @@ + - - - - - + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - + + + + + diff --git a/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj.filters b/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj.filters index 25f5bfe4563..b1ff9efcace 100644 --- a/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj.filters +++ b/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj.filters @@ -45,6 +45,9 @@ Integration Tests + + Source Files + Source Files @@ -56,6 +59,9 @@ Header Files + + Header Files + Header Files diff --git a/vnext/Desktop.IntegrationTests/TestMessageQueueThread.cpp b/vnext/Desktop.IntegrationTests/TestMessageQueueThread.cpp index f870d9bdee2..14cace8634b 100644 --- a/vnext/Desktop.IntegrationTests/TestMessageQueueThread.cpp +++ b/vnext/Desktop.IntegrationTests/TestMessageQueueThread.cpp @@ -196,6 +196,6 @@ bool TestMessageQueueThread::IsWorkerThread() return m_workerThread != NULL && GetCurrentThreadId() == GetThreadId(m_workerThread); } -#pragma endregion // namespace TestMessageQueueThread members +#pragma endregion namespace TestMessageQueueThread members }}} //namespace facebook::react::test diff --git a/vnext/Desktop.IntegrationTests/TestMessageQueueThread.h b/vnext/Desktop.IntegrationTests/TestMessageQueueThread.h index d061eaca6d6..c4df0353015 100644 --- a/vnext/Desktop.IntegrationTests/TestMessageQueueThread.h +++ b/vnext/Desktop.IntegrationTests/TestMessageQueueThread.h @@ -42,7 +42,7 @@ class TestMessageQueueThread : public facebook::react::MessageQueueThread // Once quitSynchronous() returns, no further work should run on the queue. void quitSynchronous() noexcept override; - #pragma endregion // MessageQueueThread members + #pragma endregion MessageQueueThread members private: enum class State diff --git a/vnext/Desktop.IntegrationTests/WebSocketIntegrationTest.cpp b/vnext/Desktop.IntegrationTests/WebSocketIntegrationTest.cpp index cd404f88bcd..19ce87d4828 100644 --- a/vnext/Desktop.IntegrationTests/WebSocketIntegrationTest.cpp +++ b/vnext/Desktop.IntegrationTests/WebSocketIntegrationTest.cpp @@ -3,27 +3,31 @@ #include #include -#include "unicode.h" +#include #include #include #include -using namespace facebook::react; +using namespace Microsoft::React; using namespace Microsoft::VisualStudio::CppUnitTestFramework; using std::chrono::milliseconds; using std::condition_variable; +using std::make_shared; using std::unique_lock; using std::lock_guard; using std::promise; using std::string; +using CloseCode = IWebSocket::CloseCode; + TEST_CLASS(WebSocketIntegrationTest) { TEST_METHOD(ConnectClose) { - auto ws = IWebSocket::Make("ws://localhost:5555/"); + auto server = make_shared(5556); + auto ws = IWebSocket::Make("ws://localhost:5556/"); Assert::IsFalse(nullptr == ws); bool connected = false; string message; @@ -32,8 +36,10 @@ TEST_CLASS(WebSocketIntegrationTest) connected = true; }); + server->Start(); ws->Connect(); - ws->Close(IWebSocket::CloseCode::Normal, "Closing"); + ws->Close(CloseCode::Normal, "Closing"); + server->Stop(); Assert::IsTrue(connected); } @@ -41,10 +47,12 @@ TEST_CLASS(WebSocketIntegrationTest) TEST_METHOD(ConnectNoClose) { bool connected = false; + auto server = make_shared(5556); + server->Start(); // IWebSocket scope. Ensures object is closed implicitly by destructor. { - auto ws = IWebSocket::Make("ws://localhost:5555/"); + auto ws = IWebSocket::Make("ws://localhost:5556/"); ws->SetOnConnect([&connected]() { connected = true; @@ -53,12 +61,17 @@ TEST_CLASS(WebSocketIntegrationTest) ws->Connect(); } + server->Stop(); + Assert::IsTrue(connected); } TEST_METHOD(PingClose) { - auto ws = IWebSocket::Make("ws://localhost:5555"); + auto server = make_shared(5556); + server->Start(); + + auto ws = IWebSocket::Make("ws://localhost:5556"); promise pingPromise; ws->SetOnPing([&pingPromise]() { @@ -75,43 +88,14 @@ TEST_CLASS(WebSocketIntegrationTest) auto pingFuture = pingPromise.get_future(); pingFuture.wait(); bool pinged = pingFuture.get(); + ws->Close(CloseCode::Normal, "Closing after reading"); - ws->Close(IWebSocket::CloseCode::Normal, "Closing after reading"); + server->Stop(); Assert::IsTrue(pinged); Assert::AreEqual({}, errorString); } - TEST_METHOD(SendReceiveNoClose) - { - auto ws = IWebSocket::Make("ws://localhost:5555/"); - promise response; - ws->SetOnMessage([&response](size_t size, const string& message) - { - // Ignore greeting message. - if (message == "hello") - return; - - response.set_value(message); - }); - string errorMessage; - ws->SetOnError([&errorMessage](IWebSocket::Error err) - { - errorMessage = err.Message; - }); - - ws->Connect(); - ws->Send("suffixme"); - - // Block until respone is received. Fail in case of a remote endpoint failure. - auto future = response.get_future(); - future.wait(); - string result = future.get(); - - Assert::AreEqual({}, errorMessage); - Assert::AreEqual(string("suffixme_response"), result); - } - // Emulate promise/future functionality. // Fails when connecting to stock package bundler. BEGIN_TEST_METHOD_ATTRIBUTE(WaitForBundlerResponseNoClose) @@ -157,7 +141,12 @@ TEST_CLASS(WebSocketIntegrationTest) TEST_METHOD(SendReceiveClose) { - auto ws = IWebSocket::Make("ws://localhost:5555/"); + auto server = make_shared(5556); + server->SetMessageFactory([](string&& message) + { + return message + "_response"; + }); + auto ws = IWebSocket::Make("ws://localhost:5556/"); promise sentSizePromise; ws->SetOnSend([&sentSizePromise](size_t size) { @@ -166,10 +155,6 @@ TEST_CLASS(WebSocketIntegrationTest) promise receivedPromise; ws->SetOnMessage([&receivedPromise](size_t size, const string& message) { - // Ignore greeting message - if (message == "hello") - return; - receivedPromise.set_value(message); }); string errorMessage; @@ -178,7 +163,8 @@ TEST_CLASS(WebSocketIntegrationTest) errorMessage = err.Message; }); - string sent = "suffixme"; + server->Start(); + string sent = "prefix"; ws->Connect(); ws->Send(sent); @@ -191,31 +177,34 @@ TEST_CLASS(WebSocketIntegrationTest) string received = receivedFuture.get(); Assert::AreEqual({}, errorMessage); - ws->Close(IWebSocket::CloseCode::Normal, "Closing after reading"); + ws->Close(CloseCode::Normal, "Closing after reading"); + server->Stop(); Assert::AreEqual({}, errorMessage); Assert::AreEqual(sent.length(), sentSize); - Assert::AreEqual(string("suffixme_response"), received); + Assert::AreEqual({ "prefix_response" }, received); } TEST_METHOD(SendReceiveLargeMessage) { - auto ws = IWebSocket::Make("ws://localhost:5555/"); + auto server = make_shared(5556); + server->SetMessageFactory([](string&& message) + { + return message + "_response"; + }); + auto ws = IWebSocket::Make("ws://localhost:5556/"); promise response; ws->SetOnMessage([&response](size_t size, const string& message) { - // Ignore greeting message - if (message == "hello") - return; - response.set_value(message); }); - ws->SetOnError([](IWebSocket::Error err) + string errorMessage; + ws->SetOnError([&errorMessage](IWebSocket::Error err) { - auto message = facebook::react::unicode::utf8ToUtf16(err.Message); - Assert::Fail(message.c_str()); + errorMessage = err.Message; }); + server->Start(); ws->Connect(); char digits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; @@ -234,8 +223,10 @@ TEST_CLASS(WebSocketIntegrationTest) future.wait(); string result = future.get(); - ws->Close(IWebSocket::CloseCode::Normal, "Closing after reading"); + ws->Close(CloseCode::Normal, "Closing after reading"); + server->Stop(); + Assert::AreEqual({}, errorMessage); Assert::AreEqual(static_cast(LEN + string("_response").length()), result.length()); } @@ -261,13 +252,24 @@ TEST_CLASS(WebSocketIntegrationTest) END_TEST_METHOD_ATTRIBUTE() TEST_METHOD(AdditionalHeaders) { - auto ws = IWebSocket::Make("ws://localhost:5555/"); + string cookie; + auto server = make_shared(5556); + server->SetOnHandshake([server](boost::beast::websocket::response_type& response) + { + auto cookie = response[boost::beast::http::field::cookie].to_string(); + server->SetMessageFactory([cookie](string&&) + { + return cookie; + }); + }); + auto ws = IWebSocket::Make("ws://localhost:5556/"); promise response; ws->SetOnMessage([&response](size_t size, const string& message) { response.set_value(message); }); + server->Start(); ws->Connect({}, {{ L"Cookie", "JSESSIONID=AD9A320CC4034641997FF903F1D10906" }}); ws->Send(""); @@ -275,65 +277,42 @@ TEST_CLASS(WebSocketIntegrationTest) future.wait(); string result = future.get(); - Assert::AreEqual(string("JSESSIONID=AD9A320CC4034641997FF903F1D10906"), result); + Assert::AreEqual({ "JSESSIONID=AD9A320CC4034641997FF903F1D10906" }, result); - ws->Close(IWebSocket::CloseCode::Normal, "No reason"); + ws->Close(CloseCode::Normal, "No reason"); + server->Stop(); } - /// - // Run this test against a valid WebSocket server runing on SSL. - // See sample below. - /// - /* -const WebSocket = require('ws'); -const fs = require('fs'); -const https = require('https'); - -const httpsServer = https.createServer({ - key: fs.readFileSync('key.pem'), - cert: fs.readFileSync('cert.pem') -}); -const server = new WebSocket.Server({ - server:httpsServer -}); - -server.on('connection', (ws) => { - ws.on('message', (message) => { - console.log('Received message:', message); - if (message === 'exit') { - console.log('WebSocket integration test server exit'); - process.exit(0); - } - console.log('Cookie:', ws.upgradeReq.headers.cookie); - ws.send(message + '_response'); - }); - - ws.send('hello'); -}); - -httpsServer.listen(443); - */ - BEGIN_TEST_METHOD_ATTRIBUTE(SendAndReceiveSsl) - TEST_IGNORE() - END_TEST_METHOD_ATTRIBUTE() - TEST_METHOD(SendAndReceiveSsl) + TEST_METHOD(SendReceiveSsl) { - auto ws = IWebSocket::Make("wss://localhost/"); - string message; - ws->SetOnMessage([&message](size_t size, const string& messageIn) + auto server = make_shared(5556, /*isSecure*/ true); + server->SetMessageFactory([](string&& message) { - message = messageIn; + return message + "_response"; + }); + auto ws = IWebSocket::Make("wss://localhost:5556"); + promise response; + ws->SetOnMessage([&response](size_t size, const string& messageIn) + { + response.set_value(messageIn); }); + server->Start(); ws->Connect(); ws->Send("suffixme"); - ws->Close(IWebSocket::CloseCode::Normal, "Closing after reading"); - Assert::AreEqual(string("hello"), message); + auto result = response.get_future(); + result.wait(); + + ws->Close(CloseCode::Normal, "Closing after reading"); + server->Stop(); + + Assert::AreEqual({ "suffixme_response" }, result.get()); } + //TODO: Use Test::WebSocketServer!!! BEGIN_TEST_METHOD_ATTRIBUTE(SendBinary) - //TEST_IGNORE() + TEST_IGNORE() END_TEST_METHOD_ATTRIBUTE() TEST_METHOD(SendBinary) { @@ -386,23 +365,24 @@ httpsServer.listen(443); Assert::AreEqual(messages[i], response); } - ws->Close(IWebSocket::CloseCode::Normal, "Closing after reading"); + ws->Close(CloseCode::Normal, "Closing after reading"); Assert::AreEqual({}, errorMessage); } TEST_METHOD(SendConsecutive) { - auto ws = IWebSocket::Make("ws://localhost:5555/"); + auto server = make_shared(5556); + server->SetMessageFactory([](string&& message) + { + return message + "_response"; + }); + auto ws = IWebSocket::Make("ws://localhost:5556/"); promise response; const int writes = 10; int count = 0; ws->SetOnMessage([&response, &count, writes](size_t size, const string& message) { - // Ignore greeting message. - if (message == "hello") - return; - if (++count < writes) return; @@ -414,6 +394,7 @@ httpsServer.listen(443); errorMessage = err.Message; }); + server->Start(); ws->Connect(); // Consecutive immediate writes should be enqueued. @@ -426,8 +407,11 @@ httpsServer.listen(443); future.wait(); string result = future.get(); - ws->Close(IWebSocket::CloseCode::Normal, "Closing"); + ws->Close(CloseCode::Normal, "Closing"); + server->Stop(); + Assert::AreEqual({}, errorMessage); - Assert::AreEqual(string("suffixme_response"), result); + Assert::AreEqual(writes, count); + Assert::AreEqual({ "suffixme_response" }, result); } }; diff --git a/vnext/Desktop.IntegrationTests/WebSocketServer.cpp b/vnext/Desktop.IntegrationTests/WebSocketServer.cpp new file mode 100644 index 00000000000..91f6a7241ea --- /dev/null +++ b/vnext/Desktop.IntegrationTests/WebSocketServer.cpp @@ -0,0 +1,390 @@ +#include "WebSocketServer.h" + +#include +#include + +using namespace boost::asio; + +using boost::system::error_code; +using std::function; +using std::placeholders::_1; +using std::placeholders::_2; +using std::string; + +namespace websocket = boost::beast::websocket; + +namespace Microsoft { +namespace React { +namespace Test { + +#pragma region BaseWebSocketSession + +template +BaseWebSocketSession::BaseWebSocketSession(WebSocketServiceCallbacks& callbacks) + : m_callbacks{ callbacks } + , m_state{ State::Stopped } +{ +} + +template +BaseWebSocketSession::~BaseWebSocketSession() +{ +} + +template +void BaseWebSocketSession::Start() +{ + Accept(); +} + +template +void BaseWebSocketSession::Accept() +{ + m_stream->async_accept_ex( + bind_executor(*m_strand, std::bind( + &BaseWebSocketSession::OnHandshake, + this->SharedFromThis(), + _1 // response + )), + bind_executor(*m_strand, std::bind( + &BaseWebSocketSession::OnAccept, + this->SharedFromThis(), + _1 // ec + )) + ); +} + +template +void BaseWebSocketSession::OnHandshake(websocket::response_type& response) +{ + if (m_callbacks.OnHandshake) + m_callbacks.OnHandshake(response); +} + +template +void BaseWebSocketSession::OnAccept(error_code ec) +{ + if (ec) + return;//TODO: fail + + m_state = State::Started; + + if (m_callbacks.OnConnection) + m_callbacks.OnConnection(); + + Read(); +} + +template +void BaseWebSocketSession::Read() +{ + if (State::Stopped == m_state) + return; + + m_stream->async_read(m_buffer, bind_executor(*m_strand, std::bind( + &BaseWebSocketSession::OnRead, + this->SharedFromThis(), + _1, // ec + _2 // transferred + ))); +} + +template +void BaseWebSocketSession::OnRead(error_code ec, size_t /*transferred*/) +{ + if (websocket::error::closed == ec) + return; + + if (ec) + return;//TODO: fail instead + + if (!m_callbacks.MessageFactory) + { + m_buffer.consume(m_buffer.size()); + return Read(); + } + + m_message = m_callbacks.MessageFactory(buffers_to_string(m_buffer.data())); + m_buffer.consume(m_buffer.size()); + + m_stream->text(m_stream->got_text()); + m_stream->async_write(buffer(m_message), bind_executor(*m_strand, std::bind( + &BaseWebSocketSession::OnWrite, + this->SharedFromThis(), + _1, // ec + _2 // transferred + ))); +} + +template +void BaseWebSocketSession::OnWrite(error_code ec, size_t /*transferred*/) +{ + if (ec) + return; //TODO: fail + + // Clear outgoing message contents. + m_message.clear(); + + Read(); +} + +#pragma endregion BaseWebSocketSession + +#pragma region WebSocketSession + +WebSocketSession::WebSocketSession(ip::tcp::socket socket, WebSocketServiceCallbacks& callbacks) + : BaseWebSocketSession(callbacks) +{ + m_stream = std::make_shared>(std::move(socket)); + m_strand = std::make_shared>(m_stream->get_executor()); +} + +WebSocketSession::~WebSocketSession() {} + +#pragma region BaseWebSocketSession + +std::shared_ptr> WebSocketSession::SharedFromThis() /*override*/ +{ + return this->shared_from_this(); +} + +#pragma endregion BaseWebSocketSession + +#pragma endregion WebSocketSession + +#pragma region SecureWebSocketSession + +SecureWebSocketSession::SecureWebSocketSession(ip::tcp::socket socket, WebSocketServiceCallbacks& callbacks) + : BaseWebSocketSession(callbacks) +{ + // Initialize SSL context. + string const cert = + "-----BEGIN CERTIFICATE-----\n" + "MIIDhjCCAm6gAwIBAgIJAPh+egUebaStMA0GCSqGSIb3DQEBCwUAMFgxCzAJBgNV\n" + "BAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdSZWRtb25kMRIw\n" + "EAYDVQQKDAlNaWNyb3NvZnQxDjAMBgNVBAsMBVJlYWN0MB4XDTE5MDYwMTA4MDcx\n" + "M1oXDTI5MDUyOTA4MDcxM1owWDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hp\n" + "bmd0b24xEDAOBgNVBAcMB1JlZG1vbmQxEjAQBgNVBAoMCU1pY3Jvc29mdDEOMAwG\n" + "A1UECwwFUmVhY3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgHKC9\n" + "XC+1FjDg2Xdmbpf3ILiJQtGFiD3WFb+duNXThOA0LY6gytVBY6LitAzB7Jm7spvx\n" + "BbA46kw8Dsmv02hI0diVzFKCB5bTTs0N8bgAsem6qvDpo/mvp2TtDU2J8o4RhMQ3\n" + "BQvdZUGgtH4VR2W4vIHufNjVUvN9hTL2eOBz0EYElsMSogG8f97N+m/7L6JeyjPo\n" + "kFwXYTFMjv3ihJmev/cBNkxuchLUT7NAc7bMCtmv5lzsKMKe6g0lUxDSBYxXztqU\n" + "l3huo2g990VbvTWH/lhz3bgdnon/AUKWBmS2eRmK9hH/rGlm1NeMCjexMZrYC3m8\n" + "vvfIR25plGmNjyQJAgMBAAGjUzBRMB0GA1UdDgQWBBTNLE3Nl0s3O40wDEXf9t/7\n" + "r6Y1QjAfBgNVHSMEGDAWgBTNLE3Nl0s3O40wDEXf9t/7r6Y1QjAPBgNVHRMBAf8E\n" + "BTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAbRL+69uZLW3Q6JIQ9qg3CPjm6574o\n" + "cOiyJ9DX49i23AyYNsCYulvLApHgrmltMJHrC4U7EasQCTtwpAMyLJDLIDdujSSs\n" + "ynSe5PcNeElLmEkH4PxyAFsb/2oWI2PSJh0vseuugUpeKTHJv5MPkLUm7WMLHYj5\n" + "uOQzYDwJ+IuveVzX5TRXtkY8jF9ErL4iF8eYTyp0ANeY11vJOAbd2FcAy5baYjB3\n" + "JVczHy7eegwfOQJFM9mIZE7+Ac0SaknC0Jun9486cJ0mvbdrMSd+vgF85OrpWwYU\n" + "ISfux0NDVN1gjvSgdkEB+CWnV1rNKsVKlg4psDkpq33AJEwnx3qNxtKG\n" + "-----END CERTIFICATE-----\n"; + + string const key = + "-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEowIBAAKCAQEAoBygvVwvtRYw4Nl3Zm6X9yC4iULRhYg91hW/nbjV04TgNC2O\n" + "oMrVQWOi4rQMweyZu7Kb8QWwOOpMPA7Jr9NoSNHYlcxSggeW007NDfG4ALHpuqrw\n" + "6aP5r6dk7Q1NifKOEYTENwUL3WVBoLR+FUdluLyB7nzY1VLzfYUy9njgc9BGBJbD\n" + "EqIBvH/ezfpv+y+iXsoz6JBcF2ExTI794oSZnr/3ATZMbnIS1E+zQHO2zArZr+Zc\n" + "7CjCnuoNJVMQ0gWMV87alJd4bqNoPfdFW701h/5Yc924HZ6J/wFClgZktnkZivYR\n" + "/6xpZtTXjAo3sTGa2At5vL73yEduaZRpjY8kCQIDAQABAoIBAA/bpgP7THJYF1E9\n" + "2LiZfY2pfP2DU7MxEkbQ8qCRfQQtJfOlC3pbfJG0Z56ijJzsbTGM+CsAEDsi4ZgV\n" + "Mt6qRqrntdboXMeqLsMRC/g0l6/h7y9g3OmXJxTBtJpR9fsSvgV4K+LzKgCslbpw\n" + "BgjfgHCyov/W97bxN1KYTbrhsAFoWFwyTglDIkTYo/92suwsyYt14pxnK54QyNrM\n" + "tWKS0K9rZmSMjaVYW+nnSLelFVAOAzW4SOt8CE1V0usjIkmD5smdadjT14exWnxV\n" + "zVMhsbrfUFi3oBfW8X+TuWQjBnVfX0akZALY6vmnmOEWLz4pXJBLmazSGpXyM5o2\n" + "JpxSUS0CgYEAywE9MhWqKhZXpOwGWbNe1Nibh4l8vt+pTDs2TpFdHXNT8UfuUk03\n" + "ycCxGKrDPUAUPdVGygvmqdKHpXLbWalPGdFR6Xcn5YjVxM7L37jGl28oQOdNLI5u\n" + "Lw7hJ5L84M0LZqMI5589jA63WrgkLNQ9eKnuFn9N/3n9r/uZqtGVjLsCgYEAyejc\n" + "I/St33V0CNDtfEZ8dBDztXhx1WjDzv+JgNiy7pLUB+8yW0/iU2Y8ptpmfQ0nRDDv\n" + "sGK5myuBv85PRgWQnPskL3V5+L+DK40hyYnrL4bKhxT8az2CQdWI23sS4Nq5b59A\n" + "ylUyGIUXv3P62nUgMq3kM7L6mMgz/cCxeVeQyAsCgYAlZAIIgpMIE3trJgn5ZZ9W\n" + "5tqmuT0fzwRYxSM4j2+uJ/rTGyObRxu6bmJwH6u8UVwpE2ppdo2yw9M2NxSNzDCE\n" + "mdhTfx37Ghv9lvVYLKlvZQruAWxmg4lp43y3FEy9fybVbbwLJXppnKBK9lW7aBA2\n" + "dF4lCKeuIaMHUfk4zEeWVwKBgF81HXEa9E4VfUSW+BUMy6yTPcgJZmwCParDFlya\n" + "Ui1rMO4Y3X7vOUKoR9tJyuAWrrhZ9vwOYYUIy+Lc7saO4zUSu2phk8U20SxdHVyC\n" + "W1MK1T9DJw+ObniKr0EHVMyQdrZqusttxvSG9b7Cerw+VJNxKdUzBTW72cBC96zH\n" + "HK8nAoGBAMGKiSm4a1O5SpSiiZ6kNZHw9wB98Jtic7ozoUrlVEPSeRrXq/BzsyyH\n" + "md/sN/1v/Qq4SPlUtnzRakcPa2sntDb4SEt/Lrr97ouX1C/qfWljh69jRDLPBBez\n" + "cAlHdEzualsWQsACr7I71UebXvha+v0XXAKiIRqAKRrFLmPPCFrP\n" + "-----END RSA PRIVATE KEY-----\n"; + + string dh = + "-----BEGIN DH PARAMETERS-----\n" + "MIIBCAKCAQEA5VbTCtf4s2qPpqTtk2pXsYcqo7cLF0LVQaXMhOZNmif0TKDyclSV\n" + "NQANJcl0K9C5cGfh/1oEZs30A+Ww1zCtjkwJFvQdUAhCy/1U/qhRO2swXtz+CGZL\n" + "7PL0yu0Xht3EqGRS4z98LPCALVYvuqbNKTnFHUZl8oYJT0Xx0lzzZ+r5uFYYghQU\n" + "nCohXf/O0VLCPJMnd/oLY70CcPEL9V1KDb80oTzlYzrVPAHidcOXkiZpmOHgdiA/\n" + "LLG0h495hZhL5OqqDrLM7IWxHNmzgwhQ04PdGa6zPP4fnt7L4Ia5/lYOolvdmNkx\n" + "XgdewtScX7P5ltOMhhcWS4Og+qZn18a3kwIBAg==\n" + "-----END DH PARAMETERS-----\n"; + + auto context = ssl::context(ssl::context::sslv23); + + //TODO: Remove if not used. + context.set_password_callback([](size_t, ssl::context_base::password_purpose) + { + return "test"; + }); + + context.set_options(ssl::context::default_workarounds | ssl::context::no_sslv2 | ssl::context::single_dh_use); + context.use_certificate_chain(buffer(cert.data(), cert.size())); + context.use_private_key(buffer(key.data(), key.size()), ssl::context::file_format::pem); + context.use_tmp_dh(buffer(dh.data(), dh.size())); + + m_stream = std::make_shared>>(std::move(socket), context); + m_strand = std::make_shared>(m_stream->get_executor()); +} + +SecureWebSocketSession::~SecureWebSocketSession() {} + +#pragma region BaseWebSocketSession + +std::shared_ptr>> SecureWebSocketSession::SharedFromThis() /*override*/ +{ + return this->shared_from_this(); +} + +#pragma endregion BaseWebSocketSession + +#pragma region IWebSocketSession + +void SecureWebSocketSession::Start() /*override*/ +{ + m_stream->next_layer().async_handshake(ssl::stream_base::server, bind_executor(*m_strand, std::bind( + &SecureWebSocketSession::OnSslHandshake, + this->shared_from_this(), + _1 // ec + ))); +} + +void SecureWebSocketSession::OnSslHandshake(error_code ec) +{ + if (ec) + return; + + Accept(); +} + +#pragma endregion IWebSocketSession + +#pragma endregion SecureWebSocketSession + +#pragma region WebSocketServer + +WebSocketServer::WebSocketServer(uint16_t port, bool isSecure) + : m_acceptor{ m_context } + , m_socket{ m_context } + , m_sessions{} + , m_isSecure{ isSecure } +{ + ip::tcp::endpoint ep{ip::make_address("0.0.0.0"), port }; + error_code ec; + + m_acceptor.open(ep.protocol(), ec); + if (ec) + { + return; //TODO: handle + } + + m_acceptor.set_option(socket_base::reuse_address(true), ec); + if (ec) + { + return; //TODO: handle + } + + m_acceptor.bind(ep, ec); + if (ec) + { + return; //TODO: handle + } + + m_acceptor.listen(socket_base::max_listen_connections, ec); + if (ec) + { + return; //TODO: handle + } +} + +WebSocketServer::WebSocketServer(int port, bool isSecure) + : WebSocketServer(static_cast(port), isSecure) +{ +} + +void WebSocketServer::Start() +{ + if (!m_acceptor.is_open()) + return; + + Accept(); + + m_contextThread = std::thread([self = shared_from_this()]() + { + self->m_context.run(); + }); +} + +void WebSocketServer::Accept() +{ + m_acceptor.async_accept(m_socket, std::bind(&WebSocketServer::OnAccept, shared_from_this(), /*ec*/ _1)); +} + +void WebSocketServer::Stop() +{ + if (m_acceptor.is_open()) + m_acceptor.close(); + + m_contextThread.join(); +} + +void WebSocketServer::OnAccept(error_code ec) +{ + if (ec) + { + //TODO: fail + } + else + { + std::shared_ptr session; + if (m_isSecure) + session = std::shared_ptr(new SecureWebSocketSession(std::move(m_socket), m_callbacks)); + else + session = std::shared_ptr(new WebSocketSession(std::move(m_socket), m_callbacks)); + + m_sessions.push_back(session); + session->Start(); + } + + //TODO: Accept again. + //Accept(); +} + +void WebSocketServer::SetOnConnection(function&& func) +{ + m_callbacks.OnConnection = std::move(func); +} + +void WebSocketServer::SetOnHandshake(function&& func) +{ + m_callbacks.OnHandshake = std::move(func); +} + +void WebSocketServer::SetOnMessage(function&& func) +{ + m_callbacks.OnMessage = std::move(func); +} + +void WebSocketServer::SetMessageFactory(function&& func) +{ + m_callbacks.MessageFactory = std::move(func); +} + +void WebSocketServer::SetOnError(function&& func) +{ + m_callbacks.OnError = std::move(func); +} + +#pragma endregion WebSocketServer + +} } } // Microsoft::React::Test diff --git a/vnext/Desktop.IntegrationTests/WebSocketServer.h b/vnext/Desktop.IntegrationTests/WebSocketServer.h new file mode 100644 index 00000000000..2504441010d --- /dev/null +++ b/vnext/Desktop.IntegrationTests/WebSocketServer.h @@ -0,0 +1,125 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace Microsoft { +namespace React { +namespace Test { + +struct WebSocketServiceCallbacks +{ + std::function OnConnection; + std::function OnHandshake; + std::function OnMessage; + std::function MessageFactory; + std::function OnError; +}; + +struct IWebSocketSession +{ + virtual ~IWebSocketSession() {} + + virtual void Start() = 0; +}; + +template +class BaseWebSocketSession : public IWebSocketSession +{ + enum class State : std::size_t + { + Started, + Stopped + }; + + boost::beast::multi_buffer m_buffer; + std::string m_message; + WebSocketServiceCallbacks& m_callbacks; + State m_state; + + std::function m_errorHandler; + + void Read(); + + void OnAccept(boost::system::error_code ec); + void OnHandshake(boost::beast::websocket::response_type& response); + void OnRead(boost::system::error_code ec, std::size_t transferred); + void OnWrite(boost::system::error_code ec, std::size_t transferred); + +protected: + std::shared_ptr> m_stream; + std::shared_ptr> m_strand; + + void Accept(); + + virtual std::shared_ptr> SharedFromThis() = 0; + +public: + BaseWebSocketSession(WebSocketServiceCallbacks& callbacks); + ~BaseWebSocketSession(); + + virtual void Start() override; +}; + +class WebSocketSession + : public std::enable_shared_from_this + , public BaseWebSocketSession +{ + std::shared_ptr> SharedFromThis() override; + +public: + WebSocketSession(boost::asio::ip::tcp::socket socket, WebSocketServiceCallbacks& callbacks); + ~WebSocketSession(); +}; + +class SecureWebSocketSession + : public std::enable_shared_from_this + , public BaseWebSocketSession> +{ + std::shared_ptr>> SharedFromThis() override; + +public: + SecureWebSocketSession(boost::asio::ip::tcp::socket socket, WebSocketServiceCallbacks& callbacks); + ~SecureWebSocketSession(); + + void OnSslHandshake(boost::system::error_code ec); + + #pragma region IWebSocketSession + + void Start() override; + + #pragma endregion IWebSocketSession +}; + +class WebSocketServer : public std::enable_shared_from_this +{ + std::thread m_contextThread; + boost::asio::io_context m_context; + boost::asio::ip::tcp::acceptor m_acceptor; + boost::asio::ip::tcp::socket m_socket; + WebSocketServiceCallbacks m_callbacks; + std::vector> m_sessions; + bool m_isSecure; + + void Accept(); + + void OnAccept(boost::system::error_code ec); + +public: + WebSocketServer(std::uint16_t port, bool isSecure); + WebSocketServer(int port, bool isSecure = false); + + void Start(); + void Stop(); + + void SetOnConnection(std::function&& func); + void SetOnHandshake(std::function&& func); + void SetOnMessage(std::function&& func); + void SetMessageFactory(std::function&& func); + void SetOnError(std::function&& func); +}; + +} } } // Microsoft::React::Test diff --git a/vnext/Desktop.IntegrationTests/packages.config b/vnext/Desktop.IntegrationTests/packages.config index 108f4b4577d..1fb9d1a1956 100644 --- a/vnext/Desktop.IntegrationTests/packages.config +++ b/vnext/Desktop.IntegrationTests/packages.config @@ -2,7 +2,7 @@ - + - - \ No newline at end of file + + diff --git a/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj b/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj index 1a67937ef88..17ce8f8d9f9 100644 --- a/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj +++ b/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj @@ -1,14 +1,6 @@ - - Debug - x86 - - - Release - x86 - Debug x64 @@ -17,7 +9,6 @@ Release x64 - Debug Win32 @@ -55,7 +46,7 @@ true - BOOST_ASIO_HAS_IOCP;GTEST_LANG_CXX11=1;_WIN32_WINNT=_WIN32_WINNT_WIN7;WIN32;_WINDOWS;REACTNATIVEWIN32_EXPORTS;FOLLY_NO_CONFIG;WIN32_LEAN_AND_MEAN;NOMINMAX;GLOG_NO_ABBREVIATED_SEVERITIES;_HAS_AUTO_PTR_ETC;CHAKRACORE;RN_EXPORT=;JSI_EXPORT=;NOJSC;%(PreprocessorDefinitions) + BOOST_ASIO_HAS_IOCP;GTEST_LANG_CXX11=1;_WIN32_WINNT=_WIN32_WINNT_WIN7;WIN32;_WINDOWS;REACTNATIVEWIN32_EXPORTS;FOLLY_NO_CONFIG;NOMINMAX;GLOG_NO_ABBREVIATED_SEVERITIES;_HAS_AUTO_PTR_ETC;CHAKRACORE;RN_EXPORT=;JSI_EXPORT=;%(PreprocessorDefinitions) ProgramDatabase $(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories) @@ -101,19 +92,19 @@ - - - - + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - + + + + diff --git a/vnext/Desktop.UnitTests/packages.config b/vnext/Desktop.UnitTests/packages.config index 897ea128c47..e83983f0d80 100644 --- a/vnext/Desktop.UnitTests/packages.config +++ b/vnext/Desktop.UnitTests/packages.config @@ -3,5 +3,5 @@ - - \ No newline at end of file + + diff --git a/vnext/Desktop/HttpResource.cpp b/vnext/Desktop/HttpResource.cpp index 4a39e182be6..55323d7b99d 100644 --- a/vnext/Desktop/HttpResource.cpp +++ b/vnext/Desktop/HttpResource.cpp @@ -195,9 +195,9 @@ void HttpResource::SetOnError(std::function&& handler) m_errorHandler = move(handler); } -#pragma endregion // Handler setters +#pragma endregion Handler setters -#pragma endregion // HttpResource members +#pragma endregion HttpResource members } // namespace facebook::react::experimental @@ -208,6 +208,6 @@ void HttpResource::SetOnError(std::function&& handler) return unique_ptr(new experimental::HttpResource()); } -#pragma endregion // IHttpResource static members +#pragma endregion IHttpResource static members } } // namespace facebook::react diff --git a/vnext/Desktop/LazyDevSupportManager.cpp b/vnext/Desktop/LazyDevSupportManager.cpp index f75e425b692..7adbff819bd 100644 --- a/vnext/Desktop/LazyDevSupportManager.cpp +++ b/vnext/Desktop/LazyDevSupportManager.cpp @@ -61,7 +61,7 @@ bool LazyDevSupportManager::HasException() /*override*/ return m_dsm->HasException(); } -#pragma endregion //LazyDevSupportManager +#pragma endregion LazyDevSupportManager std::shared_ptr CreateDevSupportManager() { diff --git a/vnext/Desktop/LazyDevSupportManager.h b/vnext/Desktop/LazyDevSupportManager.h index da732beccdb..3cf39e4a1b5 100644 --- a/vnext/Desktop/LazyDevSupportManager.h +++ b/vnext/Desktop/LazyDevSupportManager.h @@ -30,7 +30,7 @@ class LazyDevSupportManager : public IDevSupportManager void StopPollingLiveReload() override; bool HasException() override; - #pragma endregion // IDevSupportManager + #pragma endregion IDevSupportManager }; } } // namespace facebook::react diff --git a/vnext/Desktop/LegacyWebSocket.cpp b/vnext/Desktop/LegacyWebSocket.cpp index eab28858364..21b6a783d35 100644 --- a/vnext/Desktop/LegacyWebSocket.cpp +++ b/vnext/Desktop/LegacyWebSocket.cpp @@ -347,7 +347,7 @@ void LegacyBaseWebSocket::Ping() }); } -#pragma endregion // IWebSocket members +#pragma endregion IWebSocket members #pragma region Handler setters @@ -393,9 +393,9 @@ IWebSocket::ReadyState LegacyBaseWebSocket::GetReady return m_readyState; } -#pragma endregion // Handler setters +#pragma endregion Handler setters -#pragma endregion // LegacyBaseWebSocket members +#pragma endregion LegacyBaseWebSocket members #pragma region LegacyWebSocket members @@ -441,7 +441,7 @@ void LegacySecureWebSocket::Handshake(const IWebSock template class LegacySecureWebSocket>; -#pragma endregion // LegacySecureWebSocket members +#pragma endregion LegacySecureWebSocket members #pragma region IWebSocket static members @@ -467,7 +467,7 @@ template class LegacySecureWebSocket>; throw std::exception((string("Incorrect url protocol: ") + url.scheme).c_str()); } -#pragma endregion // IWebSocket static members +#pragma endregion IWebSocket static members } } // namespace Microsoft:React diff --git a/vnext/Desktop/Modules/NetworkingModule.cpp b/vnext/Desktop/Modules/NetworkingModule.cpp index a7df57679ad..d5ea9ed9191 100644 --- a/vnext/Desktop/Modules/NetworkingModule.cpp +++ b/vnext/Desktop/Modules/NetworkingModule.cpp @@ -143,6 +143,6 @@ vector NetworkingModule::getMethods( }; } -#pragma endregion // CxxModule members +#pragma endregion CxxModule members } } // namespace facebook::react diff --git a/vnext/Desktop/Modules/NetworkingModule.h b/vnext/Desktop/Modules/NetworkingModule.h index a1b3639b3e3..0662dc1b83a 100644 --- a/vnext/Desktop/Modules/NetworkingModule.h +++ b/vnext/Desktop/Modules/NetworkingModule.h @@ -32,7 +32,7 @@ class NetworkingModule : public facebook::xplat::module::CxxModule std::map getConstants() override; std::vector getMethods() override; - #pragma endregion // CxxModule members + #pragma endregion CxxModule members static const char* name; }; diff --git a/vnext/Desktop/React.Windows.Desktop.vcxproj b/vnext/Desktop/React.Windows.Desktop.vcxproj index 73fa5d5f91e..7fe7aa58a39 100644 --- a/vnext/Desktop/React.Windows.Desktop.vcxproj +++ b/vnext/Desktop/React.Windows.Desktop.vcxproj @@ -1,14 +1,6 @@ - - Debug - x86 - - - Release - x86 - Debug x64 @@ -17,7 +9,6 @@ Release x64 - Debug Win32 @@ -31,9 +22,6 @@ {95048601-C3DC-475F-ADF8-7C0C764C10D5} React.Windows.Desktop - - true - true @@ -64,24 +52,17 @@ - BOOST_ASIO_HAS_IOCP;_WINSOCK_DEPRECATED_NO_WARNINGS;_WIN32_WINNT=_WIN32_WINNT_WIN7;WIN32;_WINDOWS;REACTNATIVEWIN32_EXPORTS;FOLLY_NO_CONFIG;WIN32_LEAN_AND_MEAN;NOMINMAX;GLOG_NO_ABBREVIATED_SEVERITIES;_HAS_AUTO_PTR_ETC;CHAKRACORE;RN_PLATFORM=win32;RN_EXPORT=;JSI_EXPORT=;%(PreprocessorDefinitions) + BOOST_ASIO_HAS_IOCP;_WINSOCK_DEPRECATED_NO_WARNINGS;_WIN32_WINNT=_WIN32_WINNT_WIN7;WIN32;_WINDOWS;REACTNATIVEWIN32_EXPORTS;FOLLY_NO_CONFIG;NOMINMAX;GLOG_NO_ABBREVIATED_SEVERITIES;_HAS_AUTO_PTR_ETC;CHAKRACORE;RN_PLATFORM=win32;RN_EXPORT=;JSI_EXPORT=;%(PreprocessorDefinitions) ProgramDatabase %(AdditionalOptions) /Zc:strictStrings /bigobj - ..\build\$(IntDir)\%(RelativeDir) Use pch.h - Windows Shlwapi.lib;%(AdditionalDependencies) -minpdbpathlen:256 - - - NOJSC;%(PreprocessorDefinitions) - - OSS_RN;FOLLY_MOBILE=1;ENUM_BITFIELDS_NOT_SUPPORTED%(PreprocessorDefinitions) @@ -114,7 +95,10 @@ - + + + NOJSC;%(PreprocessorDefinitions) + @@ -159,20 +143,20 @@ - - - - - + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - + + + + + \ No newline at end of file diff --git a/vnext/Desktop/Sandbox/SandboxBridge.h b/vnext/Desktop/Sandbox/SandboxBridge.h index ac05d9d7dbf..ac0c6e676c8 100644 --- a/vnext/Desktop/Sandbox/SandboxBridge.h +++ b/vnext/Desktop/Sandbox/SandboxBridge.h @@ -8,10 +8,6 @@ #include #include -#if !defined(NOJSC) -#include -#endif - #include namespace folly { diff --git a/vnext/Desktop/WebSocket.cpp b/vnext/Desktop/WebSocket.cpp index 0d192c1a816..c3d571d81b2 100644 --- a/vnext/Desktop/WebSocket.cpp +++ b/vnext/Desktop/WebSocket.cpp @@ -31,8 +31,7 @@ using std::unique_ptr; using boostecr = boost::system::error_code const&; -namespace Microsoft { -namespace React { +namespace Microsoft::React { #pragma region BaseWebSocket members @@ -393,7 +392,7 @@ void BaseWebSocket::Ping() PerformPing(); } -#pragma endregion // IWebSocket members +#pragma endregion IWebSocket members #pragma region Handler setters @@ -439,9 +438,9 @@ IWebSocket::ReadyState BaseWebSocket::G return m_readyState; } -#pragma endregion // Handler setters +#pragma endregion Handler setters -#pragma endregion // BaseWebSocket members +#pragma endregion BaseWebSocket members #pragma region WebSocket members @@ -479,7 +478,7 @@ void SecureWebSocket::Handshake(const IWebSocket::Options& options) }); } -#pragma endregion // SecureWebSocket members +#pragma endregion SecureWebSocket members #pragma region IWebSocket static members @@ -505,7 +504,7 @@ void SecureWebSocket::Handshake(const IWebSocket::Options& options) throw std::exception((string("Incorrect url protocol: ") + url.scheme).c_str()); } -#pragma endregion // IWebSocket static members +#pragma endregion IWebSocket static members namespace Test { @@ -616,7 +615,7 @@ MockStream::async_close(websocket::close_reason const& cr, CloseHandler&& handle return init.result.get(); } -#pragma endregion // MockStream +#pragma endregion MockStream #pragma region TestWebSocket @@ -641,13 +640,12 @@ void TestWebSocket::SetCloseResult(function&& resultFunc) m_stream->CloseResult = std::move(resultFunc); } -#pragma endregion // TestWebSocket +#pragma endregion TestWebSocket } // namespace Microsoft::React::Test -} } // namespace Microsoft::React +} // namespace Microsoft::React -namespace boost { -namespace asio { +namespace boost::asio { // See (776) template @@ -667,6 +665,6 @@ async_connect handler(s.ConnectResult(), {}); } -} } // namespace boost::asio +} // namespace boost::asio #pragma warning(pop) diff --git a/vnext/Desktop/WebSocket.h b/vnext/Desktop/WebSocket.h index 90ea097a76f..b72172a9438 100644 --- a/vnext/Desktop/WebSocket.h +++ b/vnext/Desktop/WebSocket.h @@ -10,8 +10,7 @@ #include "IWebSocket.h" #include "Utils.h" -namespace Microsoft { -namespace React { +namespace Microsoft::React { template < @@ -33,9 +32,9 @@ class BaseWebSocket : public IWebSocket boost::beast::multi_buffer m_bufferIn; std::thread m_contextThread; - /// - // Must be modified exclusively from the context thread. - /// + /// + /// Must be modified exclusively from the context thread. + /// std::queue> m_writeRequests; std::atomic_size_t m_pingRequests { 0 }; @@ -49,51 +48,146 @@ class BaseWebSocket : public IWebSocket std::atomic_bool m_pingInProgress { false }; std::atomic_bool m_writeInProgress { false }; + /// + /// Add the message to a write queue for eventual sending. + /// + /// + /// Payload to send to the remote endpoint. + /// + /// + /// Indicates whether the payload should be treated as binary data, or text. + /// void EnqueueWrite(const std::string& message, bool binary); + + /// + /// Dequeues a message from m_writeRequests and sends it asynchronously. + /// void PerformWrite(); + + /// + /// If this instance is considered open, post a read request into m_bufferIn. + /// If there is an incoming message and m_readHandler is set, call the handler. + /// Then, post new call to this method to read further incoming data. + /// void PerformRead(); + + /// + /// If there are pending ping requests, post an asynchronous ping. + /// Invoke m_pingHandler if set. + /// Call this method again if there are still pending requests. + /// void PerformPing(); + + /// + /// Set the ready state to Closing. + /// Post a close request for this stream. + /// Stop this instance to drop any future read or write requests. + /// void PerformClose(); - /// - // Synchronizes the context thread and allows the io_context to stop dispatching tasks. - /// + /// + /// Synchronizes the context thread and allows the io_context to stop dispatching tasks. + /// void Stop(); boost::beast::websocket::close_code ToBeastCloseCode(IWebSocket::CloseCode closeCode); protected: - std::function m_errorHandler; - + /// + /// See https://www.boost.org/doc/libs/1_68_0/doc/html/boost_asio/reference/io_context.html. + /// + /// Dispatches tasks posted either by + /// or arbitrary lambdas using boost::asio::post. + /// + /// + /// Tasks will be run in the thread that calls this object's run method. + /// boost::asio::io_context m_context; + std::unique_ptr> m_workGuard; std::unique_ptr m_stream; + std::function m_errorHandler; BaseWebSocket(Url&& url); ~BaseWebSocket() override; + /// + /// Finalizes the connection setup to the remote endpoint. + /// Sets the ready state to Open. + /// + /// + /// On callback, invokes the connect handler, if set. + /// Performs a pending write, if requested during the connection process. + /// Performs a pending ping call, if requested during the connection process. + /// Closes this instance, if requested during the connection process. + /// + /// + /// Map of HTTP header fields sent by the remote endpoint. + /// virtual void Handshake(const IWebSocket::Options& options); public: - #pragma region IWebSocket members + #pragma region IWebSocket + /// + /// + /// void Connect(const Protocols& protocols, const Options& options) override; + + /// + /// + /// void Ping() override; + + /// + /// + /// void Send(const std::string& message) override; + + /// + /// + /// void SendBinary(const std::string& base64String) override; + + /// + /// + /// void Close(CloseCode code, const std::string& reason) override; ReadyState GetReadyState() const override; + /// + /// + /// void SetOnConnect(std::function&& handler) override; + + /// + /// + /// void SetOnPing(std::function&& handler) override; + + /// + /// + /// void SetOnSend(std::function&& handler) override; + + /// + /// + /// void SetOnMessage(std::function&& handler) override; + + /// + /// + /// void SetOnClose(std::function&& handler) override; + + /// + /// + /// void SetOnError(std::function&& handler) override; - #pragma endregion + #pragma endregion IWebSocket }; class WebSocket @@ -117,7 +211,9 @@ class SecureWebSocket : public BaseWebSocket +/// +/// See . +/// class MockStream { boost::asio::io_context& m_context; @@ -171,7 +267,7 @@ class MockStream BOOST_ASIO_INITFN_RESULT_TYPE(CloseHandler, void(boost::system::error_code)) async_close(boost::beast::websocket::close_reason const& cr, CloseHandler&& handler); - #pragma endregion // boost::beast::websocket::stream mocks + #pragma endregion boost::beast::websocket::stream mocks std::function ConnectResult; std::function HandshakeResult; @@ -199,4 +295,4 @@ class TestWebSocket } // namespace Microsoft::React::Test -} } // namespace Microsoft::React +} // namespace Microsoft::React diff --git a/vnext/Desktop/WebSocketJSExecutor.cpp b/vnext/Desktop/WebSocketJSExecutor.cpp index 34e9b6a06a8..4f87f03ef4f 100644 --- a/vnext/Desktop/WebSocketJSExecutor.cpp +++ b/vnext/Desktop/WebSocketJSExecutor.cpp @@ -376,6 +376,6 @@ bool WebSocketJSExecutor::IsInError() const noexcept return m_state == State::Error; } -#pragma endregion // private members +#pragma endregion private members }} // namespace facebook::react diff --git a/vnext/Desktop/WebSocketJSExecutorFactory.cpp b/vnext/Desktop/WebSocketJSExecutorFactory.cpp index 01c14b466a6..71ebc998bd9 100644 --- a/vnext/Desktop/WebSocketJSExecutorFactory.cpp +++ b/vnext/Desktop/WebSocketJSExecutorFactory.cpp @@ -26,6 +26,6 @@ std::unique_ptr WebSocketJSExecutorFactory::createJSExecutor( return std::unique_ptr(new WebSocketJSExecutor(delegate, jsQueue)); } -#pragma endregion // WebSocketJSExecutorFactory members +#pragma endregion WebSocketJSExecutorFactory members }} // namespace facebook::react diff --git a/vnext/Desktop/WebSocketModule.cpp b/vnext/Desktop/WebSocketModule.cpp index 5bafd2c26e4..0fcf46c2b0c 100644 --- a/vnext/Desktop/WebSocketModule.cpp +++ b/vnext/Desktop/WebSocketModule.cpp @@ -15,8 +15,13 @@ using namespace folly; using std::string; -namespace Microsoft { -namespace React { +namespace { + +constexpr char moduleName[] = "WebSocketModule"; + +} // anonymous namespace + +namespace Microsoft::React { WebSocketModule::WebSocketModule() { @@ -24,7 +29,7 @@ WebSocketModule::WebSocketModule() string WebSocketModule::getName() { - return "WebSocketModule"; + return moduleName; } std::map WebSocketModule::getConstants() @@ -59,15 +64,15 @@ std::vector WebSocketModule::getMeth } } - this->GetWebSocket(jsArgAsInt(args, 3), jsArgAsString(args, 0))->Connect(protocols, options); + this->GetOrCreateWebSocket(jsArgAsInt(args, 3), jsArgAsString(args, 0))->Connect(protocols, options); }), Method("close", [this](dynamic args) // [int64_t code, string reason,] int64_t id { // See react-native\Libraries\WebSocket\WebSocket.js:_close if (args.size() == 3) // WebSocketModule.close(statusCode, closeReason, this._socketId); - this->GetWebSocket(jsArgAsInt(args, 2))->Close(static_cast(jsArgAsInt(args, 0)), jsArgAsString(args, 1)); + this->GetOrCreateWebSocket(jsArgAsInt(args, 2))->Close(static_cast(jsArgAsInt(args, 0)), jsArgAsString(args, 1)); else if (args.size() == 1) // WebSocketModule.close(this._socketId); - this->GetWebSocket(jsArgAsInt(args, 0))->Close(IWebSocket::CloseCode::Normal, {}); + this->GetOrCreateWebSocket(jsArgAsInt(args, 0))->Close(IWebSocket::CloseCode::Normal, {}); else { auto errorObj = dynamic::object("id", -1)("message", "Incorrect number of parameters"); @@ -76,15 +81,15 @@ std::vector WebSocketModule::getMeth }), Method("send", [this](dynamic args) // const string& message, int64_t id { - this->GetWebSocket(jsArgAsInt(args, 1))->Send(jsArgAsString(args, 0)); + this->GetOrCreateWebSocket(jsArgAsInt(args, 1))->Send(jsArgAsString(args, 0)); }), Method("sendBinary", [this](dynamic args) // const string& base64String, int64_t id { - this->GetWebSocket(jsArgAsInt(args, 1))->SendBinary(jsArgAsString(args, 0)); + this->GetOrCreateWebSocket(jsArgAsInt(args, 1))->SendBinary(jsArgAsString(args, 0)); }), Method("ping", [this](dynamic args) // int64_t id { - this->GetWebSocket(jsArgAsInt(args, 0))->Ping(); + this->GetOrCreateWebSocket(jsArgAsInt(args, 0))->Ping(); }) }; }//getMethods @@ -98,7 +103,7 @@ void WebSocketModule::SendEvent(string&& eventName, dynamic&& args) instance->callJSFunction("RCTDeviceEventEmitter", "emit", dynamic::array(std::move(eventName), std::move(args))); } -IWebSocket* WebSocketModule::GetWebSocket(int64_t id, string&& url) +IWebSocket* WebSocketModule::GetOrCreateWebSocket(int64_t id, string&& url) { IWebSocket* ptr = nullptr; if (m_webSockets.find(id) == m_webSockets.end()) @@ -136,11 +141,11 @@ IWebSocket* WebSocketModule::GetWebSocket(int64_t id, string&& url) return ptr; } -#pragma endregion // private members +#pragma endregion private members std::unique_ptr CreateWebSocketModule() noexcept { return std::make_unique(); } -} } // Microsoft::React +} // Microsoft::React diff --git a/vnext/Desktop/packages.config b/vnext/Desktop/packages.config index 108f4b4577d..1fb9d1a1956 100644 --- a/vnext/Desktop/packages.config +++ b/vnext/Desktop/packages.config @@ -2,7 +2,7 @@ - + - - \ No newline at end of file + + diff --git a/vnext/Directory.Build.props b/vnext/Directory.Build.props index d0fbeb4293d..4018caa7c46 100644 --- a/vnext/Directory.Build.props +++ b/vnext/Directory.Build.props @@ -8,33 +8,30 @@ Debug $(MSBuildThisFileDirectory) + $(ReactNativeWindowsDir)node_modules\react-native\folly + $(ReactNativeWindowsDir)node_modules\react-native + $(ReactNativeWindowsDir)node_modules\react-native\ReactCommon\yoga - v141 $(MSBuildProjectName) - - x86 - $(ReactNativeWindowsDir)build\$(Platform)\$(Configuration) - $(ReactNativeWindowsDir)target\$(Platform)\$(Configuration) + $(ReactNativeWindowsDir)build\$(Platform)\$(Configuration) + $(ReactNativeWindowsDir)build\x86\$(Configuration) + $(ReactNativeWindowsDir)target\$(Platform)\$(Configuration) + $(ReactNativeWindowsDir)target\x86\$(Configuration) - $(BaseIntDir)\$(ProjectName)\ $(BaseOutDir)\$(ProjectName)\ - - - $(ReactNativeWindowsDir)node_modules\react-native\folly - $(ReactNativeWindowsDir)node_modules\react-native - $(ReactNativeWindowsDir)node_modules\react-native\ReactCommon\yoga + $(IntDir)Generated Files\ $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), app.json)) - + diff --git a/vnext/Directory.Build.targets b/vnext/Directory.Build.targets index 23efe85aff1..a93bc8eb44d 100644 --- a/vnext/Directory.Build.targets +++ b/vnext/Directory.Build.targets @@ -1,21 +1,38 @@ - - - x86 - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/vnext/Folly/Folly.vcxproj b/vnext/Folly/Folly.vcxproj index 882f95b7791..7b53ce7e7ba 100644 --- a/vnext/Folly/Folly.vcxproj +++ b/vnext/Folly/Folly.vcxproj @@ -5,10 +5,6 @@ Debug ARM - - Debug - x86 - Debug x64 @@ -17,15 +13,10 @@ Release ARM - - Release - x86 - Release x64 - Debug Win32 @@ -309,13 +300,13 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + diff --git a/vnext/FollyWin32/FollyWin32.vcxproj b/vnext/FollyWin32/FollyWin32.vcxproj index 0f4b53786a8..808721b657e 100644 --- a/vnext/FollyWin32/FollyWin32.vcxproj +++ b/vnext/FollyWin32/FollyWin32.vcxproj @@ -1,14 +1,6 @@  - - Debug - x86 - - - Release - x86 - Debug x64 @@ -17,7 +9,6 @@ Release x64 - Debug Win32 @@ -62,7 +53,7 @@ - _HAS_AUTO_PTR_ETC=1;FOLLY_NO_CONFIG;NOMINMAX;NOJSC;WIN32;%(PreprocessorDefinitions) + _HAS_AUTO_PTR_ETC=1;FOLLY_NO_CONFIG;NOMINMAX;WIN32;%(PreprocessorDefinitions) $(FollyDir) diff --git a/vnext/IntegrationTests/React.Windows.IntegrationTests.vcxproj b/vnext/IntegrationTests/React.Windows.IntegrationTests.vcxproj index c2ac6fc70be..4679473d505 100644 --- a/vnext/IntegrationTests/React.Windows.IntegrationTests.vcxproj +++ b/vnext/IntegrationTests/React.Windows.IntegrationTests.vcxproj @@ -5,10 +5,6 @@ Debug ARM - - Debug - x86 - Debug x64 @@ -17,15 +13,10 @@ Release ARM - - Release - x86 - Release x64 - Debug Win32 @@ -63,7 +54,7 @@ /Zc:twoPhase- %(AdditionalOptions) NotUsing - FOLLY_NO_CONFIG;RN_EXPORT=;NOJSC;%(PreprocessorDefinitions) + FOLLY_NO_CONFIG;RN_EXPORT=;%(PreprocessorDefinitions) false @@ -80,10 +71,16 @@ - + + + NOJSC;%(PreprocessorDefinitions) + - + + + NOJSC;%(PreprocessorDefinitions) + @@ -99,13 +96,13 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + diff --git a/vnext/IntegrationTests/TestInstance.cpp b/vnext/IntegrationTests/TestInstance.cpp index a6cd7acab9f..c69adf24bf5 100644 --- a/vnext/IntegrationTests/TestInstance.cpp +++ b/vnext/IntegrationTests/TestInstance.cpp @@ -73,7 +73,7 @@ dynamic TestViewManager::GetExportedCustomDirectEventTypeConstants() const return dynamic::object(); } -#pragma endregion // TestViewManager members +#pragma endregion TestViewManager members #pragma region TestNativeUIManager members @@ -113,7 +113,7 @@ void TestNativeUIManager::ReplaceView(facebook::react::ShadowNode& shadowNode) { void TestNativeUIManager::UpdateView(facebook::react::ShadowNode& shadowNode, folly::dynamic /*ReadableMap*/ props) {} -#pragma endregion // TestNativeUIManager members +#pragma endregion TestNativeUIManager members #pragma region TestShadowNode members diff --git a/vnext/IntegrationTests/TestInstance.h b/vnext/IntegrationTests/TestInstance.h index 49d92738438..c09277a0f17 100644 --- a/vnext/IntegrationTests/TestInstance.h +++ b/vnext/IntegrationTests/TestInstance.h @@ -46,7 +46,7 @@ class TestViewManager : public facebook::react::IViewManager folly::dynamic GetExportedCustomBubblingEventTypeConstants() const override; folly::dynamic GetExportedCustomDirectEventTypeConstants() const override; - #pragma endregion // IViewManager members + #pragma endregion IViewManager members }; class TestNativeUIManager : public facebook::react::INativeUIManager @@ -81,7 +81,7 @@ class TestShadowNode : public facebook::react::ShadowNode void RemoveChildAt(int64_t indexToRemove) override; void createView() override; - #pragma endregion // ShadowNode overrides + #pragma endregion ShadowNode overrides }; } } } // namespace facebook::react::test diff --git a/vnext/IntegrationTests/TestModule.cpp b/vnext/IntegrationTests/TestModule.cpp index 9ba5f7e5f5b..46d4f3a4133 100644 --- a/vnext/IntegrationTests/TestModule.cpp +++ b/vnext/IntegrationTests/TestModule.cpp @@ -45,7 +45,7 @@ void TestModule::shouldResolve() { } -#pragma endregion // TestModule.js methods +#pragma endregion TestModule.js methods string TestModule::getName() { @@ -80,7 +80,7 @@ vector TestModule::getMethods() }; } -#pragma endregion // TestModule members +#pragma endregion TestModule members #pragma region TestDeviceInfoModule members @@ -108,6 +108,6 @@ auto TestDeviceInfoModule::getMethods() -> vector return {}; } -#pragma endregion // TestDeviceInfoModule members +#pragma endregion TestDeviceInfoModule members } } } // namespace facebook::react::test diff --git a/vnext/IntegrationTests/TestModule.h b/vnext/IntegrationTests/TestModule.h index 62a3214b373..88a20d1fe00 100644 --- a/vnext/IntegrationTests/TestModule.h +++ b/vnext/IntegrationTests/TestModule.h @@ -31,7 +31,7 @@ class TestModule : public facebook::xplat::module::CxxModule void shouldResolve(); - #pragma endregion // TestModule.js methods + #pragma endregion TestModule.js methods #pragma region CxxModule members @@ -41,7 +41,7 @@ class TestModule : public facebook::xplat::module::CxxModule std::vector getMethods() override; - #pragma endregion // CxxModule members + #pragma endregion CxxModule members }; class TestDeviceInfoModule : public facebook::xplat::module::CxxModule diff --git a/vnext/NuGet.Config b/vnext/NuGet.Config index 9a849e18bbd..a6d079d69b4 100644 --- a/vnext/NuGet.Config +++ b/vnext/NuGet.Config @@ -1,9 +1,10 @@ + + + - - - \ No newline at end of file + diff --git a/vnext/Playground/NuGet.Config b/vnext/Playground/NuGet.Config new file mode 100644 index 00000000000..b48089a359b --- /dev/null +++ b/vnext/Playground/NuGet.Config @@ -0,0 +1,6 @@ + + + + + + diff --git a/vnext/PropertySheets/React.Cpp.props b/vnext/PropertySheets/React.Cpp.props index 07cc53df30e..185cd0daba9 100644 --- a/vnext/PropertySheets/React.Cpp.props +++ b/vnext/PropertySheets/React.Cpp.props @@ -10,8 +10,7 @@ - v141 - v142 + $(DefaultPlatformToolset) false Unicode @@ -32,15 +31,7 @@ BOOST_SYSTEM_SOURCE - Build boost::system symbols from sources (drop dependency on boost_system.lib). BOOST_ERROR_CODE_HEADER_ONLY - Compile Boost error_code members inline. Requires BOOST_SYSTEM_SOURCE. --> - BOOST_SYSTEM_SOURCE;BOOST_ERROR_CODE_HEADER_ONLY;%(PreprocessorDefinitions) - stdcpp14 - - - - - - - _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;%(PreprocessorDefinitions) + WIN32_LEAN_AND_MEAN;_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;BOOST_SYSTEM_SOURCE;BOOST_ERROR_CODE_HEADER_ONLY;%(PreprocessorDefinitions) stdcpp17 @@ -51,7 +42,7 @@ - + WITH_OFFICE_TRACING=0;%(PreprocessorDefinitions) diff --git a/vnext/ReactCommon/ReactCommon.vcxproj b/vnext/ReactCommon/ReactCommon.vcxproj index 4dbf523cdac..78157efe835 100644 --- a/vnext/ReactCommon/ReactCommon.vcxproj +++ b/vnext/ReactCommon/ReactCommon.vcxproj @@ -5,10 +5,6 @@ Debug ARM - - Debug - x86 - Debug x64 @@ -17,15 +13,10 @@ Release ARM - - Release - x86 - Release x64 - Debug Win32 @@ -44,9 +35,6 @@ Windows Store 10.0 - - true - StaticLibrary @@ -66,11 +54,6 @@ false - - - NOJSC;%(PreprocessorDefinitions) - - OSS_RN;FOLLY_MOBILE=1;ENUM_BITFIELDS_NOT_SUPPORTED;%(PreprocessorDefinitions) @@ -95,7 +78,7 @@ - + @@ -110,16 +93,6 @@ - - - - - - - - - - @@ -133,15 +106,8 @@ - - - - - - - - + @@ -150,7 +116,7 @@ - + @@ -160,33 +126,27 @@ - - - - - - - - - + + + NOJSC;%(PreprocessorDefinitions) + - - - - - - + + true + - + + true + @@ -208,7 +168,7 @@ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + diff --git a/vnext/ReactUWP/Base/UwpReactInstance.cpp b/vnext/ReactUWP/Base/UwpReactInstance.cpp index 9b925f011b0..2f7202d77fa 100644 --- a/vnext/ReactUWP/Base/UwpReactInstance.cpp +++ b/vnext/ReactUWP/Base/UwpReactInstance.cpp @@ -46,7 +46,9 @@ // Modules #include #include +#include #include +#include #include #include #include @@ -64,6 +66,11 @@ #include #include +#if !defined(OSS_RN) +#include +#include +#endif + #if !defined(OSS_RN) #include "ChakraJSIRuntimeHolder.h" #endif @@ -131,7 +138,9 @@ std::vector GetModules( std::shared_ptr deviceInfo, std::shared_ptr devSettings, const I18nModule::I18nInfo&& i18nInfo, - std::shared_ptr appstate) + std::shared_ptr appstate, + std::shared_ptr appTheme, + std::weak_ptr uwpInstance) { // Modules std::vector modules; @@ -181,11 +190,21 @@ std::vector GetModules( [appstate = std::move(appstate)]() mutable { return std::make_unique(std::move(appstate)); }, std::make_shared()); + modules.emplace_back( + react::windows::AppThemeModule::name, + [appTheme = std::move(appTheme)]() mutable { return std::make_unique(std::move(appTheme)); }, + messageQueue); + modules.emplace_back( ClipboardModule::name, []() { return std::make_unique(); }, messageQueue); + modules.emplace_back( + NativeAnimatedModule::name, + [uwpInstance = std::move(uwpInstance)]() mutable { return std::make_unique(std::move(uwpInstance)); }, + messageQueue); + modules.emplace_back( "I18nManager", [i18nInfo = std::move(i18nInfo)]() mutable { return createI18nModule(std::make_unique(std::move(i18nInfo))); }, @@ -213,13 +232,14 @@ void UwpReactInstance::Start(const std::shared_ptr& spThis, cons // Objects that must be created on the UI thread std::shared_ptr deviceInfo = std::make_shared(); std::shared_ptr appstate = std::make_shared(spThis); + std::shared_ptr appTheme = std::make_shared(spThis, m_defaultNativeThread); std::pair i18nInfo = I18nModule::GetI18nInfo(); // TODO: Figure out threading. What thread should this really be on? m_initThread = std::make_unique(); m_jsThread = std::static_pointer_cast(m_initThread); m_initThread->runOnQueueSync( - [this, spThis, deviceInfo, settings, i18nInfo = std::move(i18nInfo), appstate = std::move(appstate)]() mutable + [this, spThis, deviceInfo, settings, i18nInfo = std::move(i18nInfo), appstate = std::move(appstate), appTheme = std::move(appTheme)]() mutable { // Setup DevSettings based on our own internal structure auto devSettings(std::make_shared()); @@ -231,6 +251,12 @@ void UwpReactInstance::Start(const std::shared_ptr& spThis, cons devSettings->useJITCompilation = settings.EnableJITCompilation; devSettings->debugHost = settings.DebugHost; + // In most cases, using the hardcoded ms-appx URI works fine, but there are certain scenarios, + // such as in optional packaging, where the developer might need to modify the path, in which + // case we should use the custom path instead. + devSettings->bundleRootPath = settings.BundleRootPath.empty() ? "ms-appx:///Bundle/" : settings.BundleRootPath; + m_bundleRootPath = devSettings->bundleRootPath; + if (settings.UseLiveReload) { devSettings->liveReloadCallback = [weakThis = std::weak_ptr(spThis)]() noexcept @@ -261,7 +287,7 @@ void UwpReactInstance::Start(const std::shared_ptr& spThis, cons m_uiManager = CreateUIManager(spThis, m_viewManagerProvider); // Acquire default modules and then populate with custom modules - std::vector cxxModules = GetModules(m_uiManager, m_defaultNativeThread, deviceInfo, devSettings, std::move(i18nInfo), std::move(appstate)); + std::vector cxxModules = GetModules(m_uiManager, m_defaultNativeThread, deviceInfo, devSettings, std::move(i18nInfo), std::move(appstate), std::move(appTheme), std::weak_ptr(spThis)); if (m_moduleProvider != nullptr) { @@ -273,7 +299,20 @@ void UwpReactInstance::Start(const std::shared_ptr& spThis, cons #if !defined(OSS_RN) if (settings.UseJsi) - devSettings->jsiRuntimeHolder = std::make_shared(devSettings, jsQueue, nullptr, nullptr); + { + std::unique_ptr scriptStore = nullptr; + std::unique_ptr preparedScriptStore = nullptr; + + if (settings.EnableByteCodeCacheing || !settings.ByteCodeFileUri.empty()) { + scriptStore = std::make_unique(); + preparedScriptStore = std::make_unique(winrt::to_hstring(settings.ByteCodeFileUri)); + } + devSettings->jsiRuntimeHolder = std::make_shared( + devSettings, + jsQueue, + std::move(scriptStore), + std::move(preparedScriptStore)); + } #endif try diff --git a/vnext/ReactUWP/Base/UwpReactInstance.h b/vnext/ReactUWP/Base/UwpReactInstance.h index 16087f05c22..ed24dfe6389 100644 --- a/vnext/ReactUWP/Base/UwpReactInstance.h +++ b/vnext/ReactUWP/Base/UwpReactInstance.h @@ -53,6 +53,7 @@ class UwpReactInstance : public IReactInstance, public ::std::enable_shared_from const std::string& LastErrorMessage() const noexcept override { return m_errorMessage; } void loadBundle(std::string&& jsBundleRelativePath) override { if (!m_isInError) m_instanceWrapper->loadBundle(std::move(jsBundleRelativePath)); }; ExpressionAnimationStore& GetExpressionAnimationStore() override { return m_expressionAnimationStore; } + std::string GetBundleRootPath() const noexcept override { return m_bundleRootPath; } // Test hooks void SetXamlViewCreatedTestHook(std::function testHook) override; @@ -82,6 +83,8 @@ class UwpReactInstance : public IReactInstance, public ::std::enable_shared_from ExpressionAnimationStore m_expressionAnimationStore; std::function m_xamlViewCreatedTestHook; + + std::string m_bundleRootPath; }; } } diff --git a/vnext/ReactUWP/EndPoints/dll/dllmain.cpp b/vnext/ReactUWP/EndPoints/dll/dllmain.cpp index c4da51d229a..4372afdf243 100644 --- a/vnext/ReactUWP/EndPoints/dll/dllmain.cpp +++ b/vnext/ReactUWP/EndPoints/dll/dllmain.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // module.cpp : Defines the module that contains the com classes @@ -7,6 +7,10 @@ #include +extern int32_t WINRT_CALL WINRT_CanUnloadNow() noexcept; + +extern int32_t WINRT_CALL WINRT_GetActivationFactory(void* classId, void** factory) noexcept; + extern "C" HRESULT WINAPI DllCanUnloadNow(); #if !defined(__WRL_CLASSIC_COM__) @@ -14,8 +18,15 @@ extern "C" HRESULT WINAPI DllGetActivationFactory(_In_ HSTRING, _Deref_out_ IAct extern "C" HRESULT WINAPI DllGetActivationFactory(_In_ HSTRING activatibleClassId, _Deref_out_ IActivationFactory** factory) { - auto &module = Microsoft::WRL::Module::GetModule(); - return module.GetActivationFactory(activatibleClassId, factory); + HRESULT hr = WINRT_GetActivationFactory((void*)activatibleClassId, (void**)factory); + + if (hr != S_OK) + { + auto &module = Microsoft::WRL::Module::GetModule(); + hr = module.GetActivationFactory(activatibleClassId, factory); + } + + return hr; } #endif @@ -31,8 +42,15 @@ extern "C" HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, _Deref extern "C" HRESULT WINAPI DllCanUnloadNow() { - const auto &module = Microsoft::WRL::Module::GetModule(); - return module.GetObjectCount() == 0 ? S_OK : S_FALSE; + HRESULT hr = WINRT_CanUnloadNow(); + + if (hr == S_OK) + { + const auto &module = Microsoft::WRL::Module::GetModule(); + hr = module.GetObjectCount() == 0 ? S_OK : S_FALSE; + } + + return hr; } #if defined(_M_IX86) @@ -51,4 +69,4 @@ extern "C" HRESULT WINAPI DllCanUnloadNow() #pragma comment(linker, "/EXPORT:DllGetClassObject,PRIVATE") #endif #pragma comment(linker, "/EXPORT:DllCanUnloadNow,PRIVATE") -#endif \ No newline at end of file +#endif diff --git a/vnext/ReactUWP/Modules/Animated/AdditionAnimatedNode.cpp b/vnext/ReactUWP/Modules/Animated/AdditionAnimatedNode.cpp new file mode 100644 index 00000000000..c093058b172 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/AdditionAnimatedNode.cpp @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "AdditionAnimatedNode.h" +#include "NativeAnimatedNodeManager.h" + +namespace react { + namespace uwp { + AdditionAnimatedNode::AdditionAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager) : ValueAnimatedNode(tag, config, manager) + { + for (const auto& inputNode : config.find(s_inputName).dereference().second) + { + m_inputNodes.insert(static_cast(inputNode.asDouble())); + } + + m_propertySet.StartAnimation(s_valueName, + [nodes = m_inputNodes, manager]() + { + const auto anim = winrt::Window::Current().Compositor().CreateExpressionAnimation(); + + anim.Expression([nodes, manager, anim]() + { + winrt::hstring expr = L"0"; + for (const auto tag : nodes) + { + const auto identifier = std::to_wstring(tag); + anim.SetReferenceParameter(identifier, manager->GetValueAnimatedNode(tag)->PropertySet()); + expr = expr + L" + " + identifier + L"." + s_valueName + L" + " + identifier + L"." + s_offsetName; + } + return expr; + }()); + return anim; + }() + ); + } + } +} diff --git a/vnext/ReactUWP/Modules/Animated/AdditionAnimatedNode.h b/vnext/ReactUWP/Modules/Animated/AdditionAnimatedNode.h new file mode 100644 index 00000000000..99f65cf516e --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/AdditionAnimatedNode.h @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "ValueAnimatedNode.h" +#include + +namespace react { + namespace uwp { + class AdditionAnimatedNode : public ValueAnimatedNode + { + public: + AdditionAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager); + + private: + std::unordered_set m_inputNodes{}; + }; + } +} diff --git a/vnext/ReactUWP/Modules/Animated/AnimatedNode.cpp b/vnext/ReactUWP/Modules/Animated/AnimatedNode.cpp new file mode 100644 index 00000000000..786e8dca427 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/AnimatedNode.cpp @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "AnimatedNode.h" +#include "NativeAnimatedNodeManager.h" + +namespace react { + namespace uwp { + + AnimatedNode::AnimatedNode(int64_t tag, const std::shared_ptr& manager) : m_tag(tag), m_manager(manager) + { + } + + int64_t AnimatedNode::Tag() + { + return m_tag; + } + + void AnimatedNode::AddChild(const int64_t animatedNodeTag) + { + m_children.push_back(animatedNodeTag); + GetChildNode(animatedNodeTag)->OnAttachToNode(m_tag); + } + + void AnimatedNode::RemoveChild(const int64_t tag) + { + if (const auto childNode = GetChildNode(tag)) + { + childNode->OnDetachedFromNode(m_tag); + m_children.erase(std::find(m_children.begin(), m_children.end(), tag)); + } + } + + AnimatedNode* AnimatedNode::GetChildNode(int64_t tag) + { + if (std::find(m_children.begin(), m_children.end(), tag) != m_children.end()) + { + if (const auto manager = m_manager.lock()) + { + return manager->GetAnimatedNode(tag); + } + } + + return static_cast(nullptr); + } + } +} diff --git a/vnext/ReactUWP/Modules/Animated/AnimatedNode.h b/vnext/ReactUWP/Modules/Animated/AnimatedNode.h new file mode 100644 index 00000000000..370fdc058e6 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/AnimatedNode.h @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "pch.h" + +namespace react { namespace uwp { + class NativeAnimatedNodeManager; + class AnimatedNode + { + public: + AnimatedNode(int64_t tag, const std::shared_ptr& manager); + int64_t Tag(); + void AddChild(int64_t animatedNode); + void RemoveChild(int64_t animatedNode); + + virtual void Update() {}; + virtual void OnDetachedFromNode(int64_t animatedNodeTag) {}; + virtual void OnAttachToNode(int64_t animatedNodeTag) {}; + + protected: + AnimatedNode* GetChildNode(int64_t tag); + const std::weak_ptr m_manager; + + protected: + std::vector m_children{}; + int64_t m_tag{ 0 }; + }; +} } diff --git a/vnext/ReactUWP/Modules/Animated/AnimatedNodeType.h b/vnext/ReactUWP/Modules/Animated/AnimatedNodeType.h new file mode 100644 index 00000000000..25b6885fa6f --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/AnimatedNodeType.h @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include +#include + +enum AnimatedNodeType +{ + Style, + Value, + Props, + Interpolation, + Addition, + Subtraction, + Division, + Multiplication, + Modulus, + Diffclamp, + Transform, + Tracking, +}; + +static AnimatedNodeType AnimatedNodeTypeFromString(const std::string& string) +{ + if (string == "style") return AnimatedNodeType::Style; + if (string == "value") return AnimatedNodeType::Value; + if (string == "props") return AnimatedNodeType::Props; + if (string == "interpolation") return AnimatedNodeType::Interpolation; + if (string == "addition") return AnimatedNodeType::Addition; + if (string == "subtraction") return AnimatedNodeType::Subtraction; + if (string == "division") return AnimatedNodeType::Division; + if (string == "multiplication") return AnimatedNodeType::Multiplication; + if (string == "modulus") return AnimatedNodeType::Modulus; + if (string == "diffclamp") return AnimatedNodeType::Diffclamp; + if (string == "transform") return AnimatedNodeType::Transform; + + assert(string == "tracking"); + return AnimatedNodeType::Tracking; +}; diff --git a/vnext/ReactUWP/Modules/Animated/AnimationDriver.cpp b/vnext/ReactUWP/Modules/Animated/AnimationDriver.cpp new file mode 100644 index 00000000000..eea8f212935 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/AnimationDriver.cpp @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "AnimationDriver.h" + +namespace react { + namespace uwp { + + AnimationDriver::AnimationDriver(int64_t id, int64_t animatedValueTag, const Callback& endCallback, const folly::dynamic& config, const std::shared_ptr& manager) : + m_id(id), m_animatedValueTag(animatedValueTag), m_endCallback(endCallback), m_config(config), m_manager(manager) + { + m_iterations = [iterations = config.find("iterations"), end = config.items().end()]() { + if (iterations != end) + { + return iterations.dereference().second.getInt(); + } + return static_cast(1); + }(); + } + + AnimationDriver::~AnimationDriver() + { + if (m_scopedBatch) + m_scopedBatch.Completed(m_scopedBatchCompletedToken); + } + + void AnimationDriver::StartAnimation() + { + const auto [animation, scopedBatch] = MakeAnimation(m_config); + + const auto animatedValue = GetAnimatedValue(); + + if (animatedValue) + { + animatedValue->PropertySet().StartAnimation(L"offset", animation); + animatedValue->AddActiveAnimation(m_id); + } + scopedBatch.End(); + + m_scopedBatchCompletedToken = scopedBatch.Completed([endCallback = m_endCallback, animatedValue, id = m_id](auto sender, auto) + { + if (endCallback) + { + endCallback(std::vector{folly::dynamic::object("finished", true)}); + } + if (animatedValue) + { + animatedValue->RemoveActiveAnimation(id); + } + }); + + m_animation = animation; + m_scopedBatch = scopedBatch; + } + + void AnimationDriver::StopAnimation() + { + if (const auto animatedValue = GetAnimatedValue()) + { + animatedValue->PropertySet().StopAnimation(L"offset"); + m_endCallback(std::vector{folly::dynamic::object("finished", false)}); + } + } + + ValueAnimatedNode* AnimationDriver::GetAnimatedValue() + { + if (auto manager = m_manager.lock()) + { + return manager->GetValueAnimatedNode(m_animatedValueTag); + } + return static_cast(nullptr); + } + } +} diff --git a/vnext/ReactUWP/Modules/Animated/AnimationDriver.h b/vnext/ReactUWP/Modules/Animated/AnimationDriver.h new file mode 100644 index 00000000000..fa6400e9941 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/AnimationDriver.h @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "ValueAnimatedNode.h" +#include "NativeAnimatedNodeManager.h" +#include + +namespace react { namespace uwp { + typedef std::function)> Callback; + + class ValueAnimatedNode; + class AnimationDriver + { + public: + AnimationDriver(int64_t id, int64_t animatedValueTag, const Callback& endCallback, const folly::dynamic& config, const std::shared_ptr& manager); + virtual ~AnimationDriver(); + void StartAnimation(); + void StopAnimation(); + + virtual std::tuple MakeAnimation(const folly::dynamic& config) + { + return std::make_tuple(nullptr, nullptr); + }; + + inline constexpr int64_t Id() { return m_id; }; + + protected: + ValueAnimatedNode* GetAnimatedValue(); + + int64_t m_id{ 0 }; + int64_t m_animatedValueTag{}; + Callback m_endCallback{}; + int64_t m_iterations{ 0 }; + folly::dynamic m_config{}; + std::weak_ptr m_manager{}; + + winrt::Windows::UI::Composition::CompositionAnimation m_animation{ nullptr }; + winrt::Windows::UI::Composition::CompositionScopedBatch m_scopedBatch{ nullptr }; + //auto revoker for scopedBatch.Completed is broken, tracked by internal bug #22399779 + winrt::event_token m_scopedBatchCompletedToken{}; + }; +} } diff --git a/vnext/ReactUWP/Modules/Animated/AnimationType.h b/vnext/ReactUWP/Modules/Animated/AnimationType.h new file mode 100644 index 00000000000..3f01dc836a7 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/AnimationType.h @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include +#include + +enum AnimationType +{ + Decay, + Frames, + Spring, +}; + + +static AnimationType AnimationTypeFromString(const std::string& string) +{ + if (string == "decay") return AnimationType::Decay; + if (string == "frames") return AnimationType::Frames; + + assert(string == "spring"); + return AnimationType::Spring; +} diff --git a/vnext/ReactUWP/Modules/Animated/DecayAnimationDriver.cpp b/vnext/ReactUWP/Modules/Animated/DecayAnimationDriver.cpp new file mode 100644 index 00000000000..9f55880b21b --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/DecayAnimationDriver.cpp @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "DecayAnimationDriver.h" +#include +#include + +namespace react { namespace uwp { + DecayAnimationDriver::DecayAnimationDriver( + int64_t id, + int64_t animatedValueTag, + const Callback& endCallback, + const folly::dynamic& config, + const std::shared_ptr& manager) + : AnimationDriver(id, animatedValueTag, endCallback, config, manager) + { + m_deceleration = config.find(s_decelerationName).dereference().second.asDouble(); + assert(m_deceleration > 0); + m_velocity = config.find(s_velocityName).dereference().second.asDouble(); + } + + std::tuple DecayAnimationDriver::MakeAnimation(const folly::dynamic& config) + { + const auto [scopedBatch, animation] = []() + { + const auto compositor = winrt::Window::Current().Compositor(); + return std::make_tuple(compositor.CreateScopedBatch(winrt::CompositionBatchTypes::AllAnimations), compositor.CreateScalarKeyFrameAnimation()); + }(); + + std::chrono::milliseconds duration(static_cast(m_velocity / -m_deceleration * 1000)); + animation.Duration(duration); + + const auto compositor = winrt::Window::Current().Compositor(); + animation.SetScalarParameter(s_velocityParameterName, static_cast(m_velocity)); + animation.SetScalarParameter(s_decelerationParameterName, static_cast(m_deceleration)); + animation.SetScalarParameter(s_durationName, static_cast(m_velocity / -m_deceleration) * 1000); + // Offset = (Velocity*time) + (0.5*Acceleration*Time^2) + animation.InsertExpressionKeyFrame(1.0f, static_cast(L"(") + s_durationName + L" * " + s_velocityParameterName + L") + (0.5 * " + s_decelerationParameterName + L" * " + s_durationName + L" * " + s_durationName + L")", compositor.CreateCubicBezierEasingFunction({ 0,1 }, { 0, 1 })); + animation.IterationCount(static_cast(m_iterations)); + animation.IterationBehavior(winrt::AnimationIterationBehavior::Count); + + return std::make_tuple(animation, scopedBatch); + } +} } diff --git a/vnext/ReactUWP/Modules/Animated/DecayAnimationDriver.h b/vnext/ReactUWP/Modules/Animated/DecayAnimationDriver.h new file mode 100644 index 00000000000..c2db1aee8c8 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/DecayAnimationDriver.h @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "AnimatedNode.h" +#include "AnimationDriver.h" +#include + +namespace react { namespace uwp { + class DecayAnimationDriver : public AnimationDriver + { + public: + DecayAnimationDriver(int64_t id, int64_t animatedValueTag, const Callback& endCallback, const folly::dynamic& config, const std::shared_ptr& manager); + + std::tuple MakeAnimation(const folly::dynamic& config) override; + private: + double m_velocity{ 0 }; + double m_deceleration{ 0 }; + + static constexpr std::string_view s_velocityName{ "velocity" }; + static constexpr std::string_view s_decelerationName{ "deceleration" }; + + static constexpr std::wstring_view s_velocityParameterName{ L"velocity" }; + static constexpr std::wstring_view s_decelerationParameterName{ L"deceleration" }; + static constexpr std::wstring_view s_durationName{ L"duration" }; + }; +} } diff --git a/vnext/ReactUWP/Modules/Animated/DiffClampAnimatedNode.cpp b/vnext/ReactUWP/Modules/Animated/DiffClampAnimatedNode.cpp new file mode 100644 index 00000000000..426d43366fd --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/DiffClampAnimatedNode.cpp @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "DiffClampAnimatedNode.h" +#include "NativeAnimatedNodeManager.h" + +namespace react { + namespace uwp { + DiffClampAnimatedNode::DiffClampAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager) : ValueAnimatedNode(tag, config, manager) + { + m_inputNodeTag = static_cast(config.find(s_inputName).dereference().second.asDouble()); + m_min = config.find(s_minName).dereference().second.asDouble(); + m_max = config.find(s_maxName).dereference().second.asDouble(); + + m_propertySet.StartAnimation(s_valueName, + [node = m_inputNodeTag, min = m_min, max = m_max, manager]() + { + const auto anim = winrt::Window::Current().Compositor().CreateExpressionAnimation(); + anim.SetReferenceParameter(s_inputParameterName, manager->GetValueAnimatedNode(node)->PropertySet()); + anim.SetScalarParameter(s_minParameterName, static_cast(min)); + anim.SetScalarParameter(s_maxParameterName, static_cast(max)); + anim.Expression(static_cast(L"Clamp(") + s_inputParameterName + L"." + s_valueName + L" + " + s_inputParameterName + L"." + s_offsetName + L", " + s_minParameterName + L", " + s_maxParameterName + L")"); + return anim; + }() + ); + } + } +} diff --git a/vnext/ReactUWP/Modules/Animated/DiffClampAnimatedNode.h b/vnext/ReactUWP/Modules/Animated/DiffClampAnimatedNode.h new file mode 100644 index 00000000000..c504d66a23b --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/DiffClampAnimatedNode.h @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "ValueAnimatedNode.h" +#include + +namespace react { + namespace uwp { + class DiffClampAnimatedNode : public ValueAnimatedNode + { + public: + DiffClampAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager); + + private: + int64_t m_inputNodeTag{}; + double m_min{}; + double m_max{}; + + static constexpr std::string_view s_minName{ "min" }; + static constexpr std::string_view s_maxName{ "max" }; + + static constexpr std::wstring_view s_inputParameterName{ L"input" }; + static constexpr std::wstring_view s_minParameterName{ L"min" }; + static constexpr std::wstring_view s_maxParameterName{ L"max" }; + }; + } +} diff --git a/vnext/ReactUWP/Modules/Animated/DivisionAnimatedNode.cpp b/vnext/ReactUWP/Modules/Animated/DivisionAnimatedNode.cpp new file mode 100644 index 00000000000..7a262881190 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/DivisionAnimatedNode.cpp @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "DivisionAnimatedNode.h" +#include "NativeAnimatedNodeManager.h" + +namespace react { namespace uwp { + DivisionAnimatedNode::DivisionAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager) : ValueAnimatedNode(tag, config, manager) + { + for (const auto& inputNode : config.find(s_inputName).dereference().second) + { + if (m_firstInput == s_firstInputUnset) + { + m_firstInput = static_cast(inputNode.asDouble()); + } + else + { + m_inputNodes.insert(static_cast(inputNode.asDouble())); + } + } + + m_propertySet.StartAnimation(s_valueName, + [firstNode = m_firstInput, nodes = m_inputNodes, manager]() + { + const auto anim = winrt::Window::Current().Compositor().CreateExpressionAnimation(); + + anim.Expression([firstNode, nodes, manager, anim]() + { + anim.SetReferenceParameter(s_baseName, manager->GetValueAnimatedNode(firstNode)->PropertySet()); + winrt::hstring expr = static_cast(L"(") + s_baseName + L"." + s_valueName + L" + " + s_baseName + L"." + s_offsetName + L")"; + for (const auto tag : nodes) + { + const auto identifier = std::to_wstring(tag); + anim.SetReferenceParameter(identifier, manager->GetValueAnimatedNode(tag)->PropertySet()); + expr = expr + L" / (" + identifier + L"." + s_valueName + L" " + identifier + L"." + s_offsetName + L")"; + } + return expr; + }()); + return anim; + }() + ); + } +} } diff --git a/vnext/ReactUWP/Modules/Animated/DivisionAnimatedNode.h b/vnext/ReactUWP/Modules/Animated/DivisionAnimatedNode.h new file mode 100644 index 00000000000..b730eb0f84c --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/DivisionAnimatedNode.h @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "ValueAnimatedNode.h" +#include + +namespace react { namespace uwp { + class DivisionAnimatedNode : public ValueAnimatedNode + { + public: + DivisionAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager); + + private: + int64_t m_firstInput{ s_firstInputUnset }; + std::unordered_set m_inputNodes{}; + + static constexpr int64_t s_firstInputUnset{ -1 }; + + static constexpr std::wstring_view s_baseName{ L"base" }; + }; +} } diff --git a/vnext/ReactUWP/Modules/Animated/EventAnimationDriver.cpp b/vnext/ReactUWP/Modules/Animated/EventAnimationDriver.cpp new file mode 100644 index 00000000000..a8c47695814 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/EventAnimationDriver.cpp @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "EventAnimationDriver.h" +#include "NativeAnimatedNodeManager.h" +#include + +namespace react { namespace uwp { + EventAnimationDriver::EventAnimationDriver(const folly::dynamic& eventPath, int64_t animatedValueTag, const std::shared_ptr& manager) + : m_animatedValueTag(animatedValueTag), m_manager(manager) + { + for (const auto& path : eventPath) + { + m_eventPath.push_back(path.getString()); + } + } + + ValueAnimatedNode* EventAnimationDriver::AnimatedValue() + { + if (const auto manager = m_manager.lock()) + { + return manager->GetValueAnimatedNode(m_animatedValueTag); + } + return static_cast(nullptr); + } + +} } diff --git a/vnext/ReactUWP/Modules/Animated/EventAnimationDriver.h b/vnext/ReactUWP/Modules/Animated/EventAnimationDriver.h new file mode 100644 index 00000000000..f8369ac43d5 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/EventAnimationDriver.h @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "AnimatedNode.h" +#include "ValueAnimatedNode.h" +#include + +namespace react { namespace uwp { + class ValueAnimatedNode; + class EventAnimationDriver + { + public: + EventAnimationDriver(const folly::dynamic& eventPath, int64_t animatedValueTag, const std::shared_ptr& manager); + ValueAnimatedNode* AnimatedValue(); + + private: + std::vector m_eventPath{}; + int64_t m_animatedValueTag{}; + std::weak_ptr m_manager{}; + }; +} } diff --git a/vnext/ReactUWP/Modules/Animated/ExtrapolationType.h b/vnext/ReactUWP/Modules/Animated/ExtrapolationType.h new file mode 100644 index 00000000000..582f7a2ea7d --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/ExtrapolationType.h @@ -0,0 +1,21 @@ +#pragma once +#include +#include + +enum ExtrapolationType +{ + Identity, + Clamp, + Extend, +}; + +static ExtrapolationType ExtrapolationTypeFromString(const std::string& string) +{ + if (string == "identity") return ExtrapolationType::Identity; + else if (string == "clamp") return ExtrapolationType::Clamp; + else + { + assert(string == "extend"); + return ExtrapolationType::Extend; + } +} diff --git a/vnext/ReactUWP/Modules/Animated/FacadeType.h b/vnext/ReactUWP/Modules/Animated/FacadeType.h new file mode 100644 index 00000000000..4036f7b03c4 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/FacadeType.h @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include +#include + +enum FacadeType +{ + Opacity, + Rotation, + RotationX, + RotationY, + Scale, + ScaleX, + ScaleY, + TranslateX, + TranslateY, + Perspective, +}; + +static FacadeType StringToFacadeType(const std::string& string) +{ + if (string == "opacity") return FacadeType::Opacity; + if (string == "rotate") return FacadeType::Rotation; + if (string == "rotateX") return FacadeType::RotationX; + if (string == "rotateY") return FacadeType::RotationY; + if (string == "scale") return FacadeType::Scale; + if (string == "scaleX") return FacadeType::ScaleX; + if (string == "scaleY") return FacadeType::ScaleY; + if (string == "translateX") return FacadeType::TranslateX; + if (string == "translateY") return FacadeType::TranslateY; + + assert(string == "perspective"); + return FacadeType::Perspective; +} diff --git a/vnext/ReactUWP/Modules/Animated/FrameAnimationDriver.cpp b/vnext/ReactUWP/Modules/Animated/FrameAnimationDriver.cpp new file mode 100644 index 00000000000..5679f50669b --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/FrameAnimationDriver.cpp @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "FrameAnimationDriver.h" +#include + +namespace react { namespace uwp { + FrameAnimationDriver::FrameAnimationDriver( + int64_t id, + int64_t animatedValueTag, + const Callback& endCallback, + const folly::dynamic& config, + const std::shared_ptr& manager) + : AnimationDriver(id, animatedValueTag, endCallback, config, manager) + { + for (const auto& frame : config.find("frames").dereference().second) + { + m_frames.push_back(frame.asDouble()); + } + m_toValue = config.find("toValue").dereference().second.asDouble(); + } + + std::tuple FrameAnimationDriver::MakeAnimation(const folly::dynamic& config) + { + const auto [scopedBatch, animation] = []() + { + const auto compositor = winrt::Window::Current().Compositor(); + return std::make_tuple(compositor.CreateScopedBatch(winrt::CompositionBatchTypes::AllAnimations), compositor.CreateScalarKeyFrameAnimation()); + }(); + + // Frames contains 60 values per second of duration of the animation, convert the size of frames to duration in ms. + std::chrono::milliseconds duration(static_cast(m_frames.size() * 1000.0 / 60.0)); + animation.Duration(duration); + + auto normalizedProgress = 0.0f; + auto step = 1.0f / m_frames.size(); + auto fromValue = GetAnimatedValue()->RawValue(); + for (auto frame : m_frames) + { + normalizedProgress += step; + animation.InsertKeyFrame(normalizedProgress, static_cast(fromValue + (frame * (m_toValue - fromValue)))); + } + + animation.IterationCount(static_cast(m_iterations)); + animation.IterationBehavior(winrt::AnimationIterationBehavior::Count); + + return std::make_tuple(animation, scopedBatch); + } + +} } diff --git a/vnext/ReactUWP/Modules/Animated/FrameAnimationDriver.h b/vnext/ReactUWP/Modules/Animated/FrameAnimationDriver.h new file mode 100644 index 00000000000..e02265f1cc5 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/FrameAnimationDriver.h @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "AnimatedNode.h" +#include "AnimationDriver.h" +#include + +namespace react { namespace uwp { + class FrameAnimationDriver : public AnimationDriver + { + public: + FrameAnimationDriver(int64_t id, int64_t animatedValueTag, const Callback& endCallback, const folly::dynamic& config, const std::shared_ptr& manager); + + std::tuple MakeAnimation(const folly::dynamic& config) override; + private: + std::vector m_frames {}; + double m_toValue { 0 }; + }; +} } diff --git a/vnext/ReactUWP/Modules/Animated/InterpolationAnimatedNode.cpp b/vnext/ReactUWP/Modules/Animated/InterpolationAnimatedNode.cpp new file mode 100644 index 00000000000..fde574fe820 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/InterpolationAnimatedNode.cpp @@ -0,0 +1,129 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "InterpolationAnimatedNode.h" +#include "ExtrapolationType.h" +#include "NativeAnimatedNodeManager.h" + +namespace react { namespace uwp { + InterpolationAnimatedNode::InterpolationAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager) : ValueAnimatedNode(tag, manager) + { + int arrayIndex = 0; + for (const auto& rangeValue : config.find(s_inputRangeName).dereference().second) + { + m_inputRange[arrayIndex] = rangeValue.asDouble(); + arrayIndex++; + } + + arrayIndex = 0; + for (const auto& rangeValue : config.find(s_outputRangeName).dereference().second) + { + m_outputRange[arrayIndex] = rangeValue.asDouble(); + arrayIndex++; + } + + m_extrapolateLeft = config.find(s_extrapolateLeftName).dereference().second.asString(); + m_extrapolateRight = config.find(s_extrapolateRightName).dereference().second.asString(); + } + + void InterpolationAnimatedNode::Update() + { + + } + + void InterpolationAnimatedNode::OnDetachedFromNode(int64_t animatedNodeTag) + { + assert(m_parentTag == animatedNodeTag); + m_parentTag = s_parentTagUnset; + m_propertySet.StopAnimation(s_valueName); + m_propertySet.StopAnimation(s_valueName); + m_rawValueAnimation = nullptr; + m_offsetAnimation = nullptr; + } + + void InterpolationAnimatedNode::OnAttachToNode(int64_t animatedNodeTag) + { + assert(m_parentTag == s_parentTagUnset); + m_parentTag = animatedNodeTag; + + const auto [rawValueAnimation, offsetAnimation] = [this]() + { + if (const auto manager = m_manager.lock()) + { + if (const auto parent = manager->GetValueAnimatedNode(m_parentTag)) + { + const auto compositor = winrt::Window::Current().Compositor(); + + const auto rawValueAnimation = CreateExpressionAnimation(compositor, *parent); + rawValueAnimation.Expression(GetExpression(s_parentPropsName + static_cast(L".") + s_valueName)); + + const auto offsetAnimation = CreateExpressionAnimation(compositor, *parent); + offsetAnimation.Expression(L"(" + GetExpression(static_cast(L"(") + s_parentPropsName + L"." + s_offsetName + L" + " + s_parentPropsName +L"." + s_valueName + L")") + L") - this.target." + s_valueName); + + return std::make_tuple(rawValueAnimation, offsetAnimation); + } + } + return std::tuple(nullptr, nullptr); + }(); + + m_propertySet.StartAnimation(s_valueName, rawValueAnimation); + m_propertySet.StartAnimation(s_offsetName, offsetAnimation); + + m_rawValueAnimation = rawValueAnimation; + m_offsetAnimation = offsetAnimation; + } + + winrt::ExpressionAnimation InterpolationAnimatedNode::CreateExpressionAnimation(const winrt::Compositor& compositor, ValueAnimatedNode& parent) + { + const auto animation = compositor.CreateExpressionAnimation(); + animation.SetReferenceParameter(s_parentPropsName, parent.PropertySet()); + animation.SetScalarParameter(s_inputMinName, static_cast(m_inputRange[0])); + animation.SetScalarParameter(s_inputMaxName, static_cast(m_inputRange[1])); + animation.SetScalarParameter(s_outputMinName, static_cast(m_outputRange[0])); + animation.SetScalarParameter(s_outputMaxName, static_cast(m_outputRange[1])); + return animation; + } + + winrt::hstring InterpolationAnimatedNode::GetExpression(const winrt::hstring& value) + { + return GetLeftExpression(value) + GetRightExpression(value) + GetInterpolateExpression(value); + } + + winrt::hstring InterpolationAnimatedNode::GetInterpolateExpression(const winrt::hstring& value) + { + return s_outputMinName + static_cast(L" + ((") + s_outputMaxName + L" - " + s_outputMinName + L") * ((" + value + L" - " + s_inputMinName + L") / (" + s_inputMaxName + L" - " + s_inputMinName + L")))"; + } + + winrt::hstring InterpolationAnimatedNode::GetLeftExpression(const winrt::hstring& value) + { + switch (ExtrapolationTypeFromString(m_extrapolateLeft)) + { + case ExtrapolationType::Clamp: + return value + L" < " + s_inputMinName + L" ? " + s_inputMinName + L" : "; + case ExtrapolationType::Identity: + return value + L" < " + s_inputMinName + L" ? " + value + L" : "; + case ExtrapolationType::Extend: + return value + L" < " + s_inputMinName + L" ? " + GetInterpolateExpression(value) + L" : "; + default: + return L""; + + } + } + + winrt::hstring InterpolationAnimatedNode::GetRightExpression(const winrt::hstring& value) + { + switch (ExtrapolationTypeFromString(m_extrapolateRight)) + { + case ExtrapolationType::Clamp: + return value + L" > " + s_inputMaxName + L" ? " + s_inputMaxName + L" : "; + case ExtrapolationType::Identity: + return value + L" > " + s_inputMaxName + L" ? " + value + L" : "; + case ExtrapolationType::Extend: + return value + L" > " + s_inputMaxName + L" ? " + GetInterpolateExpression(value) + L" : "; + default: + return L""; + + } + } +} } diff --git a/vnext/ReactUWP/Modules/Animated/InterpolationAnimatedNode.h b/vnext/ReactUWP/Modules/Animated/InterpolationAnimatedNode.h new file mode 100644 index 00000000000..dd6937871c0 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/InterpolationAnimatedNode.h @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "ValueAnimatedNode.h" +#include + +namespace react { namespace uwp { + + class InterpolationAnimatedNode : public ValueAnimatedNode + { + public: + InterpolationAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager); + + virtual void Update() override; + virtual void OnDetachedFromNode(int64_t animatedNodeTag) override; + virtual void OnAttachToNode(int64_t animatedNodeTag) override; + + static constexpr std::wstring_view ExtrapolateTypeIdentity = L"identity"; + static constexpr std::wstring_view ExtrapolateTypeClamp = L"clamp"; + static constexpr std::wstring_view ExtrapolateTypeExtend = L"extend"; + + private: + winrt::ExpressionAnimation CreateExpressionAnimation(const winrt::Compositor& compositor, ValueAnimatedNode& parent); + + winrt::hstring GetExpression(const winrt::hstring& value); + winrt::hstring GetInterpolateExpression(const winrt::hstring& value); + winrt::hstring GetLeftExpression(const winrt::hstring& value); + winrt::hstring GetRightExpression(const winrt::hstring& value); + winrt::ExpressionAnimation m_rawValueAnimation{ nullptr }; + winrt::ExpressionAnimation m_offsetAnimation{ nullptr }; + std::array m_inputRange; + std::array m_outputRange; + std::string m_extrapolateLeft; + std::string m_extrapolateRight; + + int64_t m_parentTag{ s_parentTagUnset }; + + static constexpr int64_t s_parentTagUnset{ -1 }; + + static constexpr std::string_view s_inputRangeName{ "inputRange" }; + static constexpr std::string_view s_outputRangeName{ "outputRange" }; + static constexpr std::string_view s_extrapolateLeftName{ "extrapolateLeft" }; + static constexpr std::string_view s_extrapolateRightName{ "extrapolateRight" }; + + static constexpr std::wstring_view s_parentPropsName{ L"parentProps" }; + static constexpr std::wstring_view s_inputMinName{ L"inputMin" }; + static constexpr std::wstring_view s_inputMaxName{ L"inputMax" }; + static constexpr std::wstring_view s_outputMinName{ L"outputMin" }; + static constexpr std::wstring_view s_outputMaxName{ L"outputMax" }; + }; +} } diff --git a/vnext/ReactUWP/Modules/Animated/ModulusAnimatedNode.cpp b/vnext/ReactUWP/Modules/Animated/ModulusAnimatedNode.cpp new file mode 100644 index 00000000000..45727c49f92 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/ModulusAnimatedNode.cpp @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "ModulusAnimatedNode.h" +#include "NativeAnimatedNodeManager.h" + +namespace react { namespace uwp { + ModulusAnimatedNode::ModulusAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager) : ValueAnimatedNode(tag, config, manager) + { + m_inputNodeTag = static_cast(config.find(s_inputName).dereference().second.asDouble()); + m_modulus = static_cast(config.find(s_modulusName).dereference().second.asDouble()); + + m_propertySet.StartAnimation(s_valueName, + [node = m_inputNodeTag, mod = m_modulus, manager]() + { + const auto anim = winrt::Window::Current().Compositor().CreateExpressionAnimation(); + anim.SetReferenceParameter(s_inputParameterName, manager->GetValueAnimatedNode(node)->PropertySet()); + anim.SetScalarParameter(s_modName, static_cast(mod)); + anim.Expression(static_cast(L"(") + s_inputParameterName + L"." + s_valueName + L" + " + s_inputParameterName + L"." + s_offsetName + L") % " + s_modName); + return anim; + }() + ); + } +} } diff --git a/vnext/ReactUWP/Modules/Animated/ModulusAnimatedNode.h b/vnext/ReactUWP/Modules/Animated/ModulusAnimatedNode.h new file mode 100644 index 00000000000..7486e13f0a3 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/ModulusAnimatedNode.h @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "ValueAnimatedNode.h" +#include + +namespace react { namespace uwp { + class ModulusAnimatedNode : public ValueAnimatedNode + { + public: + ModulusAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager); + + private: + int64_t m_inputNodeTag{}; + int64_t m_modulus{}; + + static constexpr std::string_view s_modulusName{ "modulus" }; + + static constexpr std::wstring_view s_inputParameterName{ L"input" }; + static constexpr std::wstring_view s_modName{ L"mod" }; + }; +} } diff --git a/vnext/ReactUWP/Modules/Animated/MultiplicationAnimatedNode.cpp b/vnext/ReactUWP/Modules/Animated/MultiplicationAnimatedNode.cpp new file mode 100644 index 00000000000..d1274a8d8d0 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/MultiplicationAnimatedNode.cpp @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "MultiplicationAnimatedNode.h" +#include "NativeAnimatedNodeManager.h" + +namespace react { namespace uwp { + MultiplicationAnimatedNode::MultiplicationAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager) : ValueAnimatedNode(tag, config, manager) + { + for (const auto& inputNode : config.find(s_inputName).dereference().second) + { + m_inputNodes.insert(static_cast(inputNode.asDouble())); + } + + m_propertySet.StartAnimation(s_valueName, + [nodes = m_inputNodes, manager]() + { + const auto anim = winrt::Window::Current().Compositor().CreateExpressionAnimation(); + + anim.Expression([nodes, manager, anim]() + { + winrt::hstring expr = L"1"; + for (const auto tag : nodes) + { + auto identifier = std::to_wstring(tag); + anim.SetReferenceParameter(identifier, manager->GetValueAnimatedNode(tag)->PropertySet()); + expr = expr + L" * (" + identifier + L"." + s_valueName + L" + " + identifier + L"." + s_offsetName + L")"; + } + return expr; + }()); + return anim; + }() + ); + } +} } diff --git a/vnext/ReactUWP/Modules/Animated/MultiplicationAnimatedNode.h b/vnext/ReactUWP/Modules/Animated/MultiplicationAnimatedNode.h new file mode 100644 index 00000000000..4bff7c1fc00 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/MultiplicationAnimatedNode.h @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "ValueAnimatedNode.h" +#include + +namespace react { namespace uwp { + class MultiplicationAnimatedNode : public ValueAnimatedNode + { + public: + MultiplicationAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager); + + private: + std::unordered_set m_inputNodes{}; + }; +} } diff --git a/vnext/ReactUWP/Modules/Animated/NativeAnimatedModule.cpp b/vnext/ReactUWP/Modules/Animated/NativeAnimatedModule.cpp new file mode 100644 index 00000000000..f45d6d8e138 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/NativeAnimatedModule.cpp @@ -0,0 +1,202 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "NativeAnimatedModule.h" + +#include +#include "unicode.h" +#include +#include + +namespace react { namespace uwp { + const char* NativeAnimatedModule::name{ "NativeAnimatedModule" }; + const char* NativeAnimatedModule::s_createAnimatedNodeName{ "createAnimatedNode" }; + const char* NativeAnimatedModule::s_connectAnimatedNodeToViewName{ "connectAnimatedNodeToView" }; + const char* NativeAnimatedModule::s_disconnectAnimatedNodeFromViewName{ "disconnectAnimatedNodeFromView" }; + const char* NativeAnimatedModule::s_connectAnimatedNodesName{ "connectAnimatedNodes" }; + const char* NativeAnimatedModule::s_disconnectAnimatedNodesName{ "disconnectAnimatedNodes" }; + const char* NativeAnimatedModule::s_stopAnimationName{ "stopAnimation" }; + const char* NativeAnimatedModule::s_startAnimatingNodeName{ "startAnimatingNode" }; + const char* NativeAnimatedModule::s_dropAnimatedNodeName{ "dropAnimatedNode" }; + const char* NativeAnimatedModule::s_setAnimatedNodeValueName{ "setAnimatedNodeValue" }; + const char* NativeAnimatedModule::s_setAnimatedNodeOffsetName{ "setAnimatedNodeOffset" }; + const char* NativeAnimatedModule::s_flattenAnimatedNodeOffsetName{ "flattenAnimatedNodeOffset" }; + const char* NativeAnimatedModule::s_extractAnimatedNodeOffsetName{ "extractAnimatedNodeOffset" }; + const char* NativeAnimatedModule::s_addAnimatedEventToViewName{ "addAnimatedEventToView" }; + const char* NativeAnimatedModule::s_removeAnimatedEventFromViewName{ "removeAnimatedEventFromView" }; + + NativeAnimatedModule::NativeAnimatedModule(const std::weak_ptr& reactInstance) : m_wkReactInstance(reactInstance) + { + m_nodesManager = std::make_shared(NativeAnimatedNodeManager()); + } + + std::vector NativeAnimatedModule::getMethods() + { + return { + Method(s_createAnimatedNodeName, [this](folly::dynamic args) + { + const auto tag = facebook::xplat::jsArgAsInt(args, 0); + const auto config = facebook::xplat::jsArgAsObject(args, 1); + NativeAnimatedModule::CreateAnimatedNode(tag, config); + }), + Method(s_connectAnimatedNodeToViewName, [this](folly::dynamic args) + { + const auto tag = facebook::xplat::jsArgAsInt(args, 0); + const auto viewTag = facebook::xplat::jsArgAsInt(args, 1); + NativeAnimatedModule::ConnectAnimatedNodeToView(tag, viewTag); + }), + Method(s_disconnectAnimatedNodeFromViewName, [this](folly::dynamic args) + { + const auto tag = facebook::xplat::jsArgAsInt(args, 0); + const auto viewTag = facebook::xplat::jsArgAsInt(args, 1); + NativeAnimatedModule::DisconnectAnimatedNodeFromView(tag, viewTag); + }), + Method(s_connectAnimatedNodesName, [this](folly::dynamic args) + { + const auto parentTag = facebook::xplat::jsArgAsInt(args, 0); + const auto childTag = facebook::xplat::jsArgAsInt(args, 1); + NativeAnimatedModule::ConnectAnimatedNodes(parentTag, childTag); + }), + Method(s_disconnectAnimatedNodesName, [this](folly::dynamic args) + { + const auto parentTag = facebook::xplat::jsArgAsInt(args, 0); + const auto childTag = facebook::xplat::jsArgAsInt(args, 1); + NativeAnimatedModule::DisconnectAnimatedNodes(parentTag, childTag); + }), + Method(s_stopAnimationName, [this](folly::dynamic args) + { + const auto animationId = facebook::xplat::jsArgAsInt(args, 0); + NativeAnimatedModule::StopAnimation(animationId); + }), + Method(s_startAnimatingNodeName, [this](folly::dynamic args, Callback endCallback) + { + const auto animationId = facebook::xplat::jsArgAsInt(args, 0); + const auto animatedNodeTag = facebook::xplat::jsArgAsInt(args, 1); + const auto animationConfig = facebook::xplat::jsArgAsObject(args, 2); + NativeAnimatedModule::StartAnimatingNode(animationId, animatedNodeTag, animationConfig, endCallback); + }), + Method(s_dropAnimatedNodeName, [this](folly::dynamic args) + { + const auto tag = facebook::xplat::jsArgAsInt(args, 0); + NativeAnimatedModule::DropAnimatedNode(tag); + }), + Method(s_setAnimatedNodeValueName, [this](folly::dynamic args) + { + const auto tag = facebook::xplat::jsArgAsInt(args, 0); + const auto value = facebook::xplat::jsArgAsDouble(args, 1); + NativeAnimatedModule::SetAnimatedNodeValue(tag, value); + }), + Method(s_setAnimatedNodeOffsetName, [this](folly::dynamic args) + { + const auto tag = facebook::xplat::jsArgAsInt(args, 0); + const auto value = facebook::xplat::jsArgAsDouble(args, 1); + NativeAnimatedModule::SetAnimatedNodeOffset(tag, value); + }), + Method(s_flattenAnimatedNodeOffsetName, [this](folly::dynamic args) + { + const auto tag = facebook::xplat::jsArgAsInt(args, 0); + NativeAnimatedModule::FlattenAnimatedNodeOffset(tag); + }), + Method(s_extractAnimatedNodeOffsetName, [this](folly::dynamic args) + { + const auto tag = facebook::xplat::jsArgAsInt(args, 0); + NativeAnimatedModule::ExtractAnimatedNodeOffset(tag); + }), + Method(s_addAnimatedEventToViewName, [this](folly::dynamic args) + { + const auto viewTag = facebook::xplat::jsArgAsInt(args, 0); + const auto eventName = facebook::xplat::jsArgAsString(args, 1); + const auto eventMapping = facebook::xplat::jsArgAsObject(args, 2); + NativeAnimatedModule::AddAnimatedEventToView(viewTag, eventName, eventMapping); + }), + Method(s_removeAnimatedEventFromViewName, [this](folly::dynamic args) + { + const auto viewTag = facebook::xplat::jsArgAsInt(args, 0); + const auto eventName = facebook::xplat::jsArgAsString(args, 1); + const auto animatedValueTag = facebook::xplat::jsArgAsInt(args, 2); + NativeAnimatedModule::RemoveAnimatedEventFromView(viewTag, eventName, animatedValueTag); + }), + }; + } + + void NativeAnimatedModule::CreateAnimatedNode(int64_t tag, const folly::dynamic& config) + { + m_nodesManager->CreateAnimatedNode(tag, config, m_wkReactInstance, m_nodesManager); + } + + void NativeAnimatedModule::ConnectAnimatedNodeToView(int64_t animatedNodeTag, int64_t viewTag) + { + m_nodesManager->ConnectAnimatedNodeToView(animatedNodeTag, viewTag); + } + + void NativeAnimatedModule::DisconnectAnimatedNodeFromView(int64_t animatedNodeTag, int64_t viewTag) + { + m_nodesManager->DisconnectAnimatedNodeToView(animatedNodeTag, viewTag); + } + + void NativeAnimatedModule::ConnectAnimatedNodes(int64_t parentNodeTag, int64_t childNodeTag) + { + m_nodesManager->ConnectAnimatedNode(parentNodeTag, childNodeTag); + } + + void NativeAnimatedModule::DisconnectAnimatedNodes(int64_t parentNodeTag, int64_t childNodeTag) + { + m_nodesManager->DisconnectAnimatedNode(parentNodeTag, childNodeTag); + } + + void NativeAnimatedModule::StartAnimatingNode(int64_t animationId, int64_t animatedNodeTag, const folly::dynamic& animationConfig, const Callback& endCallback) + { + m_nodesManager->StartAnimatingNode(animationId, animatedNodeTag, animationConfig, endCallback, m_nodesManager); + } + + void NativeAnimatedModule::StopAnimation(int64_t animationId) + { + m_nodesManager->StopAnimation(animationId); + } + + void NativeAnimatedModule::DropAnimatedNode(int64_t tag) + { + m_nodesManager->DropAnimatedNode(tag); + } + + void NativeAnimatedModule::SetAnimatedNodeValue(int64_t tag, double value) + { + m_nodesManager->SetAnimatedNodeValue(tag, value); + } + + void NativeAnimatedModule::SetAnimatedNodeOffset(int64_t tag, double offset) + { + m_nodesManager->SetAnimatedNodeOffset(tag, offset); + } + + void NativeAnimatedModule::FlattenAnimatedNodeOffset(int64_t tag) + { + m_nodesManager->FlattenAnimatedNodeOffset(tag); + } + + void NativeAnimatedModule::ExtractAnimatedNodeOffset(int64_t tag) + { + m_nodesManager->ExtractAnimatedNodeOffset(tag); + } + + void NativeAnimatedModule::AddAnimatedEventToView(int64_t tag, const std::string& eventName, const folly::dynamic& eventMapping) + { + m_nodesManager->AddAnimatedEventToView(tag, eventName, eventMapping, m_nodesManager); + } + + void NativeAnimatedModule::RemoveAnimatedEventFromView(int64_t tag, const std::string& eventName, int64_t animatedValueTag) + { + m_nodesManager->RemoveAnimatedEventFromView(tag, eventName, animatedValueTag); + } + + void NativeAnimatedModule::StartListeningToAnimatedNodeValue(int64_t tag) + { + //NotImplemented + } + + void NativeAnimatedModule::StopListeningToAnimatedNodeValue(int64_t tag) + { + //NotImplemented + } +} } // namespace react::uwp diff --git a/vnext/ReactUWP/Modules/Animated/NativeAnimatedModule.h b/vnext/ReactUWP/Modules/Animated/NativeAnimatedModule.h new file mode 100644 index 00000000000..04a9f8a5443 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/NativeAnimatedModule.h @@ -0,0 +1,104 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include "NativeAnimatedNodeManager.h" + + /// + /// Module that exposes interface for creating and managing animated nodes + /// on the "native" side. + /// + /// + /// Animated.js library is based on a concept of a graph where nodes are + /// values or transform operations (such as interpolation, addition, etc.) + /// and connection are used to describe how change of the value in one node + /// can affect other nodes. + /// + /// Few examples of the nodes that can be created on the JS side: + /// - Animated.Value is a simplest type of node with a numeric value which + /// can be driven by an animation engine (spring, decay, etc) or by + /// calling setValue on it directly from JS + /// - Animated.add is a type of node that may have two or more input nodes. + /// It outputs the sum of all the input node values + /// - interpolate - is actually a method you can call on any node and it + /// creates a new node that takes the parent node as an input and + /// outputs its interpolated value (e.g. if you have value that can + /// animate from 0 to 1 you can create interpolated node and set output + /// range to be 0 to 100 and when the input node changes the output of + /// interpolated node will multiply the values by 100) + /// + /// You can mix and chain nodes however you like and this way create nodes + /// graph with connections between them. + /// + /// To map animated node values to view props there is a special type + /// of a node: AnimatedProps. It is created by AnimatedImplementation + /// whenever you render Animated.View and stores a mapping from the view + /// props to the corresponding animated values (so it's actually also + /// a node with connections to the value nodes). + /// + /// Last "special" elements of the the graph are "animation drivers". Those + /// are objects (represented as a graph nodes too) that based on some + /// criteria updates attached values via a composition expression animation + /// (we have few types of those, e.g., spring, timing, decay). Animation objects + /// can be "started" and "stopped". Those are like "pulse generators" for the + /// rest of the nodes graph. Those pulses then propagate along the graph to the + /// children nodes up to the special node type: AnimatedProps which then + /// can be used to calculate prop update map for a view. + /// + /// This class acts as a proxy between the "native" API that can be called + /// from JS and the main class that coordinates all the action: + /// . + /// +namespace react { namespace uwp { + class NativeAnimatedModule final : public facebook::xplat::module::CxxModule + { + public: + NativeAnimatedModule(const std::weak_ptr & reactInstance); + virtual ~NativeAnimatedModule() = default; + + // CxxModule + std::string getName() override { return name; }; + std::map getConstants() override { return {}; }; + auto getMethods()->std::vector override; + + void CreateAnimatedNode(int64_t tag, const folly::dynamic& config); + void ConnectAnimatedNodeToView(int64_t animatedNodeTag, int64_t viewTag); + void DisconnectAnimatedNodeFromView(int64_t animatedNodeTag, int64_t viewTag); + void ConnectAnimatedNodes(int64_t parentNodeTag, int64_t childNodeTag); + void DisconnectAnimatedNodes(int64_t parentNodeTag, int64_t childNodeTag); + void StartAnimatingNode(int64_t animationId, int64_t animatedNodeTag, const folly::dynamic& animationConfig, const Callback& endCallback); + void StopAnimation(int64_t animationId); + void DropAnimatedNode(int64_t tag); + void SetAnimatedNodeValue(int64_t tag, double value); + void SetAnimatedNodeOffset(int64_t tag, double offset); + void FlattenAnimatedNodeOffset(int64_t tag); + void ExtractAnimatedNodeOffset(int64_t tag); + void AddAnimatedEventToView(int64_t tag, const std::string& eventName, const folly::dynamic& eventMapping); + void RemoveAnimatedEventFromView(int64_t tag, const std::string& eventName, int64_t animatedValueTag); + void StartListeningToAnimatedNodeValue(int64_t tag); + void StopListeningToAnimatedNodeValue(int64_t tag); + + static const char* name; + private: + std::shared_ptr m_nodesManager{}; + std::weak_ptr m_wkReactInstance; + + static const char* s_createAnimatedNodeName; + static const char* s_connectAnimatedNodeToViewName; + static const char* s_disconnectAnimatedNodeFromViewName; + static const char* s_connectAnimatedNodesName; + static const char* s_disconnectAnimatedNodesName; + static const char* s_stopAnimationName; + static const char* s_startAnimatingNodeName; + static const char* s_dropAnimatedNodeName; + static const char* s_setAnimatedNodeValueName; + static const char* s_setAnimatedNodeOffsetName; + static const char* s_flattenAnimatedNodeOffsetName; + static const char* s_extractAnimatedNodeOffsetName; + static const char* s_addAnimatedEventToViewName; + static const char* s_removeAnimatedEventFromViewName; + }; +} } diff --git a/vnext/ReactUWP/Modules/Animated/NativeAnimatedNodeManager.cpp b/vnext/ReactUWP/Modules/Animated/NativeAnimatedNodeManager.cpp new file mode 100644 index 00000000000..a375f017d2f --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/NativeAnimatedNodeManager.cpp @@ -0,0 +1,340 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "NativeAnimatedNodeManager.h" +#include "StyleAnimatedNode.h" +#include "InterpolationAnimatedNode.h" +#include "AdditionAnimatedNode.h" +#include "MultiplicationAnimatedNode.h" +#include "DivisionAnimatedNode.h" +#include "SubtractionAnimatedNode.h" +#include "ModulusAnimatedNode.h" +#include "DiffClampAnimatedNode.h" + +#include "FrameAnimationDriver.h" +#include "DecayAnimationDriver.h" + +#include "FacadeType.h" +#include "AnimatedNodeType.h" +#include "AnimationType.h" + +#include +#include + +namespace react { + namespace uwp { + void NativeAnimatedNodeManager::CreateAnimatedNode(int64_t tag, const folly::dynamic& config, const std::weak_ptr& instance, const std::shared_ptr& manager) + { + if (m_animationNodes.count(tag) > 0 || + m_propsNodes.count(tag) > 0 || + m_styleNodes.count(tag) > 0 || + m_valueNodes.count(tag) > 0) + { + throw new std::invalid_argument("AnimatedNode with tag " + std::to_string(tag) + " already exists."); + return; + } + + switch (const auto type = AnimatedNodeTypeFromString(config.find("type").dereference().second.getString())) + { + case AnimatedNodeType::Style: + { + m_styleNodes.emplace(tag, std::make_unique(tag, config, manager)); + break; + } + case AnimatedNodeType::Value: + { + m_valueNodes.emplace(tag, std::make_unique(tag, config, manager)); + break; + } + case AnimatedNodeType::Props: + { + m_propsNodes.emplace(tag, std::make_unique(tag, config, instance, manager)); + break; + } + case AnimatedNodeType::Interpolation: + { + m_valueNodes.emplace(tag, std::make_unique(tag, config, manager)); + break; + } + case AnimatedNodeType::Addition: + { + m_valueNodes.emplace(tag, std::make_unique(tag, config, manager)); + break; + } + case AnimatedNodeType::Subtraction: + { + m_valueNodes.emplace(tag, std::make_unique(tag, config, manager)); + break; + } + case AnimatedNodeType::Division: + { + m_valueNodes.emplace(tag, std::make_unique(tag, config, manager)); + break; + } + case AnimatedNodeType::Multiplication: + { + m_valueNodes.emplace(tag, std::make_unique(tag, config, manager)); + break; + } + case AnimatedNodeType::Modulus: + { + m_valueNodes.emplace(tag, std::make_unique(tag, config, manager)); + break; + } + case AnimatedNodeType::Diffclamp: + { + m_valueNodes.emplace(tag, std::make_unique(tag, config, manager)); + break; + } + case AnimatedNodeType::Transform: + { + m_transformNodes.emplace(tag, std::make_unique(tag, config, manager)); + break; + } + case AnimatedNodeType::Tracking: + { + break; + } + default: + { + assert(false); + break; + } + } + } + + void NativeAnimatedNodeManager::ConnectAnimatedNodeToView(int64_t propsNodeTag, int64_t viewTag) + { + m_propsNodes.at(propsNodeTag)->ConnectToView(viewTag); + } + + void NativeAnimatedNodeManager::DisconnectAnimatedNodeToView(int64_t propsNodeTag, int64_t viewTag) + { + m_propsNodes.at(propsNodeTag)->DisconnectFromView(viewTag); + } + + void NativeAnimatedNodeManager::ConnectAnimatedNode(int64_t parentNodeTag, int64_t childNodeTag) + { + if(const auto parentNode = GetAnimatedNode(parentNodeTag)) + { + parentNode->AddChild(childNodeTag); + } + } + + void NativeAnimatedNodeManager::DisconnectAnimatedNode(int64_t parentNodeTag, int64_t childNodeTag) + { + if (const auto parentNode = GetAnimatedNode(parentNodeTag)) + { + parentNode->RemoveChild(childNodeTag); + } + } + + void NativeAnimatedNodeManager::StopAnimation(int64_t animationId) + { + if (m_activeAnimations.count(animationId)) + { + if (const auto animation = m_activeAnimations.at(animationId).get()) + { + animation->StopAnimation(); + m_activeAnimations.erase(animationId); + } + } + } + + void NativeAnimatedNodeManager::StartAnimatingNode(int64_t animationId, int64_t animatedNodeTag, const folly::dynamic& animationConfig, const Callback& endCallback, const std::shared_ptr& manager) + { + switch (AnimationTypeFromString(animationConfig.find("type").dereference().second.getString())) + { + case AnimationType::Decay: + m_activeAnimations.emplace(animationId, std::make_unique(animationId, animatedNodeTag, endCallback, animationConfig, manager)); + break; + case AnimationType::Frames: + m_activeAnimations.emplace(animationId, std::make_unique(animationId, animatedNodeTag, endCallback, animationConfig, manager)); + break; + case AnimationType::Spring: + //TODO: implement spring animations tracked by issue #2681 + break; + default: + assert(false); + break; + } + + if (m_activeAnimations.count(animationId)) + { + m_activeAnimations.at(animationId)->StartAnimation(); + } + } + + void NativeAnimatedNodeManager::DropAnimatedNode(int64_t tag) + { + m_valueNodes.erase(tag); + m_propsNodes.erase(tag); + m_styleNodes.erase(tag); + m_transformNodes.erase(tag); + } + + void NativeAnimatedNodeManager::SetAnimatedNodeValue(int64_t tag, double value) + { + if (const auto valueNode = m_valueNodes.at(tag).get()) + { + valueNode->RawValue(static_cast(value)); + } + } + + void NativeAnimatedNodeManager::SetAnimatedNodeOffset(int64_t tag, double offset) + { + if (const auto valueNode = m_valueNodes.at(tag).get()) + { + valueNode->Offset(static_cast(offset)); + } + } + + void NativeAnimatedNodeManager::FlattenAnimatedNodeOffset(int64_t tag) + { + if (const auto valueNode = m_valueNodes.at(tag).get()) + { + valueNode->FlattenOffset(); + } + } + + void NativeAnimatedNodeManager::ExtractAnimatedNodeOffset(int64_t tag) + { + if (const auto valueNode = m_valueNodes.at(tag).get()) + { + valueNode->ExtractOffset(); + } + } + + void NativeAnimatedNodeManager::AddAnimatedEventToView(int64_t viewTag, const std::string& eventName, const folly::dynamic& eventMapping, const std::shared_ptr& manager) + { + const auto valueNodeTag = static_cast(eventMapping.find("animatedValueTag").dereference().second.asDouble()); + const auto pathList = eventMapping.find("nativeEventPath").dereference().second.getString(); + + const auto key = std::make_tuple(viewTag, eventName); + if (m_eventDrivers.count(key)) + { + m_eventDrivers.at(key).emplace_back(std::make_unique(pathList, valueNodeTag, manager)); + } + else + { + auto vector = std::vector>{}; + vector.emplace_back(std::make_unique(pathList, valueNodeTag, manager)); + m_eventDrivers.insert({ key, std::move(vector) }); + } + } + + void NativeAnimatedNodeManager::RemoveAnimatedEventFromView(int64_t viewTag, const std::string& eventName, int64_t animatedValueTag) + { + const auto key = std::make_tuple(viewTag, eventName); + if (m_eventDrivers.count(key)) + { + auto& drivers = m_eventDrivers.at(key); + + for (auto iterator = drivers.begin(); iterator != drivers.end(); iterator++) + { + if (const auto value = iterator->get()->AnimatedValue()) + { + if(value->Tag() == animatedValueTag) + { + m_eventDrivers.at(key).erase(iterator); + } + } + } + + if (!drivers.size()) + { + m_eventDrivers.erase(key); + } + } + } + + void NativeAnimatedNodeManager::ProcessDelayedPropsNodes() + { + // If StartAnimations fails we'll put the props nodes back into this queue to + // try again when the next batch completes. Because of this we need to copy the + // props to change into a local and clear the member before we begin. + const auto delayedPropsNodes = m_delayedPropsNodes; + m_delayedPropsNodes.clear(); + for (const auto tag : delayedPropsNodes) + { + m_propsNodes.at(tag)->StartAnimations(); + } + } + + void NativeAnimatedNodeManager::AddDelayedPropsNode(int64_t propsNodeTag, const std::shared_ptr& instance) + { + m_delayedPropsNodes.push_back(propsNodeTag); + if (m_delayedPropsNodes.size() <= 1) + { + static_cast(instance->NativeUIManager())->AddBatchCompletedCallback([this]() { ProcessDelayedPropsNodes(); }); + } + } + + AnimationDriver* NativeAnimatedNodeManager::GetAnimationNode(int64_t tag) + { + if (m_animationNodes.count(tag)) + { + return m_animationNodes.at(tag).get(); + } + return static_cast(nullptr); + } + + AnimatedNode* NativeAnimatedNodeManager::GetAnimatedNode(int64_t tag) + { + if (m_valueNodes.count(tag)) + { + return m_valueNodes.at(tag).get(); + } + if (m_styleNodes.count(tag)) + { + return m_styleNodes.at(tag).get(); + } + if (m_propsNodes.count(tag)) + { + return m_propsNodes.at(tag).get(); + } + if (m_transformNodes.count(tag)) + { + return m_transformNodes.at(tag).get(); + } + return static_cast(nullptr); + } + + ValueAnimatedNode* NativeAnimatedNodeManager::GetValueAnimatedNode(int64_t tag) + { + if (m_valueNodes.count(tag)) + { + return m_valueNodes.at(tag).get(); + } + return static_cast(nullptr); + } + + PropsAnimatedNode* NativeAnimatedNodeManager::GetPropsAnimatedNode(int64_t tag) + { + if (m_propsNodes.count(tag)) + { + return m_propsNodes.at(tag).get(); + } + return static_cast(nullptr); + } + + StyleAnimatedNode* NativeAnimatedNodeManager::GetStyleAnimatedNode(int64_t tag) + { + if (m_styleNodes.count(tag)) + { + return m_styleNodes.at(tag).get(); + } + return static_cast(nullptr); + } + + TransformAnimatedNode* NativeAnimatedNodeManager::GetTransformAnimatedNode(int64_t tag) + { + if (m_transformNodes.count(tag)) + { + return m_transformNodes.at(tag).get(); + } + return static_cast(nullptr); + } + } +} diff --git a/vnext/ReactUWP/Modules/Animated/NativeAnimatedNodeManager.h b/vnext/ReactUWP/Modules/Animated/NativeAnimatedNodeManager.h new file mode 100644 index 00000000000..8eb6d02e101 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/NativeAnimatedNodeManager.h @@ -0,0 +1,76 @@ +#pragma once +// Copyright (c) Microsoft Corporation. All rights reserved. +// Portions derived from React Native: +// Copyright (c) 2015-present, Facebook, Inc. +// Licensed under the MIT License. + +#include +#include "AnimatedNode.h" +#include "StyleAnimatedNode.h" +#include "PropsAnimatedNode.h" +#include "ValueAnimatedNode.h" +#include "AnimationDriver.h" +#include "TransformAnimatedNode.h" +#include "EventAnimationDriver.h" +#include +#include + +namespace react { namespace uwp { + /// + /// This is the main class that coordinates how native animated JS + /// implementation drives UI changes. + /// + /// It implements a management interface for animated nodes graph and + /// establishes a number of composistion animations and property sets to + /// drive the animating of the nodes to the Xaml elements off the UI Thread + /// + /// + + typedef std::function)> Callback; + + class AnimatedNode; + class StyleAnimatedNode; + class PropsAnimatedNode; + class ValueAnimatedNode; + class TransformAnimatedNode; + class AnimationDriver; + class EventAnimationDriver; + class NativeAnimatedNodeManager + { + public: + void CreateAnimatedNode(int64_t tag, const folly::dynamic& config, const std::weak_ptr& instance, const std::shared_ptr& manager); + void ConnectAnimatedNodeToView(int64_t propsNodeTag, int64_t viewTag); + void DisconnectAnimatedNodeToView(int64_t propsNodeTag, int64_t viewTag); + void ConnectAnimatedNode(int64_t parentNodeTag, int64_t childNodeTag); + void DisconnectAnimatedNode(int64_t parentNodeTag, int64_t childNodeTag); + void StopAnimation(int64_t animationId); + void StartAnimatingNode(int64_t animationId, int64_t animatedNodeTag, const folly::dynamic& animationConfig, const Callback& endCallback, const std::shared_ptr& manager); + void DropAnimatedNode(int64_t tag); + void SetAnimatedNodeValue(int64_t tag, double value); + void SetAnimatedNodeOffset(int64_t tag, double offset); + void FlattenAnimatedNodeOffset(int64_t tag); + void ExtractAnimatedNodeOffset(int64_t tag); + void AddAnimatedEventToView(int64_t viewTag, const std::string& eventName, const folly::dynamic& eventMapping, const std::shared_ptr& manager); + void RemoveAnimatedEventFromView(int64_t viewTag, const std::string& eventName, int64_t animatedValueTag); + void ProcessDelayedPropsNodes(); + void AddDelayedPropsNode(int64_t propsNodeTag, const std::shared_ptr& instance); + + AnimationDriver* GetAnimationNode(int64_t tag); + + AnimatedNode* GetAnimatedNode(int64_t tag); + ValueAnimatedNode* GetValueAnimatedNode(int64_t tag); + PropsAnimatedNode* GetPropsAnimatedNode(int64_t tag); + StyleAnimatedNode* GetStyleAnimatedNode(int64_t tag); + TransformAnimatedNode* GetTransformAnimatedNode(int64_t tag); + + private: + std::unordered_map> m_animationNodes{}; + std::unordered_map> m_valueNodes{}; + std::unordered_map> m_propsNodes{}; + std::unordered_map> m_styleNodes{}; + std::unordered_map> m_transformNodes{}; + std::unordered_map, std::vector>> m_eventDrivers{}; + std::unordered_map> m_activeAnimations{}; + std::vector m_delayedPropsNodes{}; + }; +} } diff --git a/vnext/ReactUWP/Modules/Animated/PropsAnimatedNode.cpp b/vnext/ReactUWP/Modules/Animated/PropsAnimatedNode.cpp new file mode 100644 index 00000000000..b84281eb0c3 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/PropsAnimatedNode.cpp @@ -0,0 +1,232 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "PropsAnimatedNode.h" +#include +#include +#include "StyleAnimatedNode.h" +#include "NativeAnimatedNodeManager.h" + +namespace react { namespace uwp { + PropsAnimatedNode::PropsAnimatedNode(int64_t tag, const folly::dynamic& config, const std::weak_ptr& instance, const std::shared_ptr& manager) : + AnimatedNode(tag, manager), m_instance(instance) + { + for (const auto& entry : config.find("props").dereference().second.items()) + { + m_propMapping.insert({ entry.first.getString(), entry.second.getInt() }); + } + } + + void PropsAnimatedNode::ConnectToView(int64_t viewTag) + { + if (m_connectedViewTag != s_connectedViewTagUnset) + { + throw new std::invalid_argument("Animated node " + std::to_string(m_tag) + " has already been attached to a view already exists."); + return; + } + m_connectedViewTag = viewTag; + UpdateView(); + } + + void PropsAnimatedNode::DisconnectFromView(int64_t viewTag) + { + if (m_connectedViewTag != viewTag) + { + throw new std::invalid_argument("Attempting to disconnect view that has not been connected with the given animated node."); + return; + } + + std::vector keys{}; + for (const auto& anim : m_expressionAnimations) + { + keys.push_back(anim.first); + } + for(const auto& key : keys) + { + DisposeCompletedAnimation(key); + } + + if (m_centerPointAnimation) + { + if (const auto target = GetUIElement()) + { + target.StopAnimation(m_centerPointAnimation); + } + m_centerPointAnimation = nullptr; + } + + m_connectedViewTag = s_connectedViewTagUnset; + m_needsCenterPointAnimation = false; + } + + void PropsAnimatedNode::RestoreDefaultValues() + { + + } + + void PropsAnimatedNode::UpdateView() + { + if (m_connectedViewTag == s_connectedViewTagUnset) + { + return; + } + + if (const auto manager = std::shared_ptr(m_manager)) + { + for (const auto& entry : m_propMapping) + { + if (const auto& styleNode = manager->GetStyleAnimatedNode(entry.second)) + { + for (const auto& styleEntry : styleNode->GetMapping()) + { + MakeAnimation(styleEntry.second, styleEntry.first); + } + } + else if (const auto& valueNode = manager->GetValueAnimatedNode(entry.second)) + { + MakeAnimation(entry.second, StringToFacadeType(entry.first)); + } + } + } + + StartAnimations(); + } + + void PropsAnimatedNode::StartAnimations() + { + if (m_expressionAnimations.size()) + { + if (const auto uiElement = GetUIElement()) + { + uiElement.RotationAxis(m_rotationAxis); + for (const auto anim : m_expressionAnimations) + { + uiElement.StartAnimation(anim.second); + } + if (m_needsCenterPointAnimation) + { + if (!m_centerPointAnimation) + { + m_centerPointAnimation = winrt::Window::Current().Compositor().CreateExpressionAnimation(); + m_centerPointAnimation.Target(L"CenterPoint"); + m_centerPointAnimation.SetReferenceParameter(L"centerPointPropertySet", GetShadowNodeBase()->EnsureTransformPS()); + m_centerPointAnimation.Expression(L"centerPointPropertySet.center"); + } + + uiElement.StartAnimation(m_centerPointAnimation); + } + } + else + { + if (const auto instance = m_instance.lock()) + { + if (const auto manager = m_manager.lock()) + { + manager->AddDelayedPropsNode(Tag(), instance); + } + } + } + } + } + + void PropsAnimatedNode::DisposeCompletedAnimation(int64_t valueTag) + { + if (m_expressionAnimations.count(valueTag)) + { + if (const auto target = GetUIElement()) + { + target.StopAnimation(m_expressionAnimations.at(valueTag)); + } + m_expressionAnimations.erase(valueTag); + } + } + + void PropsAnimatedNode::MakeAnimation(int64_t valueNodeTag, FacadeType facadeType) + { + if (const auto manager = m_manager.lock()) + { + if (const auto valueNode = manager->GetValueAnimatedNode(valueNodeTag)) + { + const auto animation = winrt::Window::Current().Compositor().CreateExpressionAnimation(); + animation.SetReferenceParameter(L"ValuePropSet", valueNode->PropertySet()); + animation.Expression(L"ValuePropSet.value + ValuePropSet.offset"); + switch (facadeType) + { + case FacadeType::Opacity: + animation.Target(L"Opacity"); + break; + case FacadeType::Rotation: + m_rotationAxis = { 0,0,1 }; + animation.Expression(L"(ValuePropSet.value + ValuePropSet.offset) * 180 / PI"); + animation.Target(L"Rotation"); + m_needsCenterPointAnimation = true; + break; + case FacadeType::RotationX: + animation.Expression(L"(ValuePropSet.value + ValuePropSet.offset) * 180 / PI"); + m_rotationAxis = { 1,0,0 }; + animation.Target(L"Rotation"); + m_needsCenterPointAnimation = true; + break; + case FacadeType::RotationY: + animation.Expression(L"(ValuePropSet.value + ValuePropSet.offset) * 180 / PI"); + m_rotationAxis = { 0,1,0 }; + animation.Target(L"Rotation"); + m_needsCenterPointAnimation = true; + break; + case FacadeType::Scale: + animation.Expression(L"Vector3(ValuePropSet.value + ValuePropSet.offset, ValuePropSet.value + ValuePropSet.offset, 0)"); + animation.Target(L"Scale"); + m_needsCenterPointAnimation = true; + break; + case FacadeType::ScaleX: + animation.Target(L"Scale.X"); + m_needsCenterPointAnimation = true; + break; + case FacadeType::ScaleY: + animation.Target(L"Scale.Y"); + m_needsCenterPointAnimation = true; + break; + case FacadeType::TranslateX: + animation.Target(L"Translation.X"); + break; + case FacadeType::TranslateY: + animation.Target(L"Translation.Y"); + break; + case FacadeType::Perspective: + // TODO: implement perspective animations, tracked by issue #2680 + return; + default: + assert(false); + } + m_expressionAnimations.insert({ valueNode->Tag(), animation }); + valueNode->AddDependentPropsNode(Tag()); + } + } + } + + + ShadowNodeBase* PropsAnimatedNode::GetShadowNodeBase() + { + if (const auto instance = m_instance.lock()) + { + if (const auto nativeUIManagerHost = static_cast(instance->NativeUIManager())->getHost()) + { + return static_cast(nativeUIManagerHost->FindShadowNodeForTag(m_connectedViewTag)); + } + } + return nullptr; + } + + winrt::UIElement PropsAnimatedNode::GetUIElement() + { + if(const auto shadowNodeBase = GetShadowNodeBase()) + { + if (const auto shadowNodeView = shadowNodeBase->GetView()) + { + return shadowNodeView.as(); + } + } + return nullptr; + } +} } diff --git a/vnext/ReactUWP/Modules/Animated/PropsAnimatedNode.h b/vnext/ReactUWP/Modules/Animated/PropsAnimatedNode.h new file mode 100644 index 00000000000..a4bd3926d2a --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/PropsAnimatedNode.h @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "AnimatedNode.h" +#include +#include + +#include "FacadeType.h" + +namespace react { namespace uwp { + struct ShadowNodeBase; + class PropsAnimatedNode : public AnimatedNode + { + public: + PropsAnimatedNode(int64_t tag, const folly::dynamic& config, const std::weak_ptr& instance, const std::shared_ptr& manager); + void ConnectToView(int64_t viewTag); + void DisconnectFromView(int64_t viewTag); + void RestoreDefaultValues(); + void UpdateView(); + void StartAnimations(); + void DisposeCompletedAnimation(int64_t valueTag); + + private: + void MakeAnimation(int64_t valueNodeTag, FacadeType facadeType); + ShadowNodeBase* GetShadowNodeBase(); + winrt::UIElement GetUIElement(); + + std::weak_ptr m_instance{}; + std::map m_propMapping{}; + folly::dynamic m_propMap{}; + + int64_t m_connectedViewTag{ s_connectedViewTagUnset }; + std::unordered_map m_expressionAnimations{}; + winrt::Windows::UI::Composition::ExpressionAnimation m_centerPointAnimation{ nullptr }; + winrt::Numerics::float3 m_rotationAxis{ 0,0,1 }; + bool m_needsCenterPointAnimation{ false }; + + static constexpr int64_t s_connectedViewTagUnset{ -1 }; + }; +} } diff --git a/vnext/ReactUWP/Modules/Animated/StyleAnimatedNode.cpp b/vnext/ReactUWP/Modules/Animated/StyleAnimatedNode.cpp new file mode 100644 index 00000000000..6d6320b3a16 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/StyleAnimatedNode.cpp @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "StyleAnimatedNode.h" +#include "FacadeType.h" +#include "NativeAnimatedNodeManager.h" + +namespace react { namespace uwp { + StyleAnimatedNode::StyleAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager) : AnimatedNode(tag, manager) + { + for (const auto& entry : config.find(s_styleName).dereference().second.items()) + { + m_propMapping.insert({ entry.first.getString(), entry.second.getInt() }); + } + } + + void StyleAnimatedNode::CollectViewUpdates(const folly::dynamic& propsMap) + { + + } + + std::unordered_map StyleAnimatedNode::GetMapping() + { + std::unordered_map mapping; + for (const auto& prop : m_propMapping) + { + if (const auto manager = m_manager.lock()) + { + if (const auto transformNode = manager->GetTransformAnimatedNode(prop.second)) + { + const auto transformMapping = transformNode->GetMapping(); + mapping.insert(transformMapping.begin(), transformMapping.end()); + break; + } + } + mapping.insert({ StringToFacadeType(prop.first), prop.second }); + } + return mapping; + } +} } diff --git a/vnext/ReactUWP/Modules/Animated/StyleAnimatedNode.h b/vnext/ReactUWP/Modules/Animated/StyleAnimatedNode.h new file mode 100644 index 00000000000..e878a46605d --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/StyleAnimatedNode.h @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "AnimatedNode.h" +#include +#include "FacadeType.h" + +namespace react { namespace uwp { + class StyleAnimatedNode : public AnimatedNode + { + public: + StyleAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager); + void CollectViewUpdates(const folly::dynamic& propsMap); + + std::unordered_map GetMapping(); + private: + std::map m_propMapping{}; + + static constexpr std::string_view s_styleName{ "style" }; + }; +} } diff --git a/vnext/ReactUWP/Modules/Animated/SubtractionAnimatedNode.cpp b/vnext/ReactUWP/Modules/Animated/SubtractionAnimatedNode.cpp new file mode 100644 index 00000000000..1b5df42a60d --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/SubtractionAnimatedNode.cpp @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "SubtractionAnimatedNode.h" +#include "NativeAnimatedNodeManager.h" + +namespace react { namespace uwp { + SubtractionAnimatedNode::SubtractionAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager) : ValueAnimatedNode(tag, config, manager) + { + for (const auto& inputNode : config.find(s_inputName).dereference().second) + { + if (m_firstInput == s_firstInputUnset) + { + m_firstInput = static_cast(inputNode.asDouble()); + } + else + { + m_inputNodes.insert(static_cast(inputNode.asDouble())); + } + } + + m_propertySet.StartAnimation(s_valueName, + [firstNode = m_firstInput, nodes = m_inputNodes, manager]() + { + const auto anim = winrt::Window::Current().Compositor().CreateExpressionAnimation(); + + anim.Expression([firstNode, nodes, manager, anim]() + { + anim.SetReferenceParameter(s_baseName, manager->GetValueAnimatedNode(firstNode)->PropertySet()); + winrt::hstring expr = static_cast(L"(") + s_baseName + L"." + s_valueName + L" + " + s_baseName + L"." + s_offsetName + L")"; + for (const auto tag : nodes) + { + const auto identifier = std::to_wstring(tag); + anim.SetReferenceParameter(identifier, manager->GetValueAnimatedNode(tag)->PropertySet()); + expr = expr + L" - (" + identifier + L"." + s_valueName + L" + " + identifier + L"." + s_offsetName+ L")"; + } + return expr; + }()); + return anim; + }()); + } +} } diff --git a/vnext/ReactUWP/Modules/Animated/SubtractionAnimatedNode.h b/vnext/ReactUWP/Modules/Animated/SubtractionAnimatedNode.h new file mode 100644 index 00000000000..04f0a4b4a0f --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/SubtractionAnimatedNode.h @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "ValueAnimatedNode.h" +#include + +namespace react { namespace uwp { + class SubtractionAnimatedNode : public ValueAnimatedNode + { + public: + SubtractionAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager); + + private: + int64_t m_firstInput{ s_firstInputUnset }; + std::unordered_set m_inputNodes{}; + + static constexpr int64_t s_firstInputUnset{ -1 }; + + static constexpr std::wstring_view s_baseName{ L"base" }; + }; +} } diff --git a/vnext/ReactUWP/Modules/Animated/TransformAnimatedNode.cpp b/vnext/ReactUWP/Modules/Animated/TransformAnimatedNode.cpp new file mode 100644 index 00000000000..c0a29ed5178 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/TransformAnimatedNode.cpp @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "TransformAnimatedNode.h" +#include "FacadeType.h" + +namespace react { + namespace uwp { + TransformAnimatedNode::TransformAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager) : AnimatedNode(tag, manager) + { + for (const auto& transform : config.find(s_transformsName).dereference().second) + { + const auto property = transform.find(s_propertyName).dereference().second.asString(); + if (transform.find(s_typeName).dereference().second.asString() == s_animatedName) + { + m_transformConfigs.push_back(TransformConfig{ property, static_cast(transform.find(s_nodeTagName).dereference().second.asDouble()), 0 }); + } + else + { + m_transformConfigs.push_back(TransformConfig{ property, s_unsetNodeTag, transform.find(s_valueName).dereference().second.asDouble() }); + } + } + } + + std::unordered_map TransformAnimatedNode::GetMapping() + { + std::unordered_map mapping; + for (const auto& config : m_transformConfigs) + { + if (config.nodeTag != s_unsetNodeTag) + { + mapping.insert({ StringToFacadeType(config.property), config.nodeTag }); + } + } + return mapping; + } + } +} diff --git a/vnext/ReactUWP/Modules/Animated/TransformAnimatedNode.h b/vnext/ReactUWP/Modules/Animated/TransformAnimatedNode.h new file mode 100644 index 00000000000..14827c066b4 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/TransformAnimatedNode.h @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "AnimatedNode.h" +#include +#include "FacadeType.h" + +namespace react { + namespace uwp { + struct TransformConfig + { + public: + std::string property; + int64_t nodeTag; + double value; + }; + + class TransformAnimatedNode : public AnimatedNode + { + public: + TransformAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager); + std::unordered_map GetMapping(); + private: + std::vector m_transformConfigs; + + static constexpr int64_t s_unsetNodeTag{ -1 }; + + static constexpr std::string_view s_transformsName{ "transforms" }; + static constexpr std::string_view s_propertyName{ "property" }; + static constexpr std::string_view s_typeName{ "type" }; + static constexpr std::string_view s_animatedName{ "animated" }; + static constexpr std::string_view s_nodeTagName{ "nodeTag" }; + static constexpr std::string_view s_valueName{ "value" }; + }; + } +} diff --git a/vnext/ReactUWP/Modules/Animated/ValueAnimatedNode.cpp b/vnext/ReactUWP/Modules/Animated/ValueAnimatedNode.cpp new file mode 100644 index 00000000000..2586ef800bd --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/ValueAnimatedNode.cpp @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "ValueAnimatedNode.h" +#include "NativeAnimatedNodeManager.h" + +namespace react { namespace uwp { + ValueAnimatedNode::ValueAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager) : AnimatedNode(tag, manager) + { + m_propertySet = winrt::Window::Current().Compositor().CreatePropertySet(); + m_propertySet.InsertScalar(s_valueName, static_cast(config.find(s_jsValueName).dereference().second.asDouble())); + m_propertySet.InsertScalar(s_offsetName, static_cast(config.find(s_jsOffsetName).dereference().second.asDouble())); + } + + ValueAnimatedNode::ValueAnimatedNode(int64_t tag, const std::shared_ptr& manager) : AnimatedNode(tag, manager) + { + m_propertySet = winrt::Window::Current().Compositor().CreatePropertySet(); + m_propertySet.InsertScalar(s_valueName, 0.0); + m_propertySet.InsertScalar(s_offsetName, 0.0); + } + + double ValueAnimatedNode::RawValue() + { + auto rawValue = 0.0f; + m_propertySet.TryGetScalar(s_valueName, rawValue); + return rawValue; + } + + void ValueAnimatedNode::RawValue(double value) + { + m_propertySet.InsertScalar(s_valueName, static_cast(value)); + } + + double ValueAnimatedNode::Offset() + { + auto offset = 0.0f; + m_propertySet.TryGetScalar(s_offsetName, offset); + return offset; + } + + void ValueAnimatedNode::Offset(double offset) + { + m_propertySet.InsertScalar(s_offsetName, static_cast(offset)); + } + + double ValueAnimatedNode::Value() + { + auto rawValue = 0.0f; + auto offset = 0.0f; + m_propertySet.TryGetScalar(s_valueName, rawValue); + m_propertySet.TryGetScalar(s_offsetName, offset); + return static_cast(rawValue) + static_cast(offset); + } + + void ValueAnimatedNode::FlattenOffset() + { + RawValue(RawValue() + Offset()); + Offset(0.0f); + } + + void ValueAnimatedNode::ExtractOffset() + { + Offset(RawValue() + Offset()); + RawValue(0.0f); + } + + void ValueAnimatedNode::AddDependentPropsNode(int64_t propsNodeTag) + { + m_dependentPropsNodes.insert(propsNodeTag); + } + + void ValueAnimatedNode::RemoveDependentPropsNode(int64_t propsNodeTag) + { + m_dependentPropsNodes.erase(propsNodeTag); + } + + void ValueAnimatedNode::AddActiveAnimation(int64_t animationTag) + { + m_activeAnimations.insert(animationTag); + } + + void ValueAnimatedNode::RemoveActiveAnimation(int64_t animationTag) + { + m_activeAnimations.erase(animationTag); + if (!m_activeAnimations.size()) + { + if (const auto manager = m_manager.lock()) + { + for (const auto& props : m_dependentPropsNodes) + { + manager->GetPropsAnimatedNode(props)->DisposeCompletedAnimation(Tag()); + } + } + } + } +} } diff --git a/vnext/ReactUWP/Modules/Animated/ValueAnimatedNode.h b/vnext/ReactUWP/Modules/Animated/ValueAnimatedNode.h new file mode 100644 index 00000000000..13469f63960 --- /dev/null +++ b/vnext/ReactUWP/Modules/Animated/ValueAnimatedNode.h @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "AnimatedNode.h" +#include + +namespace winrt +{ + using namespace winrt::Windows::UI::Composition; +} + +namespace react { namespace uwp { + class ValueAnimatedNode : public AnimatedNode + { + public: + ValueAnimatedNode(int64_t tag, const folly::dynamic& config, const std::shared_ptr& manager); + ValueAnimatedNode(int64_t tag, const std::shared_ptr& manager); + double Value(); + double RawValue(); + void RawValue(double value); + double Offset(); + void Offset(double offset); + void FlattenOffset(); + void ExtractOffset(); + winrt::CompositionPropertySet PropertySet() { return m_propertySet; }; + + void AddDependentPropsNode(int64_t propsNodeTag); + void RemoveDependentPropsNode(int64_t propsNodeTag); + void AddActiveAnimation(int64_t animationTag); + void RemoveActiveAnimation(int64_t animationTag); + + protected: + winrt::CompositionPropertySet m_propertySet{ nullptr }; + + static constexpr std::string_view s_inputName{ "input" }; + + static constexpr std::string_view s_jsValueName{ "value" }; + static constexpr std::string_view s_jsOffsetName{ "offset" }; + + static constexpr std::wstring_view s_valueName{ L"value" }; + static constexpr std::wstring_view s_offsetName{ L"offset" }; + + private: + std::unordered_set m_dependentPropsNodes{}; + std::unordered_set m_activeAnimations{}; + }; +} } diff --git a/vnext/ReactUWP/Modules/AppThemeModuleUwp.cpp b/vnext/ReactUWP/Modules/AppThemeModuleUwp.cpp new file mode 100644 index 00000000000..41ecdda0eae --- /dev/null +++ b/vnext/ReactUWP/Modules/AppThemeModuleUwp.cpp @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "AppThemeModuleUwp.h" + +#include + +#if _MSC_VER <= 1913 +// VC 19 (2015-2017.6) cannot optimize co_await/cppwinrt usage +#pragma optimize( "", off ) +#endif + +namespace winrt { + using namespace Windows::UI::Xaml; + using namespace Windows::UI::ViewManagement; +} + +namespace react { namespace uwp { + +// +// AppTheme +// + +AppTheme::AppTheme(const std::shared_ptr& reactInstance, const std::shared_ptr& defaultQueueThread) : react::windows::AppTheme() + , m_wkReactInstance(reactInstance) + , m_queueThread(defaultQueueThread) +{ + m_currentTheme = winrt::Application::Current().RequestedTheme(); + m_isHighContrast = m_accessibilitySettings.HighContrast(); + m_highContrastColors = getHighContrastColors(); + + m_highContrastChangedRevoker = m_accessibilitySettings.HighContrastChanged(winrt::auto_revoke, + [this](const auto&, const auto&) { + + folly::dynamic eventData = folly::dynamic::object("highContrastColors", getHighContrastColors()) + ("isHighContrast", getIsHighContrast()); + + fireEvent("highContrastChanged", std::move(eventData)); + }); + + m_colorValuesChangedRevoker = m_uiSettings.ColorValuesChanged(winrt::auto_revoke, + [this](const auto&, const auto&) { + + m_queueThread->runOnQueue([this]() { + if (m_currentTheme != winrt::Application::Current().RequestedTheme() && !m_accessibilitySettings.HighContrast()) + { + m_currentTheme = winrt::Application::Current().RequestedTheme(); + + folly::dynamic eventData = folly::dynamic::object("currentTheme", getCurrentTheme()); + + fireEvent("appThemeChanged", std::move(eventData)); + } + }); + }); +} + +AppTheme::~AppTheme() = default; + +const std::string AppTheme::getCurrentTheme() +{ + return m_currentTheme == winrt::ApplicationTheme::Light ? AppTheme::light : AppTheme::dark; +} + +bool AppTheme::getIsHighContrast() +{ + return m_accessibilitySettings.HighContrast();; +} + +// Returns the RBG values for the 8 relevant High Contrast elements. +folly::dynamic AppTheme::getHighContrastColors() { + winrt::Windows::UI::Color ButtonFaceColor = m_uiSettings.UIElementColor(winrt::UIElementType::ButtonFace); + winrt::Windows::UI::Color ButtonTextColor = m_uiSettings.UIElementColor(winrt::UIElementType::ButtonText); + winrt::Windows::UI::Color GrayTextColor = m_uiSettings.UIElementColor(winrt::UIElementType::GrayText); + winrt::Windows::UI::Color HighlightColor = m_uiSettings.UIElementColor(winrt::UIElementType::Highlight); + winrt::Windows::UI::Color HighlightTextColor = m_uiSettings.UIElementColor(winrt::UIElementType::HighlightText); + winrt::Windows::UI::Color HotlightColor = m_uiSettings.UIElementColor(winrt::UIElementType::Hotlight); + winrt::Windows::UI::Color WindowColor = m_uiSettings.UIElementColor(winrt::UIElementType::Window); + winrt::Windows::UI::Color WindowTextColor = m_uiSettings.UIElementColor(winrt::UIElementType::WindowText); + + folly::dynamic rbgValues = folly::dynamic::object("ButtonFaceColor", formatRGB(ButtonFaceColor)) + ("ButtonTextColor", formatRGB(ButtonTextColor)) + ("GrayTextColor", formatRGB(GrayTextColor)) + ("HighlightColor", formatRGB(HighlightColor)) + ("HighlightTextColor", formatRGB(HighlightTextColor)) + ("HotlightColor", formatRGB(HotlightColor)) + ("WindowColor", formatRGB(WindowColor)) + ("WindowTextColor", formatRGB(WindowTextColor)); + return rbgValues; +} + +std::string AppTheme::formatRGB(winrt::Windows::UI::Color ElementColor) { + char colorChars[8]; + sprintf_s(colorChars, "#%02x%02x%02x", ElementColor.R, ElementColor.G, ElementColor.B); + return colorChars; +} + +void AppTheme::fireEvent(std::string const& eventName, folly::dynamic&& eventData) +{ + if (auto instance = m_wkReactInstance.lock()) + { + instance->CallJsFunction("RCTDeviceEventEmitter", "emit", folly::dynamic::array(eventName, std::move(eventData))); + } +} +} } // namespace react::uwp diff --git a/vnext/ReactUWP/Modules/AppThemeModuleUwp.h b/vnext/ReactUWP/Modules/AppThemeModuleUwp.h new file mode 100644 index 00000000000..17cbb368e09 --- /dev/null +++ b/vnext/ReactUWP/Modules/AppThemeModuleUwp.h @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include +#include + +namespace react { namespace uwp { + +class AppTheme : public react::windows::AppTheme +{ +public: + AppTheme(const std::shared_ptr& reactInstance, const std::shared_ptr& defaultQueueThread); + virtual ~AppTheme(); + + const std::string getCurrentTheme() override; + bool getIsHighContrast() override; + +private: + // High Contrast Color helper methods + folly::dynamic getHighContrastColors(); + std::string formatRGB(winrt::Windows::UI::Color ElementColor); + + void fireEvent(std::string const& eventName, folly::dynamic&& eventData); + + std::weak_ptr m_wkReactInstance; + std::shared_ptr m_queueThread; + winrt::Windows::UI::Xaml::ApplicationTheme m_currentTheme{ winrt::Windows::UI::Xaml::ApplicationTheme::Light }; + bool m_isHighContrast; + folly::dynamic m_highContrastColors; + + winrt::Windows::UI::ViewManagement::AccessibilitySettings m_accessibilitySettings{ }; + winrt::Windows::UI::ViewManagement::AccessibilitySettings::HighContrastChanged_revoker m_highContrastChangedRevoker{ }; + winrt::Windows::UI::ViewManagement::UISettings m_uiSettings{ }; + winrt::Windows::UI::ViewManagement::UISettings::ColorValuesChanged_revoker m_colorValuesChangedRevoker{ }; +}; + +} } // namespace react::uwp diff --git a/vnext/ReactUWP/Modules/LinkingManagerModule.cpp b/vnext/ReactUWP/Modules/LinkingManagerModule.cpp index c83c7650594..ef66663fa1e 100644 --- a/vnext/ReactUWP/Modules/LinkingManagerModule.cpp +++ b/vnext/ReactUWP/Modules/LinkingManagerModule.cpp @@ -35,11 +35,15 @@ static winrt::fire_and_forget openURLAsync(winrt::Windows::Foundation::Uri uri, } else { - error({}); + error({ + folly::dynamic::object + ("code", 1) + ("message", "Unable to open URL:" + facebook::react::unicode::utf16ToUtf8(uri.DisplayUri())) + }); } } -static winrt::fire_and_forget canOpenURLAsync(winrt::Windows::Foundation::Uri uri, Callback success, Callback error) +static winrt::fire_and_forget canOpenURLAsync(winrt::Windows::Foundation::Uri uri, Callback success, Callback /*error*/) { winrt::Windows::System::LaunchQuerySupportStatus status = co_await winrt::Windows::System::Launcher::QueryUriSupportAsync(uri, winrt::Windows::System::LaunchQuerySupportType::Uri); if (status == winrt::Windows::System::LaunchQuerySupportStatus::Available) @@ -48,7 +52,7 @@ static winrt::fire_and_forget canOpenURLAsync(winrt::Windows::Foundation::Uri ur } else { - error({}); + success({ false }); } } diff --git a/vnext/ReactUWP/Modules/NativeUIManager.cpp b/vnext/ReactUWP/Modules/NativeUIManager.cpp index 76580cc7d18..cac023482b6 100644 --- a/vnext/ReactUWP/Modules/NativeUIManager.cpp +++ b/vnext/ReactUWP/Modules/NativeUIManager.cpp @@ -93,6 +93,11 @@ void NativeUIManager::DirtyYogaNode(int64_t tag) } } +void NativeUIManager::AddBatchCompletedCallback(std::function callback) +{ + m_batchCompletedCallbacks.push_back(std::move(callback)); +} + winrt::XamlRoot NativeUIManager::tryGetXamlRoot() { if (m_host) @@ -112,6 +117,33 @@ winrt::XamlRoot NativeUIManager::tryGetXamlRoot() return nullptr; } +XamlView NativeUIManager::reactPeerOrContainerFrom(winrt::FrameworkElement fe) +{ + if (m_host) + { + while (fe) + { + if (auto value = GetTagAsPropertyValue(fe)) + { + auto tag = GetTag(value); + if (auto shadowNode = static_cast(m_host->FindShadowNodeForTag(tag))) + { + if (auto xamlView = shadowNode->GetView()) + { + if (xamlView == fe) + { + return xamlView; + } + } + + } + } + fe = fe.Parent().try_as(); + } + } + return nullptr; +} + NativeUIManager::NativeUIManager() { #if defined(_DEBUG) @@ -206,6 +238,13 @@ void NativeUIManager::onBatchComplete() { DoLayout(); m_inBatch = false; + + const auto callbacks = m_batchCompletedCallbacks; + m_batchCompletedCallbacks.clear(); + for (const auto& callback : callbacks) + { + callback.operator()(); + } } } diff --git a/vnext/ReactUWP/Modules/NativeUIManager.h b/vnext/ReactUWP/Modules/NativeUIManager.h index 41f503af47a..54bf8a605bc 100644 --- a/vnext/ReactUWP/Modules/NativeUIManager.h +++ b/vnext/ReactUWP/Modules/NativeUIManager.h @@ -52,12 +52,17 @@ class NativeUIManager : public facebook::react::INativeUIManager // Other public functions void DirtyYogaNode(int64_t tag); + void AddBatchCompletedCallback(std::function callback); // For unparented node like Flyout, XamlRoot should be set to handle XamlIsland/AppWindow scenarios. // Since it doesn't have parent, and all nodes in the tree should have the same XamlRoot, // this function iterates all roots and try to get a valid XamlRoot. winrt::XamlRoot tryGetXamlRoot(); + // Searches itself and its parent to get a valid XamlView. + // Like Mouse/Keyboard, the event source may not have matched XamlView. + XamlView reactPeerOrContainerFrom(winrt::FrameworkElement fe); + private: void DoLayout(); void UpdateExtraLayout(int64_t tag); @@ -70,6 +75,7 @@ class NativeUIManager : public facebook::react::INativeUIManager std::map m_tagsToYogaNodes; std::map> m_tagsToYogaContext; std::vector m_sizeChangedVector; + std::vector> m_batchCompletedCallbacks; }; } } diff --git a/vnext/ReactUWP/ReactUWP.vcxproj b/vnext/ReactUWP/ReactUWP.vcxproj index eb6496576ec..3ff9cf63687 100644 --- a/vnext/ReactUWP/ReactUWP.vcxproj +++ b/vnext/ReactUWP/ReactUWP.vcxproj @@ -1,14 +1,10 @@ - + Debug ARM - - Debug - x86 - Debug x64 @@ -17,15 +13,10 @@ Release ARM - - Release - x86 - Release x64 - Debug Win32 @@ -75,12 +66,15 @@ Use false true - - OLD_CPPWINRT;REACTWINDOWS_BUILD;RN_PLATFORM=uwp;USE_EDGEMODE_JSRT;NOMINMAX;FOLLY_NO_CONFIG;RN_EXPORT=;JSI_EXPORT=;WIN32=0;WINRT=1;NOJSC;_HAS_AUTO_PTR_ETC;%(PreprocessorDefinitions) + CHAKRACORE;CHAKRACORE_UWP;%(PreprocessorDefinitions) + USE_EDGEMODE_JSRT;%(PreprocessorDefinitions) + OLD_CPPWINRT;REACTWINDOWS_BUILD;RN_PLATFORM=uwp;NOMINMAX;FOLLY_NO_CONFIG;RN_EXPORT=;JSI_EXPORT=;WIN32=0;WINRT=1;NOJSC;_HAS_AUTO_PTR_ETC;%(PreprocessorDefinitions) $(ReactNativeWindowsDir);$(ReactNativeWindowsDir)Pch;$(ReactNativeWindowsDir)ReactUWP\GeneratedWinmdHeader;$(ReactNativeWindowsDir)ReactWindowsCore;$(ReactNativeWindowsDir)include\ReactWindowsCore;$(ReactNativeWindowsDir)include\ReactUWP;$(YogaDir);$(ReactNativeDir)\ReactCommon;$(ReactNativeWindowsDir)include;$(ReactNativeWindowsDir)stubs;$(ReactNativeWindowsDir)Shared;$(FollyDir);%(AdditionalIncludeDirectories) + $(ChakraCoreInclude);$(ChakraCoreDebugInclude);%(AdditionalIncludeDirectories) stdcpp17 /await %(AdditionalOptions) false @@ -90,6 +84,8 @@ true DebugFull -minpdbpathlen:256 + ChakraCore.Debugger.Protocol.lib;ChakraCore.Debugger.ProtocolHandler.lib;ChakraCore.Debugger.Service.lib;ChakraCore.lib;%(AdditionalDependencies) + $(ChakraCoreLibDir);$(ChakraCoreDebugLibDir) dxguid.lib;%(AdditionalDependencies) @@ -153,6 +149,7 @@ + @@ -162,8 +159,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -191,15 +214,14 @@ - - - - - + + + + + - @@ -224,9 +246,12 @@ + + + @@ -245,12 +270,34 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -306,9 +353,14 @@ + + + + + @@ -355,17 +407,15 @@ - - - + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + diff --git a/vnext/ReactUWP/ReactUWP.vcxproj.filters b/vnext/ReactUWP/ReactUWP.vcxproj.filters index 74bdcec1dce..cecb943c962 100644 --- a/vnext/ReactUWP/ReactUWP.vcxproj.filters +++ b/vnext/ReactUWP/ReactUWP.vcxproj.filters @@ -61,6 +61,51 @@ Executors + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + Shared @@ -160,6 +205,9 @@ Views + + Views + Shared @@ -175,7 +223,9 @@ Polyester - + + Shared + Views @@ -197,12 +247,21 @@ Modules + + Modules + Views Views + + Views + + + Views + Views @@ -212,7 +271,9 @@ Views\Impl - + + Views\Impl + Views @@ -231,6 +292,30 @@ Modules + + Utils + + + Views + + + Utils + + + Utils + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Utils + @@ -302,6 +387,51 @@ Executors + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + Modules @@ -395,6 +525,9 @@ Modules + + Modules + Views @@ -419,19 +552,36 @@ Utils - + + Views\cppwinrt + + + Views\cppwinrt + + + Views\cppwinrt + + Views\cppwinrt Views + + Views + + + Views + Views Views\Impl - + + Views\Impl + Views @@ -450,19 +600,7 @@ Views\cppwinrt\winrt\impl - - Views\cppwinrt\winrt\impl - - - Views\cppwinrt\winrt\impl - - - Views\cppwinrt\winrt\impl - - - Views\cppwinrt\winrt - - + Views\cppwinrt @@ -483,6 +621,42 @@ Views\Image + + Utils + + + Views + + + Utils + + + Utils + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Modules\Animated + + + Utils + @@ -557,6 +731,9 @@ {c08ab955-f1a5-41c1-9cc6-5f8bcefaf7e0} + + {A4613589-965A-4B1F-85DB-CEEC21D101DA} + {f74fe3a1-618b-482c-ba94-adc3e6e90ab8} diff --git a/vnext/ReactUWP/Utils/AccessibilityUtils.cpp b/vnext/ReactUWP/Utils/AccessibilityUtils.cpp index 808af03ebaa..50b80674232 100644 --- a/vnext/ReactUWP/Utils/AccessibilityUtils.cpp +++ b/vnext/ReactUWP/Utils/AccessibilityUtils.cpp @@ -13,7 +13,7 @@ using namespace Windows::UI::Xaml::Automation::Peers; namespace react { namespace uwp { -REACTWINDOWS_API_(void) AnnounceLiveRegionChangedIfNeeded(winrt::FrameworkElement element) +REACTWINDOWS_API_(void) AnnounceLiveRegionChangedIfNeeded(const winrt::FrameworkElement& element) { if (winrt::AutomationProperties::GetLiveSetting(element) != winrt::AutomationLiveSetting::Off && !winrt::AutomationProperties::GetName(element).empty()) diff --git a/vnext/ReactUWP/Utils/Helpers.cpp b/vnext/ReactUWP/Utils/Helpers.cpp new file mode 100644 index 00000000000..54d1ee2eb68 --- /dev/null +++ b/vnext/ReactUWP/Utils/Helpers.cpp @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "Helpers.h" +#include + +namespace react { namespace uwp { + +// Not only react-native, native modules could set tag too for controls. +// For example, to identify an clicked item, customer may add tag in NavigationView since content for the two NavigationViewItem are empty. +// +// +// +// +// +// Instead of deduce view id directly from FrameworkElement.Tag, this do additional check by uimanager. +ReactId getViewId(_In_ IReactInstance *instance, winrt::FrameworkElement const& fe) +{ + ReactId reactId; + if (auto uiManager = static_cast(instance->NativeUIManager())) + { + if (auto peer = uiManager->reactPeerOrContainerFrom(fe)) + { + reactId.isValid = true; + reactId.tag = GetTag(peer); + } + } + return reactId; +}; + +void toUpperInplace(string & str) +{ + std::for_each(str.begin(), str.end(), [](char & c) { + c = static_cast(std::toupper(c)); + }); +} + +}}; diff --git a/vnext/ReactUWP/Utils/Helpers.h b/vnext/ReactUWP/Utils/Helpers.h new file mode 100644 index 00000000000..b5635693844 --- /dev/null +++ b/vnext/ReactUWP/Utils/Helpers.h @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include +#include + +namespace winrt { + using namespace Windows::UI::Xaml; +} + +namespace react { namespace uwp { + + using namespace std; + + struct ReactId { + int64_t tag{ 0 }; + bool isValid{ false }; + }; + + template + inline typename T asEnum(folly::dynamic const& obj) + { + return static_cast(obj.asInt()); + } + + void toUpperInplace(string & str); + + ReactId getViewId(_In_ IReactInstance *instance, winrt::FrameworkElement const& fe); +}} diff --git a/vnext/ReactUWP/Utils/PropertyUtils.h b/vnext/ReactUWP/Utils/PropertyUtils.h index fb25a753f4b..4206f2806af 100644 --- a/vnext/ReactUWP/Utils/PropertyUtils.h +++ b/vnext/ReactUWP/Utils/PropertyUtils.h @@ -13,11 +13,15 @@ #include #include #include +#include #include +#include + namespace winrt { using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Documents; } namespace react { namespace uwp { @@ -78,37 +82,44 @@ inline winrt::Windows::UI::Xaml::CornerRadius GetCornerRadius(double cornerRadii return cornerRadius; } -template -void UpdatePadding(ShadowNodeBase* node, const T& element, ShadowEdges edge, double margin) +inline bool IsFlowRTL(const XD::IXamlDirectObject& element) +{ + return XamlDirectInstance::GetXamlDirect().GetEnumProperty(element, XD::XamlPropertyIndex::FrameworkElement_FlowDirection) == static_cast(winrt::FlowDirection::RightToLeft); +} + +static inline void UpdatePadding(ShadowNodeBase* node, XD::IXamlDirectObject element, ShadowEdges edge, double margin, XD::XamlPropertyIndex propertyIndex) { node->m_padding[edge] = margin; - winrt::Thickness thickness = GetThickness(node->m_padding, element.FlowDirection() == winrt::FlowDirection::RightToLeft); - element.Padding(thickness); + winrt::Thickness thickness = GetThickness(node->m_padding, IsFlowRTL(element)); + XamlDirectInstance::GetXamlDirect().SetThicknessProperty(element, propertyIndex, thickness); } -template -void SetBorderThickness(ShadowNodeBase* node, T& element, ShadowEdges edge, double margin) +static inline void SetBorderThickness(ShadowNodeBase* node, XD::IXamlDirectObject element, ShadowEdges edge, double margin, XD::XamlPropertyIndex propertyIndex) { node->m_border[edge] = margin; - winrt::Thickness thickness = GetThickness(node->m_border, element.FlowDirection() == winrt::FlowDirection::RightToLeft); - element.BorderThickness(thickness); + winrt::Thickness thickness = GetThickness(node->m_border, IsFlowRTL(element)); + XamlDirectInstance::GetXamlDirect().SetThicknessProperty(element, propertyIndex, thickness); } -template -void SetBorderBrush(const T& element, const winrt::Windows::UI::Xaml::Media::Brush& brush) +static inline void SetBorderBrush(XD::IXamlDirectObject element, const winrt::Windows::UI::Xaml::Media::Brush& brush, XD::XamlPropertyIndex propertyIndex) { - element.BorderBrush(brush); + XamlDirectInstance::GetXamlDirect().SetColorProperty(element, propertyIndex, brush.as().Color()); } -template -bool TryUpdateBackgroundBrush(T& element, const std::string& propertyName, const folly::dynamic& propertyValue) +static inline bool TryUpdateBackgroundBrush(XD::IXamlDirectObject element, const std::string& propertyName, const folly::dynamic& propertyValue, XD::XamlPropertyIndex propertyIndex) { if (propertyName == "backgroundColor") { if (propertyValue.isNumber()) - element.Background(BrushFrom(propertyValue)); + { + XamlDirectInstance::GetXamlDirect().SetColorProperty( + element, + propertyIndex, + SolidColorBrushFrom(propertyValue).Color() + ); + } else if (propertyValue.isNull()) - element.ClearValue(T::BackgroundProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty(element, propertyIndex); return true; } @@ -116,23 +127,27 @@ bool TryUpdateBackgroundBrush(T& element, const std::string& propertyName, const return false; } -template -void UpdateCornerRadius(ShadowNodeBase* node, T& element, ShadowCorners corner, double newValue) +static inline void UpdateCornerRadius(ShadowNodeBase* node, XD::IXamlDirectObject element, ShadowCorners corner, double newValue, XD::XamlPropertyIndex propertyIndex) { node->m_cornerRadius[corner] = newValue; - winrt::CornerRadius cornerRadius = GetCornerRadius(node->m_cornerRadius, element.FlowDirection() == winrt::FlowDirection::RightToLeft); - element.CornerRadius(cornerRadius); + winrt::CornerRadius cornerRadius = GetCornerRadius(node->m_cornerRadius, IsFlowRTL(element)); + XamlDirectInstance::GetXamlDirect().SetCornerRadiusProperty(element, propertyIndex, cornerRadius); } -template -bool TryUpdateForeground(const T& element, const std::string& propertyName, const folly::dynamic& propertyValue) +static inline bool TryUpdateForeground(XD::IXamlDirectObject element, const std::string& propertyName, const folly::dynamic& propertyValue, XD::XamlPropertyIndex propertyIndex) { if (propertyName == "color") { if (propertyValue.isNumber()) - element.Foreground(BrushFrom(propertyValue)); + { + XamlDirectInstance::GetXamlDirect().SetColorProperty( + element, + propertyIndex, + SolidColorBrushFrom(propertyValue).Color() + ); + } else if (propertyValue.isNull()) - element.ClearValue(T::ForegroundProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty(element, propertyIndex); return true; } @@ -140,52 +155,57 @@ bool TryUpdateForeground(const T& element, const std::string& propertyName, cons return false; } -template -bool TryUpdateBorderProperties(ShadowNodeBase* node, T& element, const std::string& propertyName, const folly::dynamic& propertyValue) +static inline bool TryUpdateBorderProperties(ShadowNodeBase* node, XD::IXamlDirectObject element, const std::string& propertyName, const folly::dynamic& propertyValue, XD::XamlPropertyIndex propertyIndex) { bool isBorderProperty = true; if (propertyName == "borderColor") { if (propertyValue.isNumber()) - element.BorderBrush(BrushFrom(propertyValue)); + { + XamlDirectInstance::GetXamlDirect().SetColorProperty( + element, + propertyIndex, + SolidColorBrushFrom(propertyValue).Color() + ); + } else if (propertyValue.isNull()) - element.ClearValue(T::BorderBrushProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty(element, propertyIndex); } else if (propertyName == "borderLeftWidth") { if (propertyValue.isNumber()) - SetBorderThickness(node, element, ShadowEdges::Left, propertyValue.asDouble()); + SetBorderThickness(node, element, ShadowEdges::Left, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "borderTopWidth") { if (propertyValue.isNumber()) - SetBorderThickness(node, element, ShadowEdges::Top, propertyValue.asDouble()); + SetBorderThickness(node, element, ShadowEdges::Top, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "borderRightWidth") { if (propertyValue.isNumber()) - SetBorderThickness(node, element, ShadowEdges::Right, propertyValue.asDouble()); + SetBorderThickness(node, element, ShadowEdges::Right, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "borderBottomWidth") { if (propertyValue.isNumber()) - SetBorderThickness(node, element, ShadowEdges::Bottom, propertyValue.asDouble()); + SetBorderThickness(node, element, ShadowEdges::Bottom, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "borderStartWidth") { if (propertyValue.isNumber()) - SetBorderThickness(node, element, ShadowEdges::Start, propertyValue.asDouble()); + SetBorderThickness(node, element, ShadowEdges::Start, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "borderEndWidth") { if (propertyValue.isNumber()) - SetBorderThickness(node, element, ShadowEdges::End, propertyValue.asDouble()); + SetBorderThickness(node, element, ShadowEdges::End, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "borderWidth") { if (propertyValue.isNumber()) - SetBorderThickness(node, element, ShadowEdges::AllEdges, propertyValue.asDouble()); + SetBorderThickness(node, element, ShadowEdges::AllEdges, propertyValue.asDouble(), propertyIndex); } else { @@ -195,55 +215,54 @@ bool TryUpdateBorderProperties(ShadowNodeBase* node, T& element, const std::stri return isBorderProperty; } -template -bool TryUpdatePadding(ShadowNodeBase* node, const T& element, const std::string& propertyName, const folly::dynamic& propertyValue) +static inline bool TryUpdatePadding(ShadowNodeBase* node, XD::IXamlDirectObject element, const std::string& propertyName, const folly::dynamic& propertyValue, XD::XamlPropertyIndex propertyIndex) { bool isPaddingProperty = true; if (propertyName == "paddingLeft") { if (propertyValue.isNumber()) - UpdatePadding(node, element, ShadowEdges::Left, propertyValue.asDouble()); + UpdatePadding(node, element, ShadowEdges::Left, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "paddingTop") { if (propertyValue.isNumber()) - UpdatePadding(node, element, ShadowEdges::Top, propertyValue.asDouble()); + UpdatePadding(node, element, ShadowEdges::Top, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "paddingRight") { if (propertyValue.isNumber()) - UpdatePadding(node, element, ShadowEdges::Right, propertyValue.asDouble()); + UpdatePadding(node, element, ShadowEdges::Right, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "paddingBottom") { if (propertyValue.isNumber()) - UpdatePadding(node, element, ShadowEdges::Bottom, propertyValue.asDouble()); + UpdatePadding(node, element, ShadowEdges::Bottom, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "paddingStart") { if (propertyValue.isNumber()) - UpdatePadding(node, element, ShadowEdges::Start, propertyValue.asDouble()); + UpdatePadding(node, element, ShadowEdges::Start, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "paddingEnd") { if (propertyValue.isNumber()) - UpdatePadding(node, element, ShadowEdges::End, propertyValue.asDouble()); + UpdatePadding(node, element, ShadowEdges::End, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "paddingHorizontal") { if (propertyValue.isNumber()) - UpdatePadding(node, element, ShadowEdges::Horizontal, propertyValue.asDouble()); + UpdatePadding(node, element, ShadowEdges::Horizontal, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "paddingVertical") { if (propertyValue.isNumber()) - UpdatePadding(node, element, ShadowEdges::Vertical, propertyValue.asDouble()); + UpdatePadding(node, element, ShadowEdges::Vertical, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "padding") { if (propertyValue.isNumber()) - UpdatePadding(node, element, ShadowEdges::AllEdges, propertyValue.asDouble()); + UpdatePadding(node, element, ShadowEdges::AllEdges, propertyValue.asDouble(), propertyIndex); } else { @@ -253,53 +272,52 @@ bool TryUpdatePadding(ShadowNodeBase* node, const T& element, const std::string& return isPaddingProperty; } -template -bool TryUpdateCornerRadius(ShadowNodeBase* node, T& element, const std::string& propertyName, const folly::dynamic& propertyValue) +static inline bool TryUpdateCornerRadius(ShadowNodeBase* node, XD::IXamlDirectObject element, const std::string& propertyName, const folly::dynamic& propertyValue, XD::XamlPropertyIndex propertyIndex) { if (propertyName == "borderTopLeftRadius") { if (propertyValue.isNumber()) - UpdateCornerRadius(node, element, ShadowCorners::TopLeft, propertyValue.asDouble()); + UpdateCornerRadius(node, element, ShadowCorners::TopLeft, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "borderTopRightRadius") { if (propertyValue.isNumber()) - UpdateCornerRadius(node, element, ShadowCorners::TopRight, propertyValue.asDouble()); + UpdateCornerRadius(node, element, ShadowCorners::TopRight, propertyValue.asDouble(), propertyIndex); } if (propertyName == "borderTopStartRadius") { if (propertyValue.isNumber()) - UpdateCornerRadius(node, element, ShadowCorners::TopStart, propertyValue.asDouble()); + UpdateCornerRadius(node, element, ShadowCorners::TopStart, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "borderTopEndRadius") { if (propertyValue.isNumber()) - UpdateCornerRadius(node, element, ShadowCorners::TopEnd, propertyValue.asDouble()); + UpdateCornerRadius(node, element, ShadowCorners::TopEnd, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "borderBottomRightRadius") { if (propertyValue.isNumber()) - UpdateCornerRadius(node, element, ShadowCorners::BottomRight, propertyValue.asDouble()); + UpdateCornerRadius(node, element, ShadowCorners::BottomRight, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "borderBottomLeftRadius") { if (propertyValue.isNumber()) - UpdateCornerRadius(node, element, ShadowCorners::BottomLeft, propertyValue.asDouble()); + UpdateCornerRadius(node, element, ShadowCorners::BottomLeft, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "borderBottomStartRadius") { if (propertyValue.isNumber()) - UpdateCornerRadius(node, element, ShadowCorners::BottomStart, propertyValue.asDouble()); + UpdateCornerRadius(node, element, ShadowCorners::BottomStart, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "borderBottomEndRadius") { if (propertyValue.isNumber()) - UpdateCornerRadius(node, element, ShadowCorners::BottomEnd, propertyValue.asDouble()); + UpdateCornerRadius(node, element, ShadowCorners::BottomEnd, propertyValue.asDouble(), propertyIndex); } else if (propertyName == "borderRadius") { if (propertyValue.isNumber()) - UpdateCornerRadius(node, element, ShadowCorners::AllCorners, propertyValue.asDouble()); + UpdateCornerRadius(node, element, ShadowCorners::AllCorners, propertyValue.asDouble(), propertyIndex); } else { @@ -309,61 +327,33 @@ bool TryUpdateCornerRadius(ShadowNodeBase* node, T& element, const std::string& return true; } -template -bool TryUpdateFontProperties(const T& element, const std::string& propertyName, const folly::dynamic& propertyValue) +static inline bool TryUpdateFontProperties(XD::IXamlDirectObject element, const std::string& propertyName, const folly::dynamic& propertyValue, XD::XamlPropertyIndex propertyIndex) { bool isFontProperty = true; if (propertyName == "fontSize") { if (propertyValue.isNumber()) - element.FontSize(propertyValue.asDouble()); + XamlDirectInstance::GetXamlDirect().SetDoubleProperty(element, propertyIndex, propertyValue.asDouble()); else if (propertyValue.isNull()) - element.ClearValue(T::FontSizeProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty(element, propertyIndex); } else if (propertyName == "fontFamily") { if (propertyValue.isString()) - element.FontFamily(winrt::Windows::UI::Xaml::Media::FontFamily(asWStr(propertyValue))); + XamlDirectInstance::GetXamlDirect().SetStringProperty(element, propertyIndex, asHstring(propertyValue)); else if (propertyValue.isNull()) - element.ClearValue(T::FontFamilyProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty(element, propertyIndex); } else if (propertyName == "fontWeight") { if (propertyValue.isString()) { - const std::string& value = propertyValue.getString(); - winrt::Windows::UI::Text::FontWeight fontWeight; - if (value == "normal") - fontWeight = winrt::Windows::UI::Text::FontWeights::Normal(); - else if (value == "bold") - fontWeight = winrt::Windows::UI::Text::FontWeights::Bold(); - else if (value == "100") - fontWeight.Weight = 100; - else if (value == "200") - fontWeight.Weight = 200; - else if (value == "300") - fontWeight.Weight = 300; - else if (value == "400") - fontWeight.Weight = 400; - else if (value == "500") - fontWeight.Weight = 500; - else if (value == "600") - fontWeight.Weight = 600; - else if (value == "700") - fontWeight.Weight = 700; - else if (value == "800") - fontWeight.Weight = 800; - else if (value == "900") - fontWeight.Weight = 900; - else - fontWeight = winrt::Windows::UI::Text::FontWeights::Normal(); - - element.FontWeight(fontWeight); + XamlDirectInstance::GetXamlDirect().SetStringProperty(element, propertyIndex, asHstring(propertyValue)); } else if (propertyValue.isNull()) { - element.ClearValue(T::FontWeightProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty(element, propertyIndex); } } @@ -371,13 +361,14 @@ bool TryUpdateFontProperties(const T& element, const std::string& propertyName, { if (propertyValue.isString()) { - element.FontStyle((propertyValue.getString() == "italic") + auto fontStyle = (propertyValue.getString() == "italic") ? winrt::Windows::UI::Text::FontStyle::Italic - : winrt::Windows::UI::Text::FontStyle::Normal); + : winrt::Windows::UI::Text::FontStyle::Normal; + XamlDirectInstance::GetXamlDirect().SetEnumProperty(element, propertyIndex, static_cast(fontStyle)); } else if (propertyValue.isNull()) { - element.ClearValue(T::FontStyleProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty(element, propertyIndex); } } @@ -389,34 +380,33 @@ bool TryUpdateFontProperties(const T& element, const std::string& propertyName, return isFontProperty; } -template -void SetTextAlignment(const T& element, const std::string& value) +static inline void SetTextAlignment(XD::IXamlDirectObject element, const std::string& value, XD::XamlPropertyIndex propertyIndex) { if (value == "left") - element.TextAlignment(winrt::TextAlignment::Left); + XamlDirectInstance::GetXamlDirect().SetEnumProperty(element, propertyIndex, static_cast(winrt::TextAlignment::Left)); else if (value == "right") - element.TextAlignment(winrt::TextAlignment::Right); + XamlDirectInstance::GetXamlDirect().SetEnumProperty(element, propertyIndex, static_cast(winrt::TextAlignment::Right)); else if (value == "center") - element.TextAlignment(winrt::TextAlignment::Center); + XamlDirectInstance::GetXamlDirect().SetEnumProperty(element, propertyIndex, static_cast(winrt::TextAlignment::Center)); else if (value == "justify") - element.TextAlignment(winrt::TextAlignment::Justify); + XamlDirectInstance::GetXamlDirect().SetEnumProperty(element, propertyIndex, static_cast(winrt::TextAlignment::Justify)); else - element.TextAlignment(winrt::TextAlignment::DetectFromContent); + XamlDirectInstance::GetXamlDirect().SetEnumProperty(element, propertyIndex, static_cast(winrt::TextAlignment::DetectFromContent)); } -template -bool TryUpdateTextAlignment(const T& element, const std::string& propertyName, const folly::dynamic& propertyValue) +static inline bool TryUpdateTextAlignment(XD::IXamlDirectObject element, const std::string& propertyName, const folly::dynamic& propertyValue, XD::XamlPropertyIndex propertyIndex) { if (propertyName == "textAlign") { if (propertyValue.isString()) { const std::string& value = propertyValue.getString(); - SetTextAlignment(element, value); + SetTextAlignment(element, value, propertyIndex); } else if (propertyValue.isNull()) { - element.ClearValue(T::TextAlignmentProperty()); + //element.ClearValue(T::TextAlignmentProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty(element, propertyIndex); } return true; @@ -425,34 +415,32 @@ bool TryUpdateTextAlignment(const T& element, const std::string& propertyName, c return false; } -template -void SetTextTrimming(const T& element, const std::string& value) +static inline void SetTextTrimming(XD::IXamlDirectObject element, const std::string& value, XD::XamlPropertyIndex propertyIndex) { if (value == "clip") - element.TextTrimming(winrt::TextTrimming::Clip); + XamlDirectInstance::GetXamlDirect().SetEnumProperty(element, propertyIndex, static_cast(winrt::TextTrimming::Clip)); else if (value == "head" || value == "middle" || value == "tail") { // "head" and "middle" not supported by UWP, but "tail" // behavior is the most similar - element.TextTrimming(winrt::TextTrimming::CharacterEllipsis); + XamlDirectInstance::GetXamlDirect().SetEnumProperty(element, propertyIndex, static_cast(winrt::TextTrimming::CharacterEllipsis)); } else - element.TextTrimming(winrt::TextTrimming::None); + XamlDirectInstance::GetXamlDirect().SetEnumProperty(element, propertyIndex, static_cast(winrt::TextTrimming::None)); } -template -bool TryUpdateTextTrimming(const T& element, const std::string& propertyName, const folly::dynamic& propertyValue) +static inline bool TryUpdateTextTrimming(XD::IXamlDirectObject element, const std::string& propertyName, const folly::dynamic& propertyValue, XD::XamlPropertyIndex propertyIndex) { if (propertyName == "ellipsizeMode") { if (propertyValue.isString()) { const std::string& value = propertyValue.getString(); - SetTextTrimming(element, value); + SetTextTrimming(element, value, propertyIndex); } else if (propertyValue.isNull()) { - element.ClearValue(T::TextTrimmingProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty(element, propertyIndex); } return true; @@ -461,8 +449,7 @@ bool TryUpdateTextTrimming(const T& element, const std::string& propertyName, co return false; } -template -bool TryUpdateTextDecorationLine(const T& element, const std::string& propertyName, const folly::dynamic& propertyValue) +static inline bool TryUpdateTextDecorationLine(XD::IXamlDirectObject element, const std::string& propertyName, const folly::dynamic& propertyValue, XD::XamlPropertyIndex propertyIndex) { if (propertyName == "textDecorationLine") { @@ -486,11 +473,11 @@ bool TryUpdateTextDecorationLine(const T& element, const std::string& propertyNa else if (value == "underline line-through") decorations = TextDecorations::Underline | TextDecorations::Strikethrough; - element.TextDecorations(decorations); + XamlDirectInstance::GetXamlDirect().SetEnumProperty(element, propertyIndex, static_cast(decorations)); } else if (propertyValue.isNull()) { - element.ClearValue(T::TextDecorationsProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty(element, propertyIndex); } return true; @@ -499,30 +486,39 @@ bool TryUpdateTextDecorationLine(const T& element, const std::string& propertyNa return false; } -template -void SetFlowDirection(const T& element, const std::string& value) +static inline void SetFlowDirection(XD::IXamlDirectObject element, const std::string& value, XD::XamlPropertyIndex propertyIndex) { if (value == "rtl") - element.FlowDirection(winrt::FlowDirection::RightToLeft); + XamlDirectInstance::GetXamlDirect().SetEnumProperty( + element, + propertyIndex, + static_cast(winrt::FlowDirection::RightToLeft) + ); else if (value =="ltr") - element.FlowDirection(winrt::FlowDirection::LeftToRight); + XamlDirectInstance::GetXamlDirect().SetEnumProperty( + element, + propertyIndex, + static_cast(winrt::FlowDirection::LeftToRight) + ); else // 'auto', 'inherit' - element.ClearValue(winrt::FrameworkElement::FlowDirectionProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + element, + propertyIndex + ); } -template -bool TryUpdateFlowDirection(const T& element, const std::string& propertyName, const folly::dynamic& propertyValue) +static inline bool TryUpdateFlowDirection(XD::IXamlDirectObject element, const std::string& propertyName, const folly::dynamic& propertyValue, XD::XamlPropertyIndex propertyIndex) { if ((propertyName == "writingDirection") || (propertyName == "direction")) { if (propertyValue.isString()) { const std::string& value = propertyValue.getString(); - SetFlowDirection(element, value); + SetFlowDirection(element, value, propertyIndex); } else if (propertyValue.isNull()) { - element.ClearValue(T::FlowDirectionProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty(element, propertyIndex); } return true; @@ -531,15 +527,21 @@ bool TryUpdateFlowDirection(const T& element, const std::string& propertyName, c return false; } -template -bool TryUpdateCharacterSpacing(const T& element, const std::string& propertyName, const folly::dynamic& propertyValue) +static inline bool TryUpdateCharacterSpacing(XD::IXamlDirectObject element, const std::string& propertyName, const folly::dynamic& propertyValue, XD::XamlPropertyIndex propertyIndex) { if (propertyName == "letterSpacing" || propertyName == "characterSpacing") { if (propertyValue.isNumber()) - element.CharacterSpacing(static_cast(propertyValue.asDouble())); + XamlDirectInstance::GetXamlDirect().SetEnumProperty( + element, + propertyIndex, + static_cast(propertyValue.asDouble()) + ); else if (propertyValue.isNull()) - element.ClearValue(T::CharacterSpacingProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + element, + propertyIndex + ); return true; } @@ -547,22 +549,29 @@ bool TryUpdateCharacterSpacing(const T& element, const std::string& propertyName return false; } -template -bool TryUpdateOrientation(const T& element, const std::string& propertyName, const folly::dynamic& propertyValue) +static inline bool TryUpdateOrientation(XD::IXamlDirectObject element, const std::string& propertyName, const folly::dynamic& propertyValue, XD::XamlPropertyIndex propertyIndex) { if (propertyName == "orientation") { if (propertyValue.isNull()) { - element.ClearValue(T::OrientationProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty(element, propertyIndex); } else if (propertyValue.isString()) { const std::string& valueString = propertyValue.getString(); if (valueString == "horizontal") - element.Orientation(Orientation::Horizontal); + XamlDirectInstance::GetXamlDirect().SetEnumProperty( + element, + propertyIndex, + static_cast(winrt::Orientation::Horizontal) + ); else if (valueString == "vertical") - element.Orientation(Orientation::Vertical); + XamlDirectInstance::GetXamlDirect().SetEnumProperty( + element, + propertyIndex, + static_cast(winrt::Orientation::Vertical) + ); } return true; diff --git a/vnext/ReactUWP/Utils/UwpPreparedScriptStore.cpp b/vnext/ReactUWP/Utils/UwpPreparedScriptStore.cpp new file mode 100644 index 00000000000..292ade9ab90 --- /dev/null +++ b/vnext/ReactUWP/Utils/UwpPreparedScriptStore.cpp @@ -0,0 +1,108 @@ +#include "pch.h" +#include "Utils/UwpPreparedScriptStore.h" +#include +#include +#include "unicode.h" +#include "jsi/jsi.h" + +#if _MSC_VER <= 1913 +// VC 19 (2015-2017.6) cannot optimize co_await/cppwinrt usage +#pragma optimize( "", off ) +#endif + +namespace winrt { + using namespace winrt::Windows::Foundation; + using namespace winrt::Windows::Storage; +}; + +namespace react { namespace uwp { + UwpPreparedScriptStore::UwpPreparedScriptStore(winrt::hstring uri) + { + if (!uri.empty()) + { + m_byteCodeFileAsync = winrt::StorageFile::GetFileFromApplicationUriAsync(winrt::Uri(uri)); + } + } + +std::unique_ptr UwpPreparedScriptStore::tryGetPreparedScript( + const facebook::jsi::ScriptSignature& scriptSignature, + const facebook::jsi::JSRuntimeSignature& runtimeSignature, + const char* prepareTag // Optional tag. For e.g. eagerly evaluated vs lazy cache. +) noexcept +{ + try { + + // check if app bundle version is older than or equal to the prepared script version + // if true then just read the buffer from the prepared script and return + auto byteCodeFile = TryGetByteCodeFileSync(scriptSignature); + if (byteCodeFile == nullptr) { + return nullptr; + } + + auto buffer = winrt::FileIO::ReadBufferAsync(byteCodeFile).get(); + auto bytecodeBuffer(std::make_unique(buffer.Length())); + auto dataReader{ winrt::Streams::DataReader::FromBuffer(buffer) }; + dataReader.ReadBytes(winrt::array_view { &bytecodeBuffer->data()[0], &bytecodeBuffer->data()[bytecodeBuffer->size()] }); + dataReader.Close(); + + return bytecodeBuffer; + } + catch (...) { + return nullptr; + } +} + +void UwpPreparedScriptStore::persistPreparedScript( + std::shared_ptr preparedScript, + const facebook::jsi::ScriptSignature& scriptMetadata, + const facebook::jsi::JSRuntimeSignature& runtimeMetadata, + const char* prepareTag // Optional tag. For e.g. eagerly evaluated vs lazy cache. +) noexcept +{ + persistPreparedScriptAsync(preparedScript, scriptMetadata, runtimeMetadata, prepareTag); +} + +winrt::fire_and_forget UwpPreparedScriptStore::persistPreparedScriptAsync( + std::shared_ptr preparedScript, + const facebook::jsi::ScriptSignature& scriptMetadata, + const facebook::jsi::JSRuntimeSignature& runtimeMetadata, + const char* prepareTag // Optional tag. For e.g. eagerly evaluated vs lazy cache. +) +{ + try { + co_await winrt::resume_background(); + auto folder = winrt::ApplicationData::Current().LocalCacheFolder(); + auto fileName = winrt::to_hstring(scriptMetadata.url + ".bytecode"); + auto file = co_await folder.CreateFileAsync(fileName, winrt::CreationCollisionOption::ReplaceExisting); + winrt::FileIO::WriteBytesAsync(file, winrt::array_view{ &preparedScript->data()[0], &preparedScript->data()[preparedScript->size()] }); + } + catch (...) { + } +} + +winrt::StorageFile UwpPreparedScriptStore::TryGetByteCodeFileSync(const facebook::jsi::ScriptSignature& scriptSignature) +{ + try { + if (m_byteCodeFileAsync != nullptr) { + auto file = m_byteCodeFileAsync.get(); + auto fileprops = file.GetBasicPropertiesAsync().get(); + facebook::jsi::ScriptVersion_t byteCodeVersion = fileprops.DateModified().time_since_epoch().count(); + if (byteCodeVersion >= scriptSignature.version) { + return file; + } + } + } + catch (...) { + // Eat this exception. If we can't get the file from the uri. Still try looking in the cache. + } + + // Getting here means one of two things. No bytecode file uri was specified, or the file uri was specified but it is outdated. + // Try looking in LocalCache folder for bytecode file and use that. + auto fileName = winrt::to_hstring(scriptSignature.url + ".bytecode"); + auto file = winrt::ApplicationData::Current().LocalCacheFolder().GetFileAsync(fileName).get(); + auto fileprops = file.GetBasicPropertiesAsync().get(); + facebook::jsi::ScriptVersion_t byteCodeVersion = fileprops.DateModified().time_since_epoch().count(); + + return byteCodeVersion > scriptSignature.version ? file : nullptr; +} +}} diff --git a/vnext/ReactUWP/Utils/UwpPreparedScriptStore.h b/vnext/ReactUWP/Utils/UwpPreparedScriptStore.h new file mode 100644 index 00000000000..acab5ac9873 --- /dev/null +++ b/vnext/ReactUWP/Utils/UwpPreparedScriptStore.h @@ -0,0 +1,64 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include "jsi/jsi.h" + +namespace react { namespace uwp { +class UwpPreparedScriptStore : public facebook::jsi::PreparedScriptStore +{ +public: + UwpPreparedScriptStore(winrt::hstring uri); + std::unique_ptr tryGetPreparedScript( + const facebook::jsi::ScriptSignature& scriptSignature, + const facebook::jsi::JSRuntimeSignature& runtimeSignature, + const char* prepareTag // Optional tag. For e.g. eagerly evaluated vs lazy cache. + ) noexcept override; + + void persistPreparedScript( + std::shared_ptr preparedScript, + const facebook::jsi::ScriptSignature& scriptMetadata, + const facebook::jsi::JSRuntimeSignature& runtimeMetadata, + const char* prepareTag // Optional tag. For e.g. eagerly evaluated vs lazy cache. + ) noexcept override; + + UwpPreparedScriptStore(const UwpPreparedScriptStore&) = delete; + void operator=(const UwpPreparedScriptStore&) = delete; +private: + winrt::fire_and_forget persistPreparedScriptAsync( + std::shared_ptr preparedScript, + const facebook::jsi::ScriptSignature& scriptMetadata, + const facebook::jsi::JSRuntimeSignature& runtimeMetadata, + const char* prepareTag // Optional tag. For e.g. eagerly evaluated vs lazy cache. + ); + winrt::Windows::Storage::StorageFile TryGetByteCodeFileSync(const facebook::jsi::ScriptSignature& scriptSignature); + winrt::Windows::Foundation::IAsyncOperation m_byteCodeFileAsync; +}; + +// This is very similiar to ByteArrayBuffer in ChakraJsiRuntime.h. +// Defining this to avoid referencing types in chakra headers +class ByteCodeBuffer final : public facebook::jsi::Buffer { +public: + size_t size() const override { + return size_; + } + const uint8_t* data() const { + return byteArray_.get(); + } + + uint8_t* data() { + return byteArray_.get(); + } + + ByteCodeBuffer(int size) : size_(size), byteArray_(std::make_unique(size)) {} + ByteCodeBuffer(const ByteCodeBuffer&) = delete; + void operator=(const ByteCodeBuffer&) = delete; + +private: + int size_; + std::unique_ptr byteArray_; +}; +}} diff --git a/vnext/ReactUWP/Utils/UwpScriptStore.cpp b/vnext/ReactUWP/Utils/UwpScriptStore.cpp new file mode 100644 index 00000000000..090bbe705d3 --- /dev/null +++ b/vnext/ReactUWP/Utils/UwpScriptStore.cpp @@ -0,0 +1,54 @@ +#include "pch.h" +#include "Utils/UwpScriptStore.h" +#include +#include +#include +#include +#include "unicode.h" + +namespace winrt { + using namespace winrt::Windows::Foundation; + using namespace winrt::Windows::Storage; +} + +namespace react { namespace uwp { + +UwpScriptStore::UwpScriptStore() {} + +facebook::jsi::VersionedBuffer UwpScriptStore::getVersionedScript(const std::string& url) noexcept +{ + facebook::jsi::VersionedBuffer versionedBuffer_; + versionedBuffer_.buffer = nullptr; + versionedBuffer_.version = 0; + + return versionedBuffer_; +} + +// Script version = timestamp of bundle file last created +facebook::jsi::ScriptVersion_t UwpScriptStore::getScriptVersion(const std::string& url) noexcept +{ + const std::string bundleUrl = "ms-appx:///Bundle/" + url + ".bundle"; + const winrt::DateTime bundleModifiedTime = getBundleModifiedDate(bundleUrl).get(); + const std::uint64_t timestamp = bundleModifiedTime.time_since_epoch().count(); + return timestamp; +} + +std::future UwpScriptStore::getBundleModifiedDate(const std::string& bundleUri) +{ + winrt::hstring str(facebook::react::unicode::utf8ToUtf16(bundleUri)); + winrt::Windows::Foundation::Uri uri(str); + + try + { + auto file = co_await winrt::StorageFile::GetFileFromApplicationUriAsync(uri); + auto props = file.GetBasicPropertiesAsync().get(); + return props.DateModified(); + } + catch (winrt::hresult_error const& ex) + { + winrt::DateTime date; + return date; + } +} + +}} diff --git a/vnext/ReactUWP/Utils/UwpScriptStore.h b/vnext/ReactUWP/Utils/UwpScriptStore.h new file mode 100644 index 00000000000..b30d627cf13 --- /dev/null +++ b/vnext/ReactUWP/Utils/UwpScriptStore.h @@ -0,0 +1,19 @@ +#pragma once +#include +#include + +namespace react { namespace uwp { + +class UwpScriptStore : public facebook::jsi::ScriptStore +{ +public: + facebook::jsi::VersionedBuffer getVersionedScript(const std::string& url) noexcept override; + facebook::jsi::ScriptVersion_t getScriptVersion(const std::string& url) noexcept override; + UwpScriptStore(); + UwpScriptStore(const UwpScriptStore&) = delete; + void operator=(const UwpScriptStore&) = delete; +private: + std::future getBundleModifiedDate(const std::string& bundlePath); +}; + +}} diff --git a/vnext/ReactUWP/Views/ActivityIndicatorViewManager.cpp b/vnext/ReactUWP/Views/ActivityIndicatorViewManager.cpp index fef240b92df..1d454f00f4d 100644 --- a/vnext/ReactUWP/Views/ActivityIndicatorViewManager.cpp +++ b/vnext/ReactUWP/Views/ActivityIndicatorViewManager.cpp @@ -50,6 +50,8 @@ void ActivityIndicatorViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate if (progressRing == nullptr) return; + auto progressRingXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(progressRing); + for (const auto& pair : reactDiffMap.items()) { const std::string& propertyName = pair.first.getString(); @@ -58,9 +60,16 @@ void ActivityIndicatorViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate if (propertyName == "animating") { if (propertyValue.isBool()) - progressRing.IsActive(propertyValue.asBool()); + XamlDirectInstance::GetXamlDirect().SetBooleanProperty( + progressRingXD, + XD::XamlPropertyIndex::ProgressRing_IsActive, + propertyValue.asBool() + ); else if (pair.second.isNull()) - progressRing.ClearValue(winrt::ProgressRing::IsActiveProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + progressRingXD, + XD::XamlPropertyIndex::ProgressRing_IsActive + ); } } diff --git a/vnext/ReactUWP/Views/CheckboxViewManager.cpp b/vnext/ReactUWP/Views/CheckboxViewManager.cpp index a5f39491ae6..4191aa0d007 100644 --- a/vnext/ReactUWP/Views/CheckboxViewManager.cpp +++ b/vnext/ReactUWP/Views/CheckboxViewManager.cpp @@ -13,6 +13,7 @@ #include #include +#include namespace winrt { using namespace Windows::UI::Xaml; @@ -21,11 +22,6 @@ namespace winrt { namespace react { namespace uwp { -enum class CheckboxCommands -{ - SetFocus = 1, -}; - class CheckBoxShadowNode : public ShadowNodeBase { using Super = ShadowNodeBase; @@ -82,15 +78,6 @@ const char* CheckBoxViewManager::GetName() const return "RCTCheckBox"; } -folly::dynamic CheckBoxViewManager::GetCommands() const -{ - auto commands = Super::GetCommands(); - commands.update(folly::dynamic::object - ("SetFocus", static_cast>(CheckboxCommands::SetFocus)) - ); - return commands; -} - folly::dynamic CheckBoxViewManager::GetNativeProps() const { auto props = Super::GetNativeProps(); @@ -120,6 +107,8 @@ void CheckBoxViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const f if (checkbox == nullptr) return; + auto checkboxXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(checkbox); + for (const auto& pair : reactDiffMap.items()) { const std::string& propertyName = pair.first.getString(); @@ -128,36 +117,34 @@ void CheckBoxViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const f if (propertyName == "disabled") { if (propertyValue.isBool()) - checkbox.IsEnabled(!propertyValue.asBool()); + XamlDirectInstance::GetXamlDirect().SetBooleanProperty( + checkboxXD, + XD::XamlPropertyIndex::Control_IsEnabled, + !propertyValue.asBool() + ); else if (pair.second.isNull()) - checkbox.ClearValue(winrt::Control::IsEnabledProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + checkboxXD, + XD::XamlPropertyIndex::Control_IsEnabled + ); } else if (propertyName == "checked") { if (propertyValue.isBool()) - checkbox.IsChecked(propertyValue.asBool()); + XamlDirectInstance::GetXamlDirect().SetBooleanProperty( + checkboxXD, + XD::XamlPropertyIndex::ToggleButton_IsChecked, + propertyValue.asBool() + ); else if (pair.second.isNull()) - checkbox.ClearValue(winrt::Primitives::ToggleButton::IsCheckedProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + checkboxXD, + XD::XamlPropertyIndex::ToggleButton_IsChecked + ); } } Super::UpdateProperties(nodeToUpdate, reactDiffMap); } -void CheckBoxViewManager::DispatchCommand(XamlView viewToUpdate, int64_t commandId, const folly::dynamic& commandArgs) -{ - auto checkbox = viewToUpdate.as(); - if (checkbox == nullptr) - return; - - switch (commandId) - { - case static_cast(CheckboxCommands::SetFocus): - { - checkbox.Focus(winrt::FocusState::Programmatic); - break; - } - } -} - }} diff --git a/vnext/ReactUWP/Views/CheckboxViewManager.h b/vnext/ReactUWP/Views/CheckboxViewManager.h index 02ff928a6fa..5e29a5733e9 100644 --- a/vnext/ReactUWP/Views/CheckboxViewManager.h +++ b/vnext/ReactUWP/Views/CheckboxViewManager.h @@ -14,13 +14,11 @@ class CheckBoxViewManager : public ControlViewManager CheckBoxViewManager(const std::shared_ptr& reactInstance); const char* GetName() const override; - folly::dynamic GetCommands() const override; folly::dynamic GetNativeProps() const override; facebook::react::ShadowNode* createShadow() const override; void UpdateProperties(ShadowNodeBase* nodeToUpdate, const folly::dynamic& reactDiffMap) override; - void DispatchCommand(XamlView viewToUpdate, int64_t commandId, const folly::dynamic& commandArgs) override; protected: XamlView CreateViewCore(int64_t tag) override; diff --git a/vnext/ReactUWP/Views/ControlViewManager.cpp b/vnext/ReactUWP/Views/ControlViewManager.cpp index 73fa69e8981..57129cfdef9 100644 --- a/vnext/ReactUWP/Views/ControlViewManager.cpp +++ b/vnext/ReactUWP/Views/ControlViewManager.cpp @@ -11,6 +11,8 @@ #include #include +#include + namespace winrt { using namespace Windows::UI::Xaml; using namespace Windows::UI::Xaml::Controls; @@ -40,24 +42,27 @@ void ControlViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const fo if (control != nullptr) { + auto controlXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(control); + for (const auto& pair : reactDiffMap.items()) { const std::string& propertyName = pair.first.getString(); const folly::dynamic& propertyValue = pair.second; + auto borderProperty = propertyName == "borderColor" ? XD::XamlPropertyIndex::Control_BorderBrush : XD::XamlPropertyIndex::Control_BorderThickness; - if (TryUpdateBackgroundBrush(control, propertyName, propertyValue)) + if (TryUpdateBackgroundBrush(controlXD, propertyName, propertyValue, XD::XamlPropertyIndex::Control_Background)) { continue; } - else if (TryUpdateBorderProperties(nodeToUpdate, control, propertyName, propertyValue)) + else if (TryUpdateBorderProperties(nodeToUpdate, controlXD, propertyName, propertyValue, borderProperty)) { continue; } - else if (TryUpdateForeground(control, propertyName, propertyValue)) + else if (TryUpdateForeground(controlXD, propertyName, propertyValue, XD::XamlPropertyIndex::Control_Foreground)) { continue; } - else if (implementsPadding && TryUpdatePadding(nodeToUpdate, control, propertyName, propertyValue)) + else if (implementsPadding && TryUpdatePadding(nodeToUpdate, controlXD, propertyName, propertyValue, XD::XamlPropertyIndex::Control_Padding)) { continue; } diff --git a/vnext/ReactUWP/Views/DatePickerViewManager.cpp b/vnext/ReactUWP/Views/DatePickerViewManager.cpp index 3ebbed19924..e46710d7e6b 100644 --- a/vnext/ReactUWP/Views/DatePickerViewManager.cpp +++ b/vnext/ReactUWP/Views/DatePickerViewManager.cpp @@ -15,6 +15,9 @@ #include #include #include +#include + +#include namespace winrt { using namespace Windows::UI::Xaml; @@ -67,6 +70,8 @@ void DatePickerShadowNode::updateProperties(const folly::dynamic&& props) if (datePicker == nullptr) return; + auto datePickerXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(datePicker); + bool updateSelectedDate = false; bool updateMaxDate = false; bool updateMinDate = false; @@ -79,23 +84,44 @@ void DatePickerShadowNode::updateProperties(const folly::dynamic&& props) if (propertyName == "dayOfWeekFormat") { if (propertyValue.isString()) - datePicker.DayOfWeekFormat(asHstring(propertyValue)); + XamlDirectInstance::GetXamlDirect().SetStringProperty( + datePickerXD, + XD::XamlPropertyIndex::CalendarDatePicker_DayOfWeekFormat, + asHstring(propertyValue) + ); else if (propertyValue.isNull()) - datePicker.ClearValue(winrt::CalendarDatePicker::DayOfWeekFormatProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + datePickerXD, + XD::XamlPropertyIndex::CalendarDatePicker_DayOfWeekFormat + ); } else if (propertyName == "dateFormat") { if (propertyValue.isString()) - datePicker.DateFormat(asHstring(propertyValue)); + XamlDirectInstance::GetXamlDirect().SetStringProperty( + datePickerXD, + XD::XamlPropertyIndex::CalendarDatePicker_DateFormat, + asHstring(propertyValue) + ); else if (propertyValue.isNull()) - datePicker.ClearValue(winrt::CalendarDatePicker::DateFormatProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + datePickerXD, + XD::XamlPropertyIndex::CalendarDatePicker_DateFormat + ); } else if (propertyName == "firstDayOfWeek") { if (propertyValue.isNumber()) - datePicker.FirstDayOfWeek(static_cast(static_cast(propertyValue.asDouble()))); + XamlDirectInstance::GetXamlDirect().SetEnumProperty( + datePickerXD, + XD::XamlPropertyIndex::CalendarDatePicker_FirstDayOfWeek, + static_cast(propertyValue.asDouble()) + ); else if (propertyValue.isNull()) - datePicker.ClearValue(winrt::CalendarDatePicker::FirstDayOfWeekProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + datePickerXD, + XD::XamlPropertyIndex::CalendarDatePicker_FirstDayOfWeek + ); } else if (propertyName == "maxDate") { @@ -106,7 +132,10 @@ void DatePickerShadowNode::updateProperties(const folly::dynamic&& props) } else if (propertyValue.isNull()) { - datePicker.ClearValue(winrt::CalendarDatePicker::MaxDateProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + datePickerXD, + XD::XamlPropertyIndex::CalendarDatePicker_MaxDate + ); } } else if (propertyName == "minDate") @@ -118,15 +147,25 @@ void DatePickerShadowNode::updateProperties(const folly::dynamic&& props) } else if (propertyValue.isNull()) { - datePicker.ClearValue(winrt::CalendarDatePicker::MinDateProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + datePickerXD, + XD::XamlPropertyIndex::CalendarDatePicker_MinDate + ); } } else if (propertyName == "placeholderText") { if (propertyValue.isString()) - datePicker.PlaceholderText(asHstring(propertyValue)); + XamlDirectInstance::GetXamlDirect().SetStringProperty( + datePickerXD, + XD::XamlPropertyIndex::CalendarDatePicker_PlaceholderText, + asHstring(propertyValue) + ); else if (propertyValue.isNull()) - datePicker.ClearValue(winrt::CalendarDatePicker::PlaceholderTextProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + datePickerXD, + XD::XamlPropertyIndex::CalendarDatePicker_PlaceholderText + ); } else if (propertyName == "selectedDate") { @@ -137,7 +176,10 @@ void DatePickerShadowNode::updateProperties(const folly::dynamic&& props) } else if (propertyValue.isNull()) { - datePicker.ClearValue(winrt::CalendarDatePicker::DateProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + datePickerXD, + XD::XamlPropertyIndex::CalendarDatePicker_Date + ); } } else if (propertyName == "timeZoneOffsetInSeconds") @@ -150,13 +192,25 @@ void DatePickerShadowNode::updateProperties(const folly::dynamic&& props) } if (updateMaxDate) - datePicker.MaxDate(DateTimeFrom(m_maxTime, m_timeZoneOffsetInSeconds)); + XamlDirectInstance::GetXamlDirect().SetDateTimeProperty( + datePickerXD, + XD::XamlPropertyIndex::CalendarDatePicker_MaxDate, + DateTimeFrom(m_maxTime, m_timeZoneOffsetInSeconds) + ); if (updateMinDate) - datePicker.MinDate(DateTimeFrom(m_minTime, m_timeZoneOffsetInSeconds)); + XamlDirectInstance::GetXamlDirect().SetDateTimeProperty( + datePickerXD, + XD::XamlPropertyIndex::CalendarDatePicker_MinDate, + DateTimeFrom(m_minTime, m_timeZoneOffsetInSeconds) + ); if (updateSelectedDate) - datePicker.Date(DateTimeFrom(m_selectedTime, m_timeZoneOffsetInSeconds)); + XamlDirectInstance::GetXamlDirect().SetDateTimeProperty( + datePickerXD, + XD::XamlPropertyIndex::CalendarDatePicker_Date, + DateTimeFrom(m_selectedTime, m_timeZoneOffsetInSeconds) + ); Super::updateProperties(std::move(props)); m_updating = false; diff --git a/vnext/ReactUWP/Views/DynamicAutomationPeer.cpp b/vnext/ReactUWP/Views/DynamicAutomationPeer.cpp new file mode 100644 index 00000000000..36ec4f20580 --- /dev/null +++ b/vnext/ReactUWP/Views/DynamicAutomationPeer.cpp @@ -0,0 +1,188 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" + +#include "DynamicAutomationPeer.h" +#include "DynamicAutomationProperties.h" + +#include +#include + +namespace winrt { + using namespace Windows::Foundation; + using namespace Windows::UI::Xaml; + using namespace Windows::UI::Xaml::Automation; + using namespace Windows::UI::Xaml::Automation::Peers; + using namespace Windows::UI::Xaml::Automation::Provider; + using namespace Windows::UI::Xaml::Controls; + using namespace Windows::UI::Xaml::Interop; + using namespace Windows::UI::Xaml::Media; +} + +namespace winrt::react::uwp::implementation +{ + +DynamicAutomationPeer::DynamicAutomationPeer(winrt::FrameworkElement const& owner) + : Super(owner) +{ +} + +winrt::hstring DynamicAutomationPeer::GetClassNameCore() const +{ + return L"DynamticAutomationPeer"; +} + +winrt::AutomationControlType DynamicAutomationPeer::GetAutomationControlTypeCore() const +{ + auto accessibilityRole = GetAccessibilityRole(); + + switch (accessibilityRole) + { + case winrt::react::uwp::AccessibilityRoles::Button: + case winrt::react::uwp::AccessibilityRoles::ImageButton: + return winrt::AutomationControlType::Button; + case winrt::react::uwp::AccessibilityRoles::Link: + return winrt::AutomationControlType::Hyperlink; + case winrt::react::uwp::AccessibilityRoles::Image: + return winrt::AutomationControlType::Image; + case winrt::react::uwp::AccessibilityRoles::KeyboardKey: + return winrt::AutomationControlType::Custom; + case winrt::react::uwp::AccessibilityRoles::Text: + case winrt::react::uwp::AccessibilityRoles::Summary: + case winrt::react::uwp::AccessibilityRoles::Header: + return winrt::AutomationControlType::Text; + case winrt::react::uwp::AccessibilityRoles::Adjustable: + return winrt::AutomationControlType::Slider; + case winrt::react::uwp::AccessibilityRoles::Search: + case winrt::react::uwp::AccessibilityRoles::Unknown: + default: + return winrt::AutomationControlType::Group; + } +} + +winrt::IInspectable DynamicAutomationPeer::GetPatternCore(winrt::PatternInterface const& patternInterface) const +{ + auto accessibilityRole = GetAccessibilityRole(); + + if (patternInterface == winrt::PatternInterface::Invoke && + (accessibilityRole == winrt::react::uwp::AccessibilityRoles::Button || accessibilityRole == winrt::react::uwp::AccessibilityRoles::ImageButton)) + { + return *this; + } + else if (patternInterface == winrt::PatternInterface::Selection || patternInterface == winrt::PatternInterface::SelectionItem) + { + return *this; + } + + return Super::GetPatternCore(patternInterface); +} + +bool DynamicAutomationPeer::IsEnabledCore() const +{ + bool disabled = GetAccessibilityState(winrt::react::uwp::AccessibilityStates::Disabled); + return !disabled && Super::IsEnabledCore(); +} + +// IInvokeProvider + +void DynamicAutomationPeer::Invoke() const +{ + if (auto invokeHandler = GetAccessibilityInvokeEventHandler()) + { + invokeHandler(); + } +} + +// ISelectionProvider + +winrt::com_array DynamicAutomationPeer::GetSelection() const +{ + // We don't differentiate between Views that are containers and Views that are items, and we don't + // have a way to specify the linkage between the two + + // Returning nothing until that linkage exists + return {}; +} + +// ISelectionItemProvider + +bool DynamicAutomationPeer::IsSelected() const +{ + return GetAccessibilityState(winrt::react::uwp::AccessibilityStates::Selected); +} + +winrt::IRawElementProviderSimple DynamicAutomationPeer::SelectionContainer() const +{ + // We don't differentiate between Views that are containers and Views that are items, and we don't + // have a way to specify the linkage between the two + + // Returning nothing until that linkage exists + + return nullptr; +} + +void DynamicAutomationPeer::AddToSelection() const +{ + // Right now RN does not have "selection" events, so this is a no-op +} + +void DynamicAutomationPeer::RemoveFromSelection() const +{ + // Right now RN does not have "selection" events, so this is a no-op +} + +void DynamicAutomationPeer::Select() const +{ + // Right now RN does not have "selection" events, so this is a no-op +} + +winrt::react::uwp::AccessibilityRoles DynamicAutomationPeer::GetAccessibilityRole() const +{ + try + { + if (auto owner = Owner()) + { + return DynamicAutomationProperties::GetAccessibilityRole(owner); + } + } + catch (...) {} + + return winrt::react::uwp::AccessibilityRoles::None; +} + +bool DynamicAutomationPeer::GetAccessibilityState(winrt::react::uwp::AccessibilityStates state) const +{ + try + { + if (auto owner = Owner()) + { + switch (state) + { + case winrt::react::uwp::AccessibilityStates::Disabled: + return DynamicAutomationProperties::GetAccessibilityStateDisabled(owner); + case winrt::react::uwp::AccessibilityStates::Selected: + return DynamicAutomationProperties::GetAccessibilityStateSelected(owner); + } + } + } + catch (...) {} + + return false; +} + +winrt::react::uwp::AccessibilityInvokeEventHandler DynamicAutomationPeer::GetAccessibilityInvokeEventHandler() const +{ + try + { + if (auto owner = Owner()) + { + return DynamicAutomationProperties::GetAccessibilityInvokeEventHandler(owner); + } + } + catch (...) {} + + return nullptr; +} + +} // namespace winrt::react::uwp::implementation diff --git a/vnext/ReactUWP/Views/DynamicAutomationPeer.h b/vnext/ReactUWP/Views/DynamicAutomationPeer.h new file mode 100644 index 00000000000..7cf65fa93a4 --- /dev/null +++ b/vnext/ReactUWP/Views/DynamicAutomationPeer.h @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "DynamicAutomationProperties.h" + +#include "cppwinrt/DynamicAutomationPeer.g.h" +namespace winrt::react::uwp::implementation +{ + +// +// DynamicAutomationPeer translates the values of the attached properties in DynamicAutomationProperties +// into the equivalent UIA AutomationPeer +// +struct DynamicAutomationPeer : DynamicAutomationPeerT +{ + using Super = DynamicAutomationPeerT; + + DynamicAutomationPeer() = delete; + DynamicAutomationPeer(winrt::Windows::UI::Xaml::FrameworkElement const& owner); + + winrt::hstring GetClassNameCore() const; + + winrt::Windows::UI::Xaml::Automation::Peers::AutomationControlType GetAutomationControlTypeCore() const; + winrt::Windows::Foundation::IInspectable GetPatternCore(winrt::Windows::UI::Xaml::Automation::Peers::PatternInterface const& patternInterface) const; + + bool IsEnabledCore() const; + + // IInvokeProvider + void Invoke() const; + + // ISelectionProvider + bool CanSelectMultiple() const { return true; } + bool IsSelectionRequired() const { return false; } + winrt::com_array GetSelection() const; + + // ISelectionItemProvider + bool IsSelected() const; + winrt::Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple SelectionContainer() const; + void AddToSelection() const; + void RemoveFromSelection() const; + void Select() const; + +private: + winrt::react::uwp::AccessibilityRoles GetAccessibilityRole() const; + bool GetAccessibilityState(winrt::react::uwp::AccessibilityStates state) const; + winrt::react::uwp::AccessibilityInvokeEventHandler GetAccessibilityInvokeEventHandler() const; +}; +} // namespace winrt::react::uwp::implementation + +namespace winrt::react::uwp::factory_implementation +{ + struct DynamicAutomationPeer : DynamicAutomationPeerT + { + }; +} diff --git a/vnext/ReactUWP/Views/DynamicAutomationProperties.cpp b/vnext/ReactUWP/Views/DynamicAutomationProperties.cpp new file mode 100644 index 00000000000..082431d98f7 --- /dev/null +++ b/vnext/ReactUWP/Views/DynamicAutomationProperties.cpp @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" + +#include "DynamicAutomationProperties.h" + +#include +#include + +namespace winrt +{ + using namespace Windows::Foundation; + using namespace Windows::UI; + using namespace Windows::UI::Xaml; + using namespace Windows::UI::Xaml::Interop; +} // namespace winrt + +namespace winrt::react::uwp::implementation +{ + +const winrt::TypeName dynamicAutomationTypeName{ + winrt::hstring{L"DynamicAutomationProperties"}, + winrt::TypeKind::Metadata }; + +winrt::Windows::UI::Xaml::DependencyProperty DynamicAutomationProperties::AccessibilityRoleProperty() +{ + static winrt::DependencyProperty s_AccessibilityRoleProperty = + winrt::DependencyProperty::RegisterAttached( + L"AccessibilityRole", + winrt::xaml_typename(), + dynamicAutomationTypeName, + winrt::PropertyMetadata(winrt::box_value(winrt::react::uwp::AccessibilityRoles::None))); + + return s_AccessibilityRoleProperty; +} + +void DynamicAutomationProperties::SetAccessibilityRole(winrt::Windows::UI::Xaml::UIElement const& element, winrt::react::uwp::AccessibilityRoles const& value) +{ + element.SetValue(AccessibilityRoleProperty(), winrt::box_value(value)); +} + +winrt::react::uwp::AccessibilityRoles DynamicAutomationProperties::GetAccessibilityRole(winrt::Windows::UI::Xaml::UIElement const& element) +{ + return winrt::unbox_value(element.GetValue(AccessibilityRoleProperty())); +} + +winrt::Windows::UI::Xaml::DependencyProperty DynamicAutomationProperties::AccessibilityStateDisabledProperty() +{ + static winrt::DependencyProperty s_AccessibilityStateDisabledProperty = + winrt::DependencyProperty::RegisterAttached( + L"AccessibilityStateDisabled", + winrt::xaml_typename(), + dynamicAutomationTypeName, + winrt::PropertyMetadata(winrt::box_value(false))); + + return s_AccessibilityStateDisabledProperty; +} + +void DynamicAutomationProperties::SetAccessibilityStateDisabled(winrt::Windows::UI::Xaml::UIElement const& element, bool value) +{ + element.SetValue(AccessibilityStateDisabledProperty(), winrt::box_value(value)); +} + +bool DynamicAutomationProperties::GetAccessibilityStateDisabled(winrt::Windows::UI::Xaml::UIElement const& element) +{ + return winrt::unbox_value(element.GetValue(AccessibilityStateDisabledProperty())); +} + +winrt::Windows::UI::Xaml::DependencyProperty DynamicAutomationProperties::AccessibilityStateSelectedProperty() +{ + static winrt::DependencyProperty s_AccessibilityStateSelectedProperty = + winrt::DependencyProperty::RegisterAttached( + L"AccessibilityStateSelected", + winrt::xaml_typename(), + dynamicAutomationTypeName, + winrt::PropertyMetadata(winrt::box_value(false))); + + return s_AccessibilityStateSelectedProperty; +} + +void DynamicAutomationProperties::SetAccessibilityStateSelected(winrt::Windows::UI::Xaml::UIElement const& element, bool value) +{ + element.SetValue(AccessibilityStateSelectedProperty(), winrt::box_value(value)); +} + +bool DynamicAutomationProperties::GetAccessibilityStateSelected(winrt::Windows::UI::Xaml::UIElement const& element) +{ + return winrt::unbox_value(element.GetValue(AccessibilityStateSelectedProperty())); +} + +winrt::Windows::UI::Xaml::DependencyProperty DynamicAutomationProperties::AccessibilityInvokeEventHandlerProperty() +{ + static winrt::DependencyProperty s_AccessibilityInvokeEventHandlerProperty = + winrt::DependencyProperty::RegisterAttached( + L"AccessibilityInvokeEventHandler", + winrt::xaml_typename(), + dynamicAutomationTypeName, + winrt::PropertyMetadata(winrt::box_value(nullptr))); + + return s_AccessibilityInvokeEventHandlerProperty; +} + +void DynamicAutomationProperties::SetAccessibilityInvokeEventHandler(winrt::Windows::UI::Xaml::UIElement const& element, winrt::react::uwp::AccessibilityInvokeEventHandler const& value) +{ + element.SetValue(AccessibilityInvokeEventHandlerProperty(), winrt::box_value(value)); +} + +winrt::react::uwp::AccessibilityInvokeEventHandler DynamicAutomationProperties::GetAccessibilityInvokeEventHandler(winrt::Windows::UI::Xaml::UIElement const& element) +{ + return winrt::unbox_value(element.GetValue(AccessibilityInvokeEventHandlerProperty())); +} + +} // namespace winrt::react::uwp::implementation diff --git a/vnext/ReactUWP/Views/DynamicAutomationProperties.h b/vnext/ReactUWP/Views/DynamicAutomationProperties.h new file mode 100644 index 00000000000..d85cff29a0e --- /dev/null +++ b/vnext/ReactUWP/Views/DynamicAutomationProperties.h @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include + +#include "cppwinrt/DynamicAutomationProperties.g.h" + +namespace winrt::react::uwp::implementation +{ + +// +// DynamicAutomationProperties provides attached properties for the various +// accessibility related properties in RN that will be used by DynamicAutomationPeer +// +struct DynamicAutomationProperties : DynamicAutomationPropertiesT +{ + using Super = DynamicAutomationPropertiesT; + +public: + DynamicAutomationProperties() = delete; + + // Attached Properties + + static winrt::Windows::UI::Xaml::DependencyProperty AccessibilityRoleProperty(); + static void SetAccessibilityRole(winrt::Windows::UI::Xaml::UIElement const& element, winrt::react::uwp::AccessibilityRoles const& value); + static winrt::react::uwp::AccessibilityRoles GetAccessibilityRole(winrt::Windows::UI::Xaml::UIElement const& element); + + static winrt::Windows::UI::Xaml::DependencyProperty AccessibilityStateDisabledProperty(); + static void SetAccessibilityStateDisabled(winrt::Windows::UI::Xaml::UIElement const& element, bool value); + static bool GetAccessibilityStateDisabled(winrt::Windows::UI::Xaml::UIElement const& element); + + static winrt::Windows::UI::Xaml::DependencyProperty AccessibilityStateSelectedProperty(); + static void SetAccessibilityStateSelected(winrt::Windows::UI::Xaml::UIElement const& element, bool value); + static bool GetAccessibilityStateSelected(winrt::Windows::UI::Xaml::UIElement const& element); + + static winrt::Windows::UI::Xaml::DependencyProperty AccessibilityInvokeEventHandlerProperty(); + static void SetAccessibilityInvokeEventHandler(Windows::UI::Xaml::UIElement const& element, winrt::react::uwp::AccessibilityInvokeEventHandler const& value); + static winrt::react::uwp::AccessibilityInvokeEventHandler GetAccessibilityInvokeEventHandler(winrt::Windows::UI::Xaml::UIElement const& element); +}; + +} + +namespace winrt::react::uwp::factory_implementation +{ + struct DynamicAutomationProperties : DynamicAutomationPropertiesT + { + }; +} + +namespace react::uwp +{ + // BUG: Calling static members on winrt::react::uwp::DynamicAutomationProperties fails to call + // down into winrt::react::uwp::implementation::DynamicAutomationProperties because of how we're + // using cppwinrt. This workaround is so that consumers in react::uwp can just call DynamicAutomationProperties + + using DynamicAutomationProperties = winrt::react::uwp::implementation::DynamicAutomationProperties; +} diff --git a/vnext/ReactUWP/Views/FlyoutViewManager.cpp b/vnext/ReactUWP/Views/FlyoutViewManager.cpp index 301ab236ec2..d4d72cdedaf 100644 --- a/vnext/ReactUWP/Views/FlyoutViewManager.cpp +++ b/vnext/ReactUWP/Views/FlyoutViewManager.cpp @@ -17,70 +17,44 @@ namespace winrt { using namespace Windows::UI::Xaml::Interop; } +static const std::unordered_map placementModeMinVersion = { + {"top", winrt::FlyoutPlacementMode::Top}, + {"bottom", winrt::FlyoutPlacementMode::Bottom}, + {"left", winrt::FlyoutPlacementMode::Left}, + {"right", winrt::FlyoutPlacementMode::Right}, + {"full", winrt::FlyoutPlacementMode::Full} +}; + +static const std::unordered_map placementModeRS5 = { + {"top", winrt::FlyoutPlacementMode::Top}, + {"bottom", winrt::FlyoutPlacementMode::Bottom}, + {"left", winrt::FlyoutPlacementMode::Left}, + {"right", winrt::FlyoutPlacementMode::Right}, + {"full", winrt::FlyoutPlacementMode::Full}, + {"top-edge-aligned-left", winrt::FlyoutPlacementMode::TopEdgeAlignedLeft}, + {"top-edge-aligned-right", winrt::FlyoutPlacementMode::TopEdgeAlignedRight}, + {"bottom-edge-aligned-left", winrt::FlyoutPlacementMode::BottomEdgeAlignedLeft}, + {"bottom-edge-aligned-right", winrt::FlyoutPlacementMode::BottomEdgeAlignedRight}, + {"left-edge-aligned-top", winrt::FlyoutPlacementMode::LeftEdgeAlignedTop}, + {"left-edge-aligned-bottom", winrt::FlyoutPlacementMode::LeftEdgeAlignedBottom}, + {"right-edge-aligned-top", winrt::FlyoutPlacementMode::RightEdgeAlignedTop}, + {"right-edge-aligned-bottom", winrt::FlyoutPlacementMode::RightEdgeAlignedBottom} +}; + template<> struct json_type_traits { static winrt::FlyoutPlacementMode parseJson(const folly::dynamic& json) { - winrt::FlyoutPlacementMode placement; - if (json == "top") - { - placement = winrt::FlyoutPlacementMode::Top; - } - else if (json == "bottom") - { - placement = winrt::FlyoutPlacementMode::Bottom; - } - else if (json == "left") - { - placement = winrt::FlyoutPlacementMode::Left; - } - else if (json == "right") - { - placement = winrt::FlyoutPlacementMode::Right; - } - else if (json == "top-edge-aligned-left") - { - placement = winrt::FlyoutPlacementMode::TopEdgeAlignedLeft; - } - else if (json == "top-edge-aligned-right") - { - placement = winrt::FlyoutPlacementMode::TopEdgeAlignedRight; - } - else if (json == "bottom-edge-aligned-left") - { - placement = winrt::FlyoutPlacementMode::BottomEdgeAlignedLeft; - } - else if (json == "bottom-edge-aligned-right") - { - placement = winrt::FlyoutPlacementMode::BottomEdgeAlignedRight; - } - else if (json == "left-edge-aligned-top") - { - placement = winrt::FlyoutPlacementMode::LeftEdgeAlignedTop; - } - else if (json == "right-edge-aligned-top") - { - placement = winrt::FlyoutPlacementMode::RightEdgeAlignedTop; - } - else if (json == "left-bottom") - { - placement = winrt::FlyoutPlacementMode::LeftEdgeAlignedBottom; - } - else if (json == "right-edge-aligned-bottom") - { - placement = winrt::FlyoutPlacementMode::RightEdgeAlignedBottom; - } - else if (json == "full") - { - placement = winrt::FlyoutPlacementMode::Full; - } - else + auto placementMode = !!(winrt::Flyout().try_as()) ? placementModeRS5 : placementModeMinVersion; + auto iter = placementMode.find(json.asString()); + + if (iter != placementMode.end()) { - placement = winrt::FlyoutPlacementMode::Top; + return iter->second; } - return placement; + return winrt::FlyoutPlacementMode::Right; } }; @@ -115,18 +89,21 @@ class FlyoutShadowNode : public ShadowNodeBase bool m_isFlyoutShowOptionsSupported = false; winrt::FlyoutShowOptions m_showOptions = nullptr; - std::shared_ptr m_touchEventHanadler; + std::unique_ptr m_touchEventHanadler; + std::unique_ptr m_previewKeyboardEventHandlerOnRoot; }; FlyoutShadowNode::~FlyoutShadowNode() { m_touchEventHanadler->RemoveTouchHandlers(); + m_previewKeyboardEventHandlerOnRoot->unhook(); } void FlyoutShadowNode::AddView(ShadowNode& child, int64_t index) { auto childView = static_cast(child).GetView(); m_touchEventHanadler->AddTouchHandlers(childView); + m_previewKeyboardEventHandlerOnRoot->hook(childView); if (m_flyout != nullptr) m_flyout.Content(childView.as()); @@ -143,7 +120,8 @@ void FlyoutShadowNode::createView() m_showOptions = winrt::FlyoutShowOptions(); auto wkinstance = GetViewManager()->GetReactInstance(); - m_touchEventHanadler = std::make_shared(wkinstance); + m_touchEventHanadler = std::make_unique(wkinstance); + m_previewKeyboardEventHandlerOnRoot = std::make_unique(wkinstance); m_flyout.Closing([=](winrt::FlyoutBase /*flyoutbase*/, winrt::FlyoutBaseClosingEventArgs args) { @@ -273,12 +251,6 @@ void FlyoutShadowNode::updateProperties(const folly::dynamic&& props) m_showOptions.Position(newPoint); } - if (m_isFlyoutShowOptionsSupported) - { - winrt::Rect exclusionRect = winrt::Rect(100, 100, 20, 20); - m_showOptions.ExclusionRect(exclusionRect); - } - if (updateIsOpen) { if (m_isOpen) @@ -363,7 +335,7 @@ const char* FlyoutViewManager::GetName() const XamlView FlyoutViewManager::CreateViewCore(int64_t tag) { - return ViewPanel::Create().as(); + return winrt::make().as(); } facebook::react::ShadowNode* FlyoutViewManager::createShadow() const diff --git a/vnext/ReactUWP/Views/FrameworkElementViewManager.cpp b/vnext/ReactUWP/Views/FrameworkElementViewManager.cpp index 148de01af44..a38f7647141 100644 --- a/vnext/ReactUWP/Views/FrameworkElementViewManager.cpp +++ b/vnext/ReactUWP/Views/FrameworkElementViewManager.cpp @@ -20,6 +20,9 @@ #include #include #include +#include + +#include "DynamicAutomationProperties.h" namespace winrt { using namespace Windows::UI::Xaml; @@ -65,6 +68,10 @@ void FrameworkElementViewManager::TransferProperties(XamlView oldView, XamlView auto accessibilityView = winrt::AutomationProperties::GetAccessibilityView(oldView); winrt::AutomationProperties::SetAccessibilityView(newView, accessibilityView); winrt::AutomationProperties::SetAccessibilityView(oldView, winrt::Peers::AccessibilityView::Raw); + TransferProperty(oldView, newView, DynamicAutomationProperties::AccessibilityRoleProperty()); + TransferProperty(oldView, newView, DynamicAutomationProperties::AccessibilityStateDisabledProperty()); + TransferProperty(oldView, newView, DynamicAutomationProperties::AccessibilityStateSelectedProperty()); + TransferProperty(oldView, newView, DynamicAutomationProperties::AccessibilityInvokeEventHandlerProperty()); auto tooltip = winrt::ToolTipService::GetToolTip(oldView); oldView.ClearValue(winrt::ToolTipService::ToolTipProperty()); @@ -87,8 +94,11 @@ folly::dynamic FrameworkElementViewManager::GetNativeProps() const void FrameworkElementViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const folly::dynamic& reactDiffMap) { auto element(nodeToUpdate->GetView().as()); + if (element != nullptr) { + auto elementXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(element); + for (const auto& pair : reactDiffMap.items()) { const std::string& propertyName = pair.first.getString(); @@ -100,13 +110,20 @@ void FrameworkElementViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, { double opacity = propertyValue.asDouble(); if (opacity >= 0 && opacity <= 1) - element.Opacity(opacity); + XamlDirectInstance::GetXamlDirect().SetDoubleProperty( + elementXD, + XD::XamlPropertyIndex::UIElement_Opacity, + opacity + ); // else // TODO report error } else if (propertyValue.isNull()) { - element.ClearValue(winrt::UIElement::OpacityProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + elementXD, + XD::XamlPropertyIndex::UIElement_Opacity + ); continue; } } @@ -149,13 +166,20 @@ void FrameworkElementViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, { double width = propertyValue.asDouble(); if (width >= 0) - element.Width(width); + XamlDirectInstance::GetXamlDirect().SetDoubleProperty( + elementXD, + XD::XamlPropertyIndex::FrameworkElement_Width, + width + ); // else // TODO report error } else if (propertyValue.isNull()) { - element.ClearValue(winrt::FrameworkElement::WidthProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + elementXD, + XD::XamlPropertyIndex::FrameworkElement_Width + ); continue; } @@ -166,13 +190,20 @@ void FrameworkElementViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, { double height = propertyValue.asDouble(); if (height >= 0) - element.Height(height); + XamlDirectInstance::GetXamlDirect().SetDoubleProperty( + elementXD, + XD::XamlPropertyIndex::FrameworkElement_Height, + height + ); // else // TODO report error } else if (propertyValue.isNull()) { - element.ClearValue(winrt::FrameworkElement::HeightProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + elementXD, + XD::XamlPropertyIndex::FrameworkElement_Height + ); continue; } } @@ -182,13 +213,20 @@ void FrameworkElementViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, { double minWidth = propertyValue.asDouble(); if (minWidth >= 0) - element.MinWidth(minWidth); + XamlDirectInstance::GetXamlDirect().SetDoubleProperty( + elementXD, + XD::XamlPropertyIndex::FrameworkElement_MinWidth, + minWidth + ); // else // TODO report error } else if (propertyValue.isNull()) { - element.ClearValue(winrt::FrameworkElement::MinWidthProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + elementXD, + XD::XamlPropertyIndex::FrameworkElement_MinWidth + ); continue; } } @@ -198,13 +236,20 @@ void FrameworkElementViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, { double maxWidth = propertyValue.asDouble(); if (maxWidth >= 0) - element.MaxWidth(maxWidth); + XamlDirectInstance::GetXamlDirect().SetDoubleProperty( + elementXD, + XD::XamlPropertyIndex::FrameworkElement_MaxWidth, + maxWidth + ); // else // TODO report error } else if (propertyValue.isNull()) { - element.ClearValue(winrt::FrameworkElement::MaxWidthProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + elementXD, + XD::XamlPropertyIndex::FrameworkElement_MaxWidth + ); continue; } @@ -215,13 +260,20 @@ void FrameworkElementViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, { double minHeight = propertyValue.asDouble(); if (minHeight >= 0) - element.MinHeight(minHeight); + XamlDirectInstance::GetXamlDirect().SetDoubleProperty( + elementXD, + XD::XamlPropertyIndex::FrameworkElement_MinHeight, + minHeight + ); // else // TODO report error } else if (propertyValue.isNull()) { - element.ClearValue(winrt::FrameworkElement::MinHeightProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + elementXD, + XD::XamlPropertyIndex::FrameworkElement_MinHeight + ); continue; } } @@ -231,13 +283,20 @@ void FrameworkElementViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, { double maxHeight = propertyValue.asDouble(); if (maxHeight >= 0) - element.MaxHeight(maxHeight); + XamlDirectInstance::GetXamlDirect().SetDoubleProperty( + elementXD, + XD::XamlPropertyIndex::FrameworkElement_MaxHeight, + maxHeight + ); // else // TODO report error } else if (propertyValue.isNull()) { - element.ClearValue(winrt::FrameworkElement::MaxHeightProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + elementXD, + XD::XamlPropertyIndex::FrameworkElement_MaxHeight + ); continue; } @@ -247,13 +306,19 @@ void FrameworkElementViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, if (propertyValue.isString()) { auto value = react::uwp::asHstring(propertyValue); - auto boxedValue = winrt::Windows::Foundation::PropertyValue::CreateString(value); - element.SetValue(winrt::AutomationProperties::HelpTextProperty(), boxedValue); + XamlDirectInstance::GetXamlDirect().SetStringProperty( + elementXD, + XD::XamlPropertyIndex::AutomationProperties_HelpText, + value + ); } else if (propertyValue.isNull()) { - element.ClearValue(winrt::AutomationProperties::HelpTextProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + elementXD, + XD::XamlPropertyIndex::AutomationProperties_HelpText + ); } } else if (propertyName == "accessibilityLabel") @@ -261,13 +326,19 @@ void FrameworkElementViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, if (propertyValue.isString()) { auto value = react::uwp::asHstring(propertyValue); - auto boxedValue = winrt::Windows::Foundation::PropertyValue::CreateString(value); - - element.SetValue(winrt::AutomationProperties::NameProperty(), boxedValue); + + XamlDirectInstance::GetXamlDirect().SetStringProperty( + elementXD, + XD::XamlPropertyIndex::AutomationProperties_Name, + value + ); } else if (propertyValue.isNull()) { - element.ClearValue(winrt::AutomationProperties::NameProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + elementXD, + XD::XamlPropertyIndex::AutomationProperties_Name + ); } AnnounceLiveRegionChangedIfNeeded(element); } @@ -276,7 +347,11 @@ void FrameworkElementViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, if (propertyValue.isBool()) { if (!propertyValue.asBool()) - winrt::AutomationProperties::SetAccessibilityView(element, winrt::Peers::AccessibilityView::Raw); + XamlDirectInstance::GetXamlDirect().SetEnumProperty( + elementXD, + XD::XamlPropertyIndex::AutomationProperties_AccessibilityView, + static_cast(winrt::Peers::AccessibilityView::Raw) + ); } } else if (propertyName == "accessibilityLiveRegion") @@ -296,52 +371,135 @@ void FrameworkElementViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, liveSetting = winrt::AutomationLiveSetting::Assertive; } - element.SetValue(winrt::AutomationProperties::LiveSettingProperty(), winrt::box_value(liveSetting)); + XamlDirectInstance::GetXamlDirect().SetEnumProperty( + elementXD, + XD::XamlPropertyIndex::AutomationProperties_LiveSetting, + static_cast(liveSetting) + ); } else if (propertyValue.isNull()) { - element.ClearValue(winrt::AutomationProperties::LiveSettingProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + elementXD, + XD::XamlPropertyIndex::AutomationProperties_LiveSetting + ); } AnnounceLiveRegionChangedIfNeeded(element); } + else if (propertyName == "accessibilityRole") + { + if (propertyValue.isString()) + { + const std::string& role = propertyValue.getString(); + if (role == "none") + DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::None); + else if (role == "button") + DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Button); + else if (role == "link") + DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Link); + else if (role == "search") + DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Search); + else if (role == "image") + DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Image); + else if (role == "keyboardkey") + DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::KeyboardKey); + else if (role == "text") + DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Text); + else if (role == "adjustable") + DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Adjustable); + else if (role == "imagebutton") + DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::ImageButton); + else if (role == "header") + DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Header); + else if (role == "summary") + DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Summary); + else + DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Unknown); + } + else if (propertyValue.isNull()) + { + element.ClearValue(DynamicAutomationProperties::AccessibilityRoleProperty()); + } + } + else if (propertyName == "accessibilityStates") + { + bool disabled = false; + bool selected = false; + + if (propertyValue.isArray()) + { + for (const auto& state : propertyValue) + { + if (!state.isString()) + continue; + if (state.getString() == "disabled") + disabled = true; + else if (state.getString() == "selected") + selected = true; + } + } + + DynamicAutomationProperties::SetAccessibilityStateDisabled(element, disabled); + DynamicAutomationProperties::SetAccessibilityStateSelected(element, selected); + } else if (propertyName == "testID") { if (propertyValue.isString()) { auto value = react::uwp::asHstring(propertyValue); - auto boxedValue = winrt::Windows::Foundation::PropertyValue::CreateString(value); - element.SetValue(winrt::AutomationProperties::AutomationIdProperty(), boxedValue); + XamlDirectInstance::GetXamlDirect().SetStringProperty( + elementXD, + XD::XamlPropertyIndex::AutomationProperties_AutomationId, + value + ); } else if (propertyValue.isNull()) { - element.ClearValue(winrt::AutomationProperties::AutomationIdProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + elementXD, + XD::XamlPropertyIndex::AutomationProperties_AutomationId + ); } } else if (propertyName == "tooltip") { if (propertyValue.isString()) { - winrt::TextBlock tooltip = winrt::TextBlock(); - tooltip.Text(asHstring(propertyValue)); - winrt::ToolTipService::SetToolTip(element, tooltip); + auto tooltip = XamlDirectInstance::GetXamlDirect().CreateInstance(XD::XamlTypeIndex::TextBlock); + XamlDirectInstance::GetXamlDirect().SetStringProperty( + tooltip, + XD::XamlPropertyIndex::TextBlock_Text, + asHstring(propertyValue) + ); + XamlDirectInstance::GetXamlDirect().SetXamlDirectObjectProperty( + elementXD, + XD::XamlPropertyIndex::ToolTipService_ToolTip, + tooltip + ); } } else if (propertyName == "zIndex") { if (propertyValue.isNumber()) { - auto value = static_cast(propertyValue.asDouble()); - auto boxedValue = winrt::Windows::Foundation::PropertyValue::CreateInt32(value); + auto value = static_cast(propertyValue.asDouble()); - element.SetValue(winrt::Canvas::ZIndexProperty(), boxedValue); + XamlDirectInstance::GetXamlDirect().SetInt32Property( + elementXD, + XD::XamlPropertyIndex::Canvas_ZIndex, + value + ); } else if (propertyValue.isNull()) { - element.ClearValue(winrt::Canvas::ZIndexProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + elementXD, + XD::XamlPropertyIndex::Canvas_ZIndex + ); } } - else if (TryUpdateFlowDirection(element, propertyName, propertyValue)) + else if (TryUpdateFlowDirection(elementXD, propertyName, propertyValue, XD::XamlPropertyIndex::FrameworkElement_FlowDirection)) { continue; } @@ -385,6 +543,35 @@ void FrameworkElementViewManager::StartTransformAnimation( uielement.StartAnimation(expression); } +folly::dynamic FrameworkElementViewManager::GetCommands() const +{ + // Don't update SetFocus/Blur commands in subclass, otherwise commands may not match with what defined in js side. + auto commands = Super::GetCommands(); + commands.update(folly::dynamic::object + ("SetFocus", static_cast>(FocusCommand::SetFocus)) + ); + commands.update(folly::dynamic::object + ("Blur", static_cast>(FocusCommand::Blur)) + ); + return commands; +} + +void FrameworkElementViewManager::DispatchCommand(XamlView viewToUpdate, int64_t commandId, const folly::dynamic& commandArgs) +{ + assert(viewToUpdate); + + auto focusCommand = (static_cast(commandId)); + if (focusCommand == FocusCommand::SetFocus) + winrt::FocusManager::TryFocusAsync(viewToUpdate, winrt::FocusState::Programmatic); + else if (focusCommand == FocusCommand::Blur) + { + // UWP doesn't have the blur concept. Here we use FocusState::Pointer to move away to keyboard focused visual. + // Only blur if current UI is focused to avoid problem described in PR #2687 + if (viewToUpdate == winrt::FocusManager::GetFocusedElement().try_as()) + winrt::FocusManager::TryFocusAsync(viewToUpdate, winrt::FocusState::Pointer); + } +} + // Used in scenario where View changes its backing Xaml element. void FrameworkElementViewManager::RefreshTransformMatrix(ShadowNodeBase* shadowNode) { diff --git a/vnext/ReactUWP/Views/Image/BorderEffect.h b/vnext/ReactUWP/Views/Image/BorderEffect.h index e580f958b8b..aef50aa0a6e 100644 --- a/vnext/ReactUWP/Views/Image/BorderEffect.h +++ b/vnext/ReactUWP/Views/Image/BorderEffect.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "Microsoft.UI.Composition.Effects_Impl.h" namespace winrt::Microsoft::UI::Composition::Effects::implementation diff --git a/vnext/ReactUWP/Views/Image/ImageViewManager.cpp b/vnext/ReactUWP/Views/Image/ImageViewManager.cpp index 9942a8e8e0d..288232d9d0e 100644 --- a/vnext/ReactUWP/Views/Image/ImageViewManager.cpp +++ b/vnext/ReactUWP/Views/Image/ImageViewManager.cpp @@ -82,6 +82,34 @@ struct json_type_traits namespace react { namespace uwp { + class ImageShadowNode : public ShadowNodeBase { + public: + ImageShadowNode() = default; + + void createView() override + { + ShadowNodeBase::createView(); + auto reactImage{ m_view.as() }; + + m_onLoadEndToken = reactImage->OnLoadEnd([imageViewManager{ static_cast(GetViewManager()) }, reactImage ](const auto&, const bool& succeeded) + { + ImageSource source{ reactImage->Source() }; + + imageViewManager->EmitImageEvent(reactImage.as(), succeeded ? "topLoad" : "topError", source); + imageViewManager->EmitImageEvent(reactImage.as(), "topLoadEnd", source); + }); + } + + void onDropViewInstance() override + { + auto reactImage{ m_view.as() }; + reactImage->OnLoadEnd(m_onLoadEndToken); + } + + private: + winrt::event_token m_onLoadEndToken; + }; + ImageViewManager::ImageViewManager(const std::shared_ptr& reactInstance) : Super(reactInstance) { @@ -94,17 +122,7 @@ namespace react { namespace uwp { XamlView ImageViewManager::CreateViewCore(int64_t tag) { - auto reactImage{ ReactImage::Create() }; - - reactImage->OnLoadEnd([this, reactImage](const auto&, const bool& succeeded) - { - ImageSource source{ reactImage->Source() }; - - EmitImageEvent(m_wkReactInstance.lock(), reactImage.as(), succeeded ? "topLoad" : "topError", source); - EmitImageEvent(m_wkReactInstance.lock(), reactImage.as(), "topLoadEnd", source); - }); - - return reactImage.as(); + return ReactImage::Create().as(); } void ImageViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const folly::dynamic& reactDiffMap) @@ -136,8 +154,9 @@ namespace react { namespace uwp { Super::UpdateProperties(nodeToUpdate, reactDiffMap); } - void EmitImageEvent(const std::shared_ptr& reactInstance, winrt::Canvas canvas, const char* eventName, ImageSource& source) + void ImageViewManager::EmitImageEvent(winrt::Canvas canvas, const char* eventName, ImageSource& source) { + auto reactInstance{ m_wkReactInstance.lock() }; if (reactInstance == nullptr) return; @@ -160,9 +179,11 @@ namespace react { namespace uwp { return; auto sources{ json_type_traits>::parseJson(data) }; + sources[0].bundleRootPath = instance->GetBundleRootPath(); + auto reactImage{ canvas.as() }; - EmitImageEvent(instance, canvas, "topLoadStart", sources[0]); + EmitImageEvent(canvas, "topLoadStart", sources[0]); reactImage->Source(sources[0]); } diff --git a/vnext/ReactUWP/Views/Image/ImageViewManager.h b/vnext/ReactUWP/Views/Image/ImageViewManager.h index 488528de5f5..d51bf558d2e 100644 --- a/vnext/ReactUWP/Views/Image/ImageViewManager.h +++ b/vnext/ReactUWP/Views/Image/ImageViewManager.h @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include +#include "ReactImage.h" namespace react { namespace uwp { @@ -16,6 +17,7 @@ namespace react { namespace uwp { folly::dynamic GetExportedCustomDirectEventTypeConstants() const override; folly::dynamic GetNativeProps() const override; + void EmitImageEvent(winrt::Windows::UI::Xaml::Controls::Canvas canvas, const char* eventName, ImageSource& source); protected: XamlView CreateViewCore(int64_t tag) override; diff --git a/vnext/ReactUWP/Views/Image/ReactImage.cpp b/vnext/ReactUWP/Views/Image/ReactImage.cpp index 8bb2dab283a..fcee30ef9dc 100644 --- a/vnext/ReactUWP/Views/Image/ReactImage.cpp +++ b/vnext/ReactUWP/Views/Image/ReactImage.cpp @@ -6,6 +6,7 @@ #include "ReactImage.h" #include +#include #include "unicode.h" @@ -69,12 +70,13 @@ namespace react { if (source.packagerAsset && uriString.find("file://") == 0) { - uriString.replace(0, 7, "ms-appx:///Bundle/"); + uriString.replace(0, 7, source.bundleRootPath); } winrt::Uri uri{ facebook::utf8ToUtf16(uriString) }; winrt::hstring scheme{ uri.SchemeName() }; bool needsDownload = (scheme == L"http") || (scheme == L"https"); + bool inlineData = scheme == L"data"; try { @@ -84,22 +86,33 @@ namespace react { if (needsDownload) { memoryStream = co_await GetImageStreamAsync(source); - - if (!memoryStream) - { - m_onLoadEndEvent(*this, false); - } + } + else if (inlineData) + { + memoryStream = co_await GetImageInlineDataAsync(source); } + if ((needsDownload || inlineData) && !memoryStream) + { + m_onLoadEndEvent(*this, false); + } + if (!needsDownload || memoryStream) { - auto surface{ needsDownload ? + auto surface = needsDownload || inlineData ? winrt::LoadedImageSurface::StartLoadFromStream(memoryStream) : - winrt::LoadedImageSurface::StartLoadFromUri(uri) }; - - surface.LoadCompleted({ this, &ReactImage::LoadedImageSurfaceHandler }); - - m_brush->Source(surface); + winrt::LoadedImageSurface::StartLoadFromUri(uri); + + m_surfaceLoadedRevoker = surface.LoadCompleted(winrt::auto_revoke, [weak_this{ get_weak() }, surface](winrt::LoadedImageSurface const& /*sender*/, winrt::LoadedImageSourceLoadCompletedEventArgs const& args) { + if (auto strong_this{ weak_this.get() }) { + bool succeeded{ false }; + if (args.Status() == winrt::LoadedImageSourceLoadStatus::Success) { + strong_this->m_brush->Source(surface); + succeeded = true; + } + strong_this->m_onLoadEndEvent(*strong_this, succeeded); + } + }); } } catch (winrt::hresult_error const&) @@ -108,22 +121,12 @@ namespace react { } } - void ReactImage::LoadedImageSurfaceHandler(winrt::LoadedImageSurface const& sender, winrt::LoadedImageSourceLoadCompletedEventArgs const& args) - { - bool succeeded{ false }; - if (args.Status() == winrt::LoadedImageSourceLoadStatus::Success) - { - m_brush->Source(sender.as()); - succeeded = true; - } - - m_onLoadEndEvent(*this, succeeded); - } - winrt::IAsyncOperation GetImageStreamAsync(ImageSource source) { try { + co_await winrt::resume_background(); + auto httpMethod{ source.method.empty() ? winrt::HttpMethod::Get() : winrt::HttpMethod{facebook::utf8ToUtf16(source.method)} @@ -169,5 +172,32 @@ namespace react { return nullptr; } + + winrt::IAsyncOperation GetImageInlineDataAsync(ImageSource source) + { + size_t start = source.uri.find(','); + if (start == std::string::npos || start + 1 > source.uri.length()) + return nullptr; + + try + { + co_await winrt::resume_background(); + + std::string_view base64String(source.uri.c_str() + start + 1, source.uri.length() - start - 1); + auto buffer = winrt::Windows::Security::Cryptography::CryptographicBuffer::DecodeFromBase64String(facebook::react::unicode::utf8ToUtf16(base64String)); + + winrt::InMemoryRandomAccessStream memoryStream; + co_await memoryStream.WriteAsync(buffer); + memoryStream.Seek(0); + + return memoryStream; + } + catch (winrt::hresult_error const&) + { + // Base64 decode failed + } + + return nullptr; + } } } // namespace react::uwp diff --git a/vnext/ReactUWP/Views/Image/ReactImage.h b/vnext/ReactUWP/Views/Image/ReactImage.h index 9b6a08f215d..87ba69c83f2 100644 --- a/vnext/ReactUWP/Views/Image/ReactImage.h +++ b/vnext/ReactUWP/Views/Image/ReactImage.h @@ -20,6 +20,7 @@ namespace react { { std::string uri; std::string method; + std::string bundleRootPath; folly::dynamic headers; double width = 0; double height = 0; @@ -54,16 +55,14 @@ namespace react { void ResizeMode(react::uwp::ResizeMode value) { m_brush->ResizeMode(value); } private: - void LoadedImageSurfaceHandler( - winrt::Windows::UI::Xaml::Media::LoadedImageSurface const& sender, - winrt::Windows::UI::Xaml::Media::LoadedImageSourceLoadCompletedEventArgs const& args); - ImageSource m_imageSource; winrt::com_ptr m_brush; winrt::event> m_onLoadEndEvent; + winrt::Windows::UI::Xaml::Media::LoadedImageSurface::LoadCompleted_revoker m_surfaceLoadedRevoker; }; // Helper functions winrt::Windows::Foundation::IAsyncOperation GetImageStreamAsync(ImageSource source); + winrt::Windows::Foundation::IAsyncOperation GetImageInlineDataAsync(ImageSource source); } } // namespace react::uwp diff --git a/vnext/ReactUWP/Views/Image/ReactImageBrush.cpp b/vnext/ReactUWP/Views/Image/ReactImageBrush.cpp index 6666816671d..9b3f753d4f9 100644 --- a/vnext/ReactUWP/Views/Image/ReactImageBrush.cpp +++ b/vnext/ReactUWP/Views/Image/ReactImageBrush.cpp @@ -61,7 +61,16 @@ namespace react { { if (m_loadedImageSurface != value) { + bool updateSurface{ m_loadedImageSurface }; + m_loadedImageSurface = value; + + if (updateSurface) + { + winrt::CompositionSurfaceBrush surfaceBrush{ GetOrCreateSurfaceBrush() }; + surfaceBrush.Surface(m_loadedImageSurface); + } + UpdateCompositionBrush(); } } @@ -85,39 +94,41 @@ namespace react { // and anytime we switch between Surface and Effect brushes (to/from ResizeMode::Repeat) if (CompositionBrush() != compositionBrush) { + if (ResizeMode() == ResizeMode::Repeat) + { + surfaceBrush.HorizontalAlignmentRatio(0.0f); + surfaceBrush.VerticalAlignmentRatio(0.0f); + } + else + { + surfaceBrush.HorizontalAlignmentRatio(0.5f); + surfaceBrush.VerticalAlignmentRatio(0.5f); + } + CompositionBrush(compositionBrush); } } } - bool ReactImageBrush::IsImageLargerThanView() + bool ReactImageBrush::IsImageSmallerThanView() { if (m_loadedImageSurface) { auto surface{ GetOrCreateSurfaceBrush().Surface().as() }; winrt::Size dipsSize{ surface.DecodedSize() }; - return (dipsSize.Height > AvailableSize().Height) || (dipsSize.Width > AvailableSize().Width); + return (dipsSize.Height < AvailableSize().Height) && (dipsSize.Width < AvailableSize().Width); } return false; } - bool ReactImageBrush::UsingSurfaceBrush() - { - return CompositionBrush().try_as() != nullptr; - } - winrt::CompositionStretch ReactImageBrush::ResizeModeToStretch() { auto stretch{ winrt::CompositionStretch::None }; switch (ResizeMode()) { - case ResizeMode::Center: - stretch = IsImageLargerThanView() ? winrt::CompositionStretch::Uniform : winrt::CompositionStretch::None; - break; - case ResizeMode::Contain: stretch = winrt::CompositionStretch::Uniform; break; @@ -130,8 +141,9 @@ namespace react { stretch = winrt::CompositionStretch::Fill; break; + case ResizeMode::Center: case ResizeMode::Repeat: - stretch = IsImageLargerThanView() ? winrt::CompositionStretch::Uniform : winrt::CompositionStretch::None; + stretch = IsImageSmallerThanView() ? winrt::CompositionStretch::None : winrt::CompositionStretch::Uniform; break; } @@ -178,9 +190,6 @@ namespace react { winrt::CompositionEffectFactory effectFactory{ winrt::Window::Current().Compositor().CreateEffectFactory(borderEffect) }; m_effectBrush = effectFactory.CreateBrush(); - surfaceBrush.HorizontalAlignmentRatio(0.0f); - surfaceBrush.VerticalAlignmentRatio(0.0f); - m_effectBrush.SetSourceParameter(L"source", surfaceBrush); } diff --git a/vnext/ReactUWP/Views/Image/ReactImageBrush.h b/vnext/ReactUWP/Views/Image/ReactImageBrush.h index d2472f84e4f..467b3d8c910 100644 --- a/vnext/ReactUWP/Views/Image/ReactImageBrush.h +++ b/vnext/ReactUWP/Views/Image/ReactImageBrush.h @@ -45,8 +45,7 @@ namespace react { private: void UpdateCompositionBrush(); - bool IsImageLargerThanView(); - bool UsingSurfaceBrush(); + bool IsImageSmallerThanView(); winrt::Windows::UI::Composition::CompositionStretch ResizeModeToStretch(); winrt::Windows::UI::Composition::CompositionSurfaceBrush GetOrCreateSurfaceBrush(); winrt::Windows::UI::Composition::CompositionEffectBrush GetOrCreateEffectBrush(winrt::Windows::UI::Composition::CompositionSurfaceBrush const& surfaceBrush); diff --git a/vnext/ReactUWP/Views/KeyboardEventHandler.cpp b/vnext/ReactUWP/Views/KeyboardEventHandler.cpp new file mode 100644 index 00000000000..d59c60dc241 --- /dev/null +++ b/vnext/ReactUWP/Views/KeyboardEventHandler.cpp @@ -0,0 +1,399 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "Views/KeyboardEventHandler.h" +#include "Utils/Helpers.h" +#include "Utils/PropertyHandlerUtils.h" +#include + +using namespace std::placeholders; + +static constexpr auto ALT_KEY = "altKey"; +static constexpr auto CTRL_KEY = "ctrlKey"; +static constexpr auto META_KEY = "metaKey"; +static constexpr auto SHIFT_KEY = "shiftKey"; +static constexpr auto EVENT_PHASE = "handledEventPhase"; +static constexpr auto KEY = "key"; +static constexpr auto TARGET = "target"; + +using namespace react::uwp; + +template<> +struct json_type_traits +{ + static react::uwp::HandledKeyboardEvent parseJson(const folly::dynamic& json) + { + react::uwp::HandledKeyboardEvent event; + + for (auto const& pair : json.items()) + { + const std::string& propertyName = pair.first.getString(); + const folly::dynamic& propertyValue = pair.second; + + if (propertyName == ALT_KEY) + event.altKey = propertyValue.asBool(); + else if (propertyName == SHIFT_KEY) + event.shiftKey = propertyValue.asBool(); + else if (propertyName == CTRL_KEY) + event.ctrlKey = propertyValue.asBool(); + else if (propertyName == META_KEY) + event.metaKey = propertyValue.asBool(); + else if (propertyName == KEY) + event.key = propertyValue.asString(); + else if (propertyName == EVENT_PHASE) + event.handledEventPhase = asEnum(propertyValue); + } + + //To simplify the implementaion, key from JS is converted to upper case. + toUpperInplace(event.key); + return event; + } +}; + +namespace react {namespace uwp { + +std::vector KeyboardHelper::FromJS(folly::dynamic const& obj) +{ + return json_type_traits>::parseJson(obj); +} + +static folly::dynamic ToEventData(ReactKeyboardEvent event) +{ + return folly::dynamic::object + (TARGET, event.target) + (ALT_KEY, event.altKey) + (CTRL_KEY, event.ctrlKey) + (KEY, event.key) + (META_KEY, event.metaKey) + (SHIFT_KEY, event.shiftKey); +} + +KeyboardEventBaseHandler::KeyboardEventBaseHandler(KeyboardEventCallback&& keyDown, KeyboardEventCallback&& keyUp) + :m_keyDownCallback(std::move(keyDown)), m_keyUpCallback(std::move(keyUp)) +{ +} + +PreviewKeyboardEventHandler::PreviewKeyboardEventHandler(KeyboardEventCallback&& keyDown, KeyboardEventCallback&& keyUp) + : KeyboardEventBaseHandler(std::move(keyDown), std::move(keyUp)) +{ +} + +void PreviewKeyboardEventHandler::hook(XamlView xamlView) +{ + auto uiElement = xamlView.as(); + if (m_keyDownCallback) + m_previewKeyDownRevoker = uiElement.PreviewKeyDown(winrt::auto_revoke, m_keyDownCallback); + + if (m_keyUpCallback) + m_previewKeyUpRevoker = uiElement.PreviewKeyUp(winrt::auto_revoke, m_keyUpCallback); +} + +void PreviewKeyboardEventHandler::unhook() +{ + m_previewKeyDownRevoker.revoke(); + m_previewKeyUpRevoker.revoke(); +} + +KeyboardEventHandler::KeyboardEventHandler(KeyboardEventCallback&& keyDown, KeyboardEventCallback&& keyUp) + :KeyboardEventBaseHandler(std::move(keyDown), std::move(keyUp)) +{ +} + +void KeyboardEventHandler::hook(XamlView xamlView) +{ + auto uiElement = xamlView.as(); + if (m_keyDownCallback) + m_keyDownRevoker = uiElement.KeyDown(winrt::auto_revoke, m_keyDownCallback); + + if (m_keyUpCallback) + m_keyUpRevoker = uiElement.KeyUp(winrt::auto_revoke, m_keyUpCallback); +} + +void KeyboardEventHandler::unhook() +{ + m_keyDownRevoker.revoke(); + m_keyUpRevoker.revoke(); +} + +PreviewKeyboardEventHandlerOnRoot::PreviewKeyboardEventHandlerOnRoot(const std::weak_ptr& reactInstance) + :PreviewKeyboardEventHandler( + std::bind(&PreviewKeyboardEventHandlerOnRoot::OnPreKeyDown, this, _1, _2), + std::bind(&PreviewKeyboardEventHandlerOnRoot::OnPreKeyUp, this, _1, _2)), + m_wkReactInstance(reactInstance) +{ +} + +void PreviewKeyboardEventHandlerOnRoot::OnPreKeyDown(winrt::IInspectable const& sender, winrt::KeyRoutedEventArgs const&args) +{ + DispatchEventToJs("topKeyDown", args); +} + +void PreviewKeyboardEventHandlerOnRoot::OnPreKeyUp(winrt::IInspectable const& sender, winrt::KeyRoutedEventArgs const&args) +{ + DispatchEventToJs("topKeyUp", args); +} + +HandledKeyboardEventHandler::HandledKeyboardEventHandler() +{ +} + +void HandledKeyboardEventHandler::UpdateHandledKeyboardEvents(std::string const& propertyName, folly::dynamic const& value) +{ + if (propertyName == "keyDownEvents") { + m_handledKeyDownKeyboardEvents = KeyboardHelper::FromJS(value); + } + else if (propertyName == "keyUpEvents") + m_handledKeyUpKeyboardEvents = KeyboardHelper::FromJS(value); +} + +void HandledKeyboardEventHandler::hook(XamlView xamlView) +{ + unhook(); + + EnsureKeyboardEventHandler(); + m_previewKeyboardEventHandler->hook(xamlView); + m_keyboardEventHandler->hook(xamlView); +} + +void HandledKeyboardEventHandler::unhook() +{ + if (m_previewKeyboardEventHandler) + m_previewKeyboardEventHandler->unhook(); + if (m_keyboardEventHandler) + m_keyboardEventHandler->unhook(); +} + +void HandledKeyboardEventHandler::EnsureKeyboardEventHandler() +{ + if (!m_previewKeyboardEventHandler) + { + m_previewKeyboardEventHandler = make_unique( + std::bind(&HandledKeyboardEventHandler::KeyboardEventHandledHandler, this, KeyboardEventPhase::PreviewKeyDown, _1, _2), + std::bind(&HandledKeyboardEventHandler::KeyboardEventHandledHandler, this, KeyboardEventPhase::PreviewKeyUp, _1, _2) + ); + } + + if (!m_keyboardEventHandler) + { + m_keyboardEventHandler = make_unique( + std::bind(&HandledKeyboardEventHandler::KeyboardEventHandledHandler, this, KeyboardEventPhase::KeyDown, _1, _2), + std::bind(&HandledKeyboardEventHandler::KeyboardEventHandledHandler, this, KeyboardEventPhase::KeyUp, _1, _2) + ); + } +} + +void HandledKeyboardEventHandler::KeyboardEventHandledHandler(KeyboardEventPhase phase, winrt::IInspectable const& sender, winrt::KeyRoutedEventArgs const& args) +{ + HandledEventPhase currentEventPhase = (phase == KeyboardEventPhase::PreviewKeyUp || phase == KeyboardEventPhase::PreviewKeyDown) + ? HandledEventPhase::Capturing : HandledEventPhase::Bubbling; + + auto event = KeyboardHelper::CreateKeyboardEvent(currentEventPhase, args); + + bool shouldMarkHandled = false; + if (phase == KeyboardEventPhase::PreviewKeyDown || phase == KeyboardEventPhase::KeyDown) + shouldMarkHandled = ShouldMarkKeyboardHandled(m_handledKeyDownKeyboardEvents, event); + else + shouldMarkHandled = ShouldMarkKeyboardHandled(m_handledKeyUpKeyboardEvents, event); + + if (shouldMarkHandled) + args.Handled(true); +} + +bool HandledKeyboardEventHandler::ShouldMarkKeyboardHandled(std::vector const& handledEvents, HandledKeyboardEvent currentEvent) +{ + for (auto const& event : handledEvents) + { + if (event.key == currentEvent.key && + (event.altKey == currentEvent.altKey) && + (event.ctrlKey == currentEvent.ctrlKey) && + (event.shiftKey == currentEvent.shiftKey) && + (event.metaKey == currentEvent.metaKey) && + event.handledEventPhase == currentEvent.handledEventPhase) + return true; + } + return false; +} + +inline bool IsModifiedKeyPressed(winrt::CoreWindow const& coreWindow, winrt::VirtualKey virtualKey) +{ + return (coreWindow.GetKeyState(virtualKey) & winrt::CoreVirtualKeyStates::Down) == winrt::CoreVirtualKeyStates::Down; +} + +inline bool IsModifiedKeyLocked(winrt::CoreWindow const& coreWindow, winrt::VirtualKey virtualKey) +{ + return (coreWindow.GetKeyState(virtualKey) & winrt::CoreVirtualKeyStates::Locked) == winrt::CoreVirtualKeyStates::Locked; +} + +template void UpdateModifiedKeyStatusTo(T& event) +{ + auto const& coreWindow = winrt::CoreWindow::GetForCurrentThread(); + event.altKey = IsModifiedKeyPressed(coreWindow, winrt::VirtualKey::Menu); + event.shiftKey = IsModifiedKeyPressed(coreWindow, winrt::VirtualKey::Shift); + event.metaKey = IsModifiedKeyPressed(coreWindow, winrt::VirtualKey::LeftWindows) + || IsModifiedKeyPressed(coreWindow, winrt::VirtualKey::RightWindows); + event.ctrlKey = IsModifiedKeyPressed(coreWindow, winrt::VirtualKey::Control); + event.capLocked = IsModifiedKeyLocked(coreWindow, winrt::VirtualKey::CapitalLock); +}; + +void PreviewKeyboardEventHandlerOnRoot::DispatchEventToJs(std::string const& eventName, winrt::KeyRoutedEventArgs const& args) +{ + if (auto instance = m_wkReactInstance.lock()) + { + if (auto source = args.OriginalSource().try_as()) + { + auto reactId = getViewId(instance.operator->(), source); + if (reactId.isValid) + { + ReactKeyboardEvent event; + event.target = reactId.tag; + UpdateModifiedKeyStatusTo(event); + event.key = KeyboardHelper::FromVirtualKey(args.Key(), event.shiftKey, event.capLocked); + instance->DispatchEvent(event.target, eventName, ToEventData(event)); + } + } + } +} + +HandledKeyboardEvent KeyboardHelper::CreateKeyboardEvent(HandledEventPhase phase, winrt::KeyRoutedEventArgs const& args) +{ + HandledKeyboardEvent event; + event.handledEventPhase = phase; + UpdateModifiedKeyStatusTo(event); + event.key = KeyboardHelper::FromVirtualKey(args.Key(), event.shiftKey, event.capLocked); + + return event; +} + +// Should align to https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values +static const std::vector> g_virtualKeyToString +{ + // Modifier keys + {winrt::VirtualKey::LeftMenu, "Alt"}, + {winrt::VirtualKey::RightMenu, "Alt"}, + {winrt::VirtualKey::Menu, "Alt"}, + {winrt::VirtualKey::CapitalLock, "CapsLock"}, + {winrt::VirtualKey::LeftControl, "Control"}, + {winrt::VirtualKey::RightControl, "Control"}, + {winrt::VirtualKey::Control, "Control"}, + {winrt::VirtualKey::LeftWindows, "Meta"}, + {winrt::VirtualKey::RightWindows, "Meta"}, + {winrt::VirtualKey::NumberKeyLock, "NumLock"}, + {winrt::VirtualKey::Scroll, "ScrollLock"}, + {winrt::VirtualKey::LeftShift, "Shift"}, + {winrt::VirtualKey::RightShift, "Shift"}, + {winrt::VirtualKey::Shift, "Shift"}, + + //Whitespace keys + {winrt::VirtualKey::Enter, "Enter"}, + {winrt::VirtualKey::Tab, "Tab"}, + {winrt::VirtualKey::Space, " "}, + + //Navigation keys + {winrt::VirtualKey::Down, "ArrowDown"}, + {winrt::VirtualKey::Left, "ArrowLeft"}, + {winrt::VirtualKey::Right, "ArrowRight"}, + {winrt::VirtualKey::Up, "ArrowUp"}, + {winrt::VirtualKey::End, "End"}, + {winrt::VirtualKey::Home, "Home"}, + {winrt::VirtualKey::PageDown, "PageDown"}, + {winrt::VirtualKey::PageUp, "PageUp"}, + + //Editing keys + {winrt::VirtualKey::Back, "Backspace"}, + {winrt::VirtualKey::Clear, "Clear"}, + {winrt::VirtualKey::Delete, "Delete"}, + {winrt::VirtualKey::Insert, "Insert"}, + + //UI keys + {winrt::VirtualKey::Accept, "Accept"}, + {winrt::VirtualKey::Application, "ContextMenu"}, + {winrt::VirtualKey::Escape, "Escape"}, + {winrt::VirtualKey::Execute, "Execute"}, + {winrt::VirtualKey::Help, "Help"}, + {winrt::VirtualKey::Pause, "Pause"}, + {winrt::VirtualKey::Select, "Select"}, + + //Device keys + {winrt::VirtualKey::Snapshot, "PrintScreen"}, + {winrt::VirtualKey::Sleep, "Standby"}, + + //Common IME keys + {winrt::VirtualKey::Convert, "Convert"}, + {winrt::VirtualKey::Final, "FinalMode"}, + {winrt::VirtualKey::ModeChange, "ModeChange"}, + {winrt::VirtualKey::NonConvert, "NonConvert"}, + + //Korean keyboards only + {winrt::VirtualKey::Hangul, "HangulMode"}, + {winrt::VirtualKey::Hanja, "HanjaMode"}, + {winrt::VirtualKey::Junja, "JunjaMode"}, + + //Japanese keyboards only + {winrt::VirtualKey::Kana, "KanaMode"}, + {winrt::VirtualKey::Kanji, "KanjiMode"}, + + //Function keys + {winrt::VirtualKey::F1, "F1"}, + {winrt::VirtualKey::F2, "F2"}, + {winrt::VirtualKey::F3, "F3"}, + {winrt::VirtualKey::F4, "F4"}, + {winrt::VirtualKey::F5, "F5"}, + {winrt::VirtualKey::F6, "F6"}, + {winrt::VirtualKey::F7, "F7"}, + {winrt::VirtualKey::F8, "F8"}, + {winrt::VirtualKey::F9, "F9"}, + {winrt::VirtualKey::F10, "F10"}, + {winrt::VirtualKey::F11, "F11"}, + {winrt::VirtualKey::F12, "F12"}, + {winrt::VirtualKey::F13, "F13"}, + {winrt::VirtualKey::F14, "F14"}, + {winrt::VirtualKey::F15, "F15"}, + {winrt::VirtualKey::F16, "F16"}, + {winrt::VirtualKey::F17, "F17"}, + {winrt::VirtualKey::F18, "F18"}, + {winrt::VirtualKey::F19, "F19"}, + {winrt::VirtualKey::F20, "F20"}, + + //Numeric keypad keys + {winrt::VirtualKey::Decimal, "Decimal"}, + {winrt::VirtualKey::Multiply, "Multiply"}, + {winrt::VirtualKey::Add, "Add"}, + {winrt::VirtualKey::Divide, "Divide"}, + {winrt::VirtualKey::Subtract, "Subtract"}, + {winrt::VirtualKey::Separator, "Separator"}, + + {winrt::VirtualKey::Number0, "0"}, + {winrt::VirtualKey::Number1, "1"}, + {winrt::VirtualKey::Number2, "2"}, + {winrt::VirtualKey::Number3, "3"}, + {winrt::VirtualKey::Number4, "4"}, + {winrt::VirtualKey::Number5, "5"}, + {winrt::VirtualKey::Number6, "6"}, + {winrt::VirtualKey::Number7, "7"}, + {winrt::VirtualKey::Number8, "8"}, + {winrt::VirtualKey::Number9, "9"}, + // +}; + +std::string KeyboardHelper::FromVirtualKey(winrt::VirtualKey virtualKey, bool shiftDown, bool capLocked) +{ + char key = static_cast(virtualKey); + + if (!isalnum(key)) + { + for (auto const& pair : g_virtualKeyToString) + { + if (pair.first == virtualKey) + return pair.second; + } + return "Unidentified"; + } + + // Customer never receives a-z + // https://docs.microsoft.com/en-us/uwp/api/windows.system.virtualkey + // Virtual Keys for 0-9 and A-Z, they're just aligned to their ASCII representation (in uppercase, for the alphabet VKs) + return std::string(1, key); +} + +}} diff --git a/vnext/ReactUWP/Views/PickerViewManager.cpp b/vnext/ReactUWP/Views/PickerViewManager.cpp index 3653cf149d2..ccb7b48551b 100644 --- a/vnext/ReactUWP/Views/PickerViewManager.cpp +++ b/vnext/ReactUWP/Views/PickerViewManager.cpp @@ -15,6 +15,7 @@ #include #include +#include namespace winrt { using namespace Windows::UI::Xaml; @@ -23,11 +24,6 @@ namespace winrt { namespace react { namespace uwp { -enum class PickerCommands -{ - SetFocus = 1, -}; - class PickerShadowNode : public ShadowNodeBase { using Super = ShadowNodeBase; @@ -95,6 +91,9 @@ void PickerShadowNode::updateProperties(const folly::dynamic&& props) bool updateSelectedIndex = false; auto combobox = GetView().as(); + + auto comboboxXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(combobox); + for (auto& pair : props.items()) { const std::string& propertyName = pair.first.getString(); @@ -105,9 +104,16 @@ void PickerShadowNode::updateProperties(const folly::dynamic&& props) if (m_isEditableComboboxSupported) { if (propertyValue.isBool()) - combobox.IsEditable(propertyValue.asBool()); + XamlDirectInstance::GetXamlDirect().SetBooleanProperty( + comboboxXD, + XD::XamlPropertyIndex::ComboBox_IsEditable, + propertyValue.asBool() + ); else if (propertyValue.isNull()) - combobox.ClearValue(winrt::ComboBox::IsEditableProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + comboboxXD, + XD::XamlPropertyIndex::ComboBox_IsEditable + ); } } else if (propertyName == "text") @@ -115,15 +121,26 @@ void PickerShadowNode::updateProperties(const folly::dynamic&& props) if (m_isEditableComboboxSupported) { if (propertyValue.isString()) - combobox.Text(asHstring(propertyValue)); + XamlDirectInstance::GetXamlDirect().SetStringProperty( + comboboxXD, + XD::XamlPropertyIndex::ComboBox_Text, + asHstring(propertyValue) + ); else if (propertyValue.isNull()) - combobox.ClearValue(winrt::ComboBox::TextProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + comboboxXD, + XD::XamlPropertyIndex::ComboBox_Text + ); } } else if (propertyName == "enabled") { if (propertyValue.isBool()) - combobox.IsEnabled(propertyValue.asBool()); + XamlDirectInstance::GetXamlDirect().SetBooleanProperty( + comboboxXD, + XD::XamlPropertyIndex::Control_IsEnabled, + propertyValue.asBool() + ); } else if (propertyName == "selectedIndex") { @@ -149,7 +166,11 @@ void PickerShadowNode::updateProperties(const folly::dynamic&& props) // Update selectedIndex last, in case items and selectedIndex were both changing if (updateSelectedIndex) - combobox.SelectedIndex(m_selectedIndex); + XamlDirectInstance::GetXamlDirect().SetInt32Property( + comboboxXD, + XD::XamlPropertyIndex::Selector_SelectedIndex, + m_selectedIndex + ); Super::updateProperties(std::move(props)); m_updating = false; @@ -159,23 +180,48 @@ void PickerShadowNode::RepopulateItems() { auto combobox = GetView().as(); - auto comboBoxItems = combobox.Items(); - comboBoxItems.Clear(); + auto comboboxXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(combobox); + auto comboboxItemsXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObjectProperty( + comboboxXD, + XD::XamlPropertyIndex::ItemsControl_Items + ); + XamlDirectInstance::GetXamlDirect().ClearCollection(comboboxItemsXD); + for (const auto& item : m_items) { if (item.count("label")) { std::string label = item["label"].asString(); - auto comboboxItem = winrt::ComboBoxItem(); - comboboxItem.Content(winrt::box_value(facebook::react::unicode::utf8ToUtf16(label))); + + auto comboboxItem = XamlDirectInstance::GetXamlDirect().CreateInstance(XD::XamlTypeIndex::ComboBoxItem); + + XamlDirectInstance::GetXamlDirect().SetStringProperty( + comboboxItem, + XD::XamlPropertyIndex::ContentControl_Content, + facebook::react::unicode::utf8ToUtf16(label) + ); if (item.count("textColor")) - comboboxItem.Foreground(BrushFrom(item["textColor"])); - comboBoxItems.Append(comboboxItem); + { + const auto propertyValueXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(BrushFrom(item["textColor"])); + XamlDirectInstance::GetXamlDirect().SetXamlDirectObjectProperty( + comboboxItem, + XD::XamlPropertyIndex::Control_Foreground, + propertyValueXD + ); + } + auto items = XamlDirectInstance::GetXamlDirect().GetObject(comboboxItemsXD).as(); + items.Append(XamlDirectInstance::GetXamlDirect().GetObject(comboboxItem).as()); + // out of bounds error when adding to collection, otherwise use code below instead of 2 lines above + //XamlDirectInstance::GetXamlDirect().AddToCollection(comboboxItemsXD, comboboxItem); } m_hasNewItems = true; } if (m_selectedIndex < static_cast(m_items.size())) - combobox.SelectedIndex(m_selectedIndex); + XamlDirectInstance::GetXamlDirect().SetInt32Property( + comboboxXD, + XD::XamlPropertyIndex::Selector_SelectedIndex, + m_selectedIndex + ); } /*static*/ void PickerShadowNode::OnSelectionChanged(IReactInstance& instance, int64_t tag, folly::dynamic&& value, int32_t selectedIndex, folly::dynamic&& text) @@ -198,15 +244,6 @@ const char* PickerViewManager::GetName() const return "RCTPicker"; } -folly::dynamic PickerViewManager::GetCommands() const -{ - auto commands = Super::GetCommands(); - commands.update(folly::dynamic::object - ("SetFocus", static_cast>(PickerCommands::SetFocus)) - ); - return commands; -} - folly::dynamic PickerViewManager::GetNativeProps() const { auto props = Super::GetNativeProps(); @@ -233,22 +270,6 @@ XamlView PickerViewManager::CreateViewCore(int64_t tag) return combobox; } -void PickerViewManager::DispatchCommand(XamlView viewToUpdate, int64_t commandId, const folly::dynamic& commandArgs) -{ - auto combobox = viewToUpdate.as(); - if (combobox == nullptr) - return; - - switch (static_cast(commandId)) - { - case PickerCommands::SetFocus: - { - combobox.Focus(winrt::FocusState::Programmatic); - break; - } - } -} - YGMeasureFunc PickerViewManager::GetYogaCustomMeasureFunc() const { return DefaultYogaSelfMeasureFunc; diff --git a/vnext/ReactUWP/Views/PickerViewManager.h b/vnext/ReactUWP/Views/PickerViewManager.h index 5b0375e87cd..3c3e658054e 100644 --- a/vnext/ReactUWP/Views/PickerViewManager.h +++ b/vnext/ReactUWP/Views/PickerViewManager.h @@ -14,13 +14,10 @@ class PickerViewManager : public ControlViewManager PickerViewManager(const std::shared_ptr& reactInstance); const char* GetName() const override; - folly::dynamic GetCommands() const override; folly::dynamic GetNativeProps() const override; facebook::react::ShadowNode* createShadow() const override; - void DispatchCommand(XamlView viewToUpdate, int64_t commandId, const folly::dynamic& commandArgs) override; - YGMeasureFunc GetYogaCustomMeasureFunc() const override; protected: diff --git a/vnext/ReactUWP/Views/PopupViewManager.cpp b/vnext/ReactUWP/Views/PopupViewManager.cpp index b90352006f2..45189864c35 100644 --- a/vnext/ReactUWP/Views/PopupViewManager.cpp +++ b/vnext/ReactUWP/Views/PopupViewManager.cpp @@ -16,6 +16,8 @@ #include #include +#include + namespace winrt { using namespace Windows::Foundation; using namespace Windows::UI::Core; @@ -40,13 +42,16 @@ class PopupShadowNode : public ShadowNodeBase winrt::Windows::Foundation::Size GetAppWindowSize(); private: - std::shared_ptr m_touchEventHanadler; + std::unique_ptr m_touchEventHanadler; + std::unique_ptr m_previewKeyboardEventHandlerOnRoot; + int64_t m_targetTag; }; PopupShadowNode::~PopupShadowNode() { m_touchEventHanadler->RemoveTouchHandlers(); + m_previewKeyboardEventHandlerOnRoot->unhook(); } void PopupShadowNode::createView() @@ -55,7 +60,8 @@ void PopupShadowNode::createView() auto popup = GetView().as(); auto wkinstance = GetViewManager()->GetReactInstance(); - m_touchEventHanadler = std::make_shared(wkinstance); + m_touchEventHanadler = std::make_unique(wkinstance); + m_previewKeyboardEventHandlerOnRoot = std::make_unique(wkinstance); popup.Closed([=](auto&&, auto&&) { @@ -78,6 +84,7 @@ void PopupShadowNode::AddView(ShadowNode& child, int64_t index) auto childView = static_cast(child).GetView(); m_touchEventHanadler->AddTouchHandlers(childView); + m_previewKeyboardEventHandlerOnRoot->hook(childView); } void PopupShadowNode::updateProperties(const folly::dynamic&& props) @@ -88,6 +95,8 @@ void PopupShadowNode::updateProperties(const folly::dynamic&& props) if (popup == nullptr) return; + auto popupXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(popup); + for (auto& pair : props.items()) { const std::string& propertyName = pair.first.getString(); @@ -103,30 +112,58 @@ void PopupShadowNode::updateProperties(const folly::dynamic&& props) else if (propertyName == "isOpen") { if (propertyValue.isBool()) - popup.IsOpen(propertyValue.getBool()); + XamlDirectInstance::GetXamlDirect().SetBooleanProperty( + popupXD, + XD::XamlPropertyIndex::Popup_IsOpen, + propertyValue.getBool() + ); else if (propertyValue.isNull()) - popup.ClearValue(winrt::Popup::IsOpenProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + popupXD, + XD::XamlPropertyIndex::Popup_IsOpen + ); } else if (propertyName == "isLightDismissEnabled") { if (propertyValue.isBool()) - popup.IsLightDismissEnabled(propertyValue.getBool()); + XamlDirectInstance::GetXamlDirect().SetBooleanProperty( + popupXD, + XD::XamlPropertyIndex::Popup_IsLightDismissEnabled, + propertyValue.getBool() + ); else if (propertyValue.isNull()) - popup.ClearValue(winrt::Popup::IsLightDismissEnabledProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + popupXD, + XD::XamlPropertyIndex::Popup_IsLightDismissEnabled + ); } else if (propertyName == "horizontalOffset") { if (propertyValue.isNumber()) - popup.HorizontalOffset(propertyValue.asDouble()); + XamlDirectInstance::GetXamlDirect().SetDoubleProperty( + popupXD, + XD::XamlPropertyIndex::Popup_HorizontalOffset, + propertyValue.asDouble() + ); else if (propertyValue.isNull()) - popup.ClearValue(winrt::Popup::HorizontalOffsetProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + popupXD, + XD::XamlPropertyIndex::Popup_HorizontalOffset + ); } else if (propertyName == "verticalOffset") { if (propertyValue.isNumber()) - popup.VerticalOffset(propertyValue.asDouble()); + XamlDirectInstance::GetXamlDirect().SetDoubleProperty( + popupXD, + XD::XamlPropertyIndex::Popup_VerticalOffset, + propertyValue.asDouble() + ); else if (propertyValue.isNull()) - popup.ClearValue(winrt::Popup::VerticalOffsetProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + popupXD, + XD::XamlPropertyIndex::Popup_VerticalOffset + ); } } diff --git a/vnext/ReactUWP/Views/RawTextViewManager.cpp b/vnext/ReactUWP/Views/RawTextViewManager.cpp index 03a8598161f..0cabe682848 100644 --- a/vnext/ReactUWP/Views/RawTextViewManager.cpp +++ b/vnext/ReactUWP/Views/RawTextViewManager.cpp @@ -13,6 +13,8 @@ #include #include +#include + namespace winrt { using namespace Windows::Foundation; using namespace Windows::UI; @@ -46,6 +48,8 @@ void RawTextViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const fo if (run == nullptr) return; + auto runXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(run); + for (const auto& pair : reactDiffMap.items()) { const std::string& propertyName = pair.first.getString(); @@ -53,7 +57,11 @@ void RawTextViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const fo if (propertyName == "text") { - run.Text(asHstring(propertyValue)); + XamlDirectInstance::GetXamlDirect().SetStringProperty( + runXD, + XD::XamlPropertyIndex::Run_Text, + asHstring(propertyValue) + ); } } Super::UpdateProperties(nodeToUpdate, reactDiffMap); diff --git a/vnext/ReactUWP/Views/ReactControl.cpp b/vnext/ReactUWP/Views/ReactControl.cpp index 37056d18fff..d093caf77c1 100644 --- a/vnext/ReactUWP/Views/ReactControl.cpp +++ b/vnext/ReactUWP/Views/ReactControl.cpp @@ -22,6 +22,8 @@ #include #include +#include + namespace react { namespace uwp { @@ -102,6 +104,8 @@ void ReactControl::AttachRoot() noexcept if (!m_touchEventHandler) m_touchEventHandler = std::make_shared(m_reactInstance); + m_previewKeyboardEventHandlerOnRoot = std::make_shared(m_reactInstance); + // Register callback from instance for live reload m_errorCallbackCookie = m_reactInstance->RegisterErrorCallback([this]() { @@ -128,6 +132,8 @@ void ReactControl::AttachRoot() noexcept #endif m_touchEventHandler->AddTouchHandlers(m_xamlRootView); + m_previewKeyboardEventHandlerOnRoot->hook(m_xamlRootView); + auto initialProps = m_initialProps; m_reactInstance->AttachMeasuredRootView(m_pParent, std::move(initialProps)); @@ -144,6 +150,9 @@ void ReactControl::DetachRoot() noexcept m_touchEventHandler->RemoveTouchHandlers(); } + if (!m_previewKeyboardEventHandlerOnRoot) + m_previewKeyboardEventHandlerOnRoot->unhook(); + if (m_reactInstance != nullptr) { m_reactInstance->DetachRootView(m_pParent); @@ -153,7 +162,14 @@ void ReactControl::DetachRoot() noexcept { auto grid(m_xamlRootView.as()); if (grid != nullptr) - grid.Children().Clear(); + { + auto gridXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(grid); + auto gridChildrenXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObjectProperty( + gridXD, + XD::XamlPropertyIndex::Panel_Children + ); + XamlDirectInstance::GetXamlDirect().ClearCollection(gridChildrenXD); + } m_redBoxGrid = nullptr; m_errorTextBlock = nullptr; @@ -237,7 +253,12 @@ int64_t ReactControl::GetActualHeight() const auto element = m_xamlRootView.as(); assert(element != nullptr); - return static_cast(element.ActualHeight()); + auto elementXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(element); + auto actualHeight = XamlDirectInstance::GetXamlDirect().GetDoubleProperty( + elementXD, + XD::XamlPropertyIndex::FrameworkElement_ActualHeight + ); + return static_cast(actualHeight); } int64_t ReactControl::GetActualWidth() const @@ -245,7 +266,12 @@ int64_t ReactControl::GetActualWidth() const auto element = m_xamlRootView.as(); assert(element != nullptr); - return static_cast(element.ActualWidth()); + auto elementXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(element); + auto actualWidth = XamlDirectInstance::GetXamlDirect().GetDoubleProperty( + elementXD, + XD::XamlPropertyIndex::FrameworkElement_ActualWidth + ); + return static_cast(actualWidth); } } diff --git a/vnext/ReactUWP/Views/ReactControl.h b/vnext/ReactUWP/Views/ReactControl.h index 6af259e204b..d3f41c49475 100644 --- a/vnext/ReactUWP/Views/ReactControl.h +++ b/vnext/ReactUWP/Views/ReactControl.h @@ -9,7 +9,7 @@ #include "IXamlRootView.h" #include #include "TouchEventHandler.h" -#include +#include "Views/KeyboardEventHandler.h" namespace winrt { using namespace Windows::UI; @@ -62,6 +62,7 @@ class ReactControl : public std::enable_shared_from_this std::shared_ptr m_moduleProvider; folly::dynamic m_initialProps; std::shared_ptr m_touchEventHandler; + std::shared_ptr m_previewKeyboardEventHandlerOnRoot; int64_t m_rootTag = -1; XamlView m_xamlRootView; diff --git a/vnext/ReactUWP/Views/RootViewManager.cpp b/vnext/ReactUWP/Views/RootViewManager.cpp index 949781b316a..6c92ae7e2f2 100644 --- a/vnext/ReactUWP/Views/RootViewManager.cpp +++ b/vnext/ReactUWP/Views/RootViewManager.cpp @@ -9,6 +9,8 @@ #include +#include + namespace winrt { using namespace Windows::UI; using namespace Windows::UI::Xaml; @@ -38,21 +40,52 @@ void RootViewManager::AddView(XamlView parent, XamlView child, int64_t index) { auto panel(parent.as()); if (panel != nullptr) - panel.Children().InsertAt(static_cast(index), child.as()); + { + auto panelXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(panel); + + auto panelChildrenXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObjectProperty( + panelXD, + XD::XamlPropertyIndex::Panel_Children + ); + auto childXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(child.as()); + XamlDirectInstance::GetXamlDirect().InsertIntoCollectionAt( + panelChildrenXD, + static_cast(index), + childXD + ); + } } void RootViewManager::RemoveAllChildren(XamlView parent) { auto panel(parent.as()); if (panel != nullptr) - panel.Children().Clear(); + { + auto panelXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(panel); + auto panelChildrenXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObjectProperty( + panelXD, + XD::XamlPropertyIndex::Panel_Children + ); + XamlDirectInstance::GetXamlDirect().ClearCollection(panelChildrenXD); + } } void RootViewManager::RemoveChildAt(XamlView parent, int64_t index) { auto panel(parent.as()); if (panel != nullptr) - panel.Children().RemoveAt(static_cast(index)); + { + auto panelXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(panel); + + auto panelChildrenXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObjectProperty( + panelXD, + XD::XamlPropertyIndex::Panel_Children + ); + XamlDirectInstance::GetXamlDirect().RemoveFromCollectionAt( + panelChildrenXD, + static_cast(index) + ); + } } void RootViewManager::SetLayoutProps(ShadowNodeBase& /*nodeToUpdate*/, XamlView /*nodeToUpdate*/, float /*left*/, float /*top*/, float /*width*/, float /*height*/) diff --git a/vnext/ReactUWP/Views/ScrollViewManager.cpp b/vnext/ReactUWP/Views/ScrollViewManager.cpp index a0a5ae6de08..ed5bf7d5369 100644 --- a/vnext/ReactUWP/Views/ScrollViewManager.cpp +++ b/vnext/ReactUWP/Views/ScrollViewManager.cpp @@ -32,7 +32,7 @@ class ScrollViewShadowNode : public ShadowNodeBase const char* eventName, double x, double y, double zoom); template std::tuple getPropertyAndValidity(folly::dynamic propertyValue, T defaultValue); - void SetScrollMode(const winrt::ScrollViewer& scrollViewer); + void SetScrollMode(const XD::IXamlDirectObject& scrollViewerXD); float m_zoomFactor{ 1.0f }; bool m_isScrollingFromInertia = false; @@ -124,6 +124,8 @@ void ScrollViewShadowNode::updateProperties(const folly::dynamic&& reactDiffMap) if (scrollViewer == nullptr) return; + auto scrollViewerXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(scrollViewer); + for (const auto& pair : reactDiffMap.items()) { const std::string& propertyName = pair.first.getString(); @@ -136,7 +138,7 @@ void ScrollViewShadowNode::updateProperties(const folly::dynamic&& reactDiffMap) { m_isHorizontal = horizontal; ScrollViewUWPImplementation(scrollViewer).SetHorizontal(horizontal); - SetScrollMode(scrollViewer); + SetScrollMode(scrollViewerXD); } } if (propertyName == "scrollEnabled") @@ -145,7 +147,7 @@ void ScrollViewShadowNode::updateProperties(const folly::dynamic&& reactDiffMap) if (valid) { m_isScrollingEnabled = scrollEnabled; - SetScrollMode(scrollViewer); + SetScrollMode(scrollViewerXD); } } else if (propertyName == "showsHorizontalScrollIndicator") @@ -153,7 +155,11 @@ void ScrollViewShadowNode::updateProperties(const folly::dynamic&& reactDiffMap) const auto [valid, showsHorizontalScrollIndicator] = getPropertyAndValidity(propertyValue, true); if (valid) { - scrollViewer.HorizontalScrollBarVisibility(showsHorizontalScrollIndicator ? winrt::ScrollBarVisibility::Visible : winrt::ScrollBarVisibility::Hidden); + XamlDirectInstance::GetXamlDirect().SetBooleanProperty( + scrollViewerXD, + XD::XamlPropertyIndex::ScrollViewer_HorizontalScrollBarVisibility, + static_cast(showsHorizontalScrollIndicator ? winrt::ScrollBarVisibility::Visible : winrt::ScrollBarVisibility::Hidden) + ); } } else if (propertyName == "showsVerticalScrollIndicator") @@ -161,7 +167,11 @@ void ScrollViewShadowNode::updateProperties(const folly::dynamic&& reactDiffMap) const auto [valid, showsVerticalScrollIndicator] = getPropertyAndValidity(propertyValue, true); if (valid) { - scrollViewer.VerticalScrollBarVisibility(showsVerticalScrollIndicator ? winrt::ScrollBarVisibility::Visible : winrt::ScrollBarVisibility::Hidden); + XamlDirectInstance::GetXamlDirect().SetBooleanProperty( + scrollViewerXD, + XD::XamlPropertyIndex::ScrollViewer_VerticalScrollBarVisibility, + static_cast(showsVerticalScrollIndicator ? winrt::ScrollBarVisibility::Visible : winrt::ScrollBarVisibility::Hidden) + ); } } else if (propertyName == "minimumZoomScale") @@ -169,7 +179,11 @@ void ScrollViewShadowNode::updateProperties(const folly::dynamic&& reactDiffMap) const auto [valid, minimumZoomScale] = getPropertyAndValidity(propertyValue, 1.0); if (valid) { - scrollViewer.MinZoomFactor(static_cast(minimumZoomScale)); + XamlDirectInstance::GetXamlDirect().SetDoubleProperty( + scrollViewerXD, + XD::XamlPropertyIndex::ScrollViewer_MinZoomFactor, + static_cast(minimumZoomScale) + ); } } else if (propertyName == "maximumZoomScale") @@ -177,7 +191,11 @@ void ScrollViewShadowNode::updateProperties(const folly::dynamic&& reactDiffMap) const auto [valid, maximumZoomScale] = getPropertyAndValidity(propertyValue, 1.0); if (valid) { - scrollViewer.MaxZoomFactor(static_cast(maximumZoomScale)); + XamlDirectInstance::GetXamlDirect().SetDoubleProperty( + scrollViewerXD, + XD::XamlPropertyIndex::ScrollViewer_MaxZoomFactor, + static_cast(maximumZoomScale) + ); } } else if (propertyName == "zoomScale") @@ -209,8 +227,17 @@ void ScrollViewShadowNode::updateProperties(const folly::dynamic&& reactDiffMap) const auto [valid, snapToAlignment] = getPropertyAndValidity(propertyValue, winrt::SnapPointsAlignment::Near); if (valid) { - scrollViewer.HorizontalSnapPointsAlignment(snapToAlignment); - scrollViewer.VerticalSnapPointsAlignment(snapToAlignment); + const auto snapToAlignmentInt32 = static_cast(snapToAlignment); + XamlDirectInstance::GetXamlDirect().SetEnumProperty( + scrollViewerXD, + XD::XamlPropertyIndex::ScrollViewer_HorizontalSnapPointsAlignment, + snapToAlignmentInt32 + ); + XamlDirectInstance::GetXamlDirect().SetEnumProperty( + scrollViewerXD, + XD::XamlPropertyIndex::ScrollViewer_VerticalSnapPointsAlignment, + snapToAlignmentInt32 + ); } } } @@ -427,12 +454,21 @@ std::tuple ScrollViewShadowNode::getPropertyAndValidity(folly::dynamic return std::make_tuple(false, defaultValue); } -void ScrollViewShadowNode::SetScrollMode(const winrt::ScrollViewer& scrollViewer) +void ScrollViewShadowNode::SetScrollMode(const XD::IXamlDirectObject& scrollViewerXD) { const auto horizontalScrollingEnabled = m_isScrollingEnabled && m_isHorizontal; const auto verticalScrollingEnabled = m_isScrollingEnabled && !m_isHorizontal; - scrollViewer.HorizontalScrollMode(horizontalScrollingEnabled ? winrt::ScrollMode::Auto : winrt::ScrollMode::Disabled); - scrollViewer.VerticalScrollMode(verticalScrollingEnabled ? winrt::ScrollMode::Auto : winrt::ScrollMode::Disabled); + + XamlDirectInstance::GetXamlDirect().SetEnumProperty( + scrollViewerXD, + XD::XamlPropertyIndex::ScrollViewer_HorizontalScrollMode, + static_cast(horizontalScrollingEnabled ? winrt::ScrollMode::Auto : winrt::ScrollMode::Disabled) + ); + XamlDirectInstance::GetXamlDirect().SetEnumProperty( + scrollViewerXD, + XD::XamlPropertyIndex::ScrollViewer_VerticalScrollMode, + static_cast(verticalScrollingEnabled ? winrt::ScrollMode::Auto : winrt::ScrollMode::Disabled) + ); } ScrollViewManager::ScrollViewManager(const std::shared_ptr& reactInstance) diff --git a/vnext/ReactUWP/Views/ShadowNodeBase.cpp b/vnext/ReactUWP/Views/ShadowNodeBase.cpp index dc240d72fee..4c1cef9a7b7 100644 --- a/vnext/ReactUWP/Views/ShadowNodeBase.cpp +++ b/vnext/ReactUWP/Views/ShadowNodeBase.cpp @@ -9,9 +9,12 @@ #include #include #include +#include "Views/KeyboardEventHandler.h" #include #include +using namespace std::placeholders; + namespace react { namespace uwp { ShadowNodeBase::ShadowNodeBase() @@ -56,13 +59,21 @@ void ShadowNodeBase::RemoveChildAt(int64_t indexToRemove) void ShadowNodeBase::onDropViewInstance() { + m_handledKeyboardEventHandler = nullptr; } void ShadowNodeBase::ReplaceView(XamlView view) { + SetTag(view, GetTag(m_view)); m_view = view; + + if (m_handledKeyboardEventHandler) + { + m_handledKeyboardEventHandler->unhook(); + m_handledKeyboardEventHandler->hook(view); + } } void ShadowNodeBase::ReplaceChild(XamlView oldChildView, XamlView newChildView) @@ -112,4 +123,20 @@ void ShadowNodeBase::UpdateTransformPS() } } +void ShadowNodeBase::UpdateHandledKeyboardEvents(std::string const& propertyName, folly::dynamic const& value) +{ + EnsureHandledKeyboardEventHandler(); + m_handledKeyboardEventHandler->UpdateHandledKeyboardEvents(propertyName, value); +} + +void ShadowNodeBase::EnsureHandledKeyboardEventHandler() +{ + if (!m_handledKeyboardEventHandler) + { + assert(m_view); + m_handledKeyboardEventHandler = std::make_unique(); + m_handledKeyboardEventHandler->hook(m_view); + } +} + }} diff --git a/vnext/ReactUWP/Views/SwitchViewManager.cpp b/vnext/ReactUWP/Views/SwitchViewManager.cpp index cef42ef61a6..e137656c6b9 100644 --- a/vnext/ReactUWP/Views/SwitchViewManager.cpp +++ b/vnext/ReactUWP/Views/SwitchViewManager.cpp @@ -10,6 +10,8 @@ #include +#include + namespace winrt { using namespace Windows::UI::Xaml; using namespace Windows::UI::Xaml::Controls; @@ -98,6 +100,8 @@ void SwitchViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const fol if (toggleSwitch == nullptr) return; + auto toggleSwitchXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(toggleSwitch); + for (const auto& pair : reactDiffMap.items()) { const std::string& propertyName = pair.first.getString(); @@ -106,16 +110,30 @@ void SwitchViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const fol if (propertyName == "disabled") { if (propertyValue.isBool()) - toggleSwitch.IsEnabled(!propertyValue.asBool()); + XamlDirectInstance::GetXamlDirect().SetBooleanProperty( + toggleSwitchXD, + XD::XamlPropertyIndex::Control_IsEnabled, + !propertyValue.asBool() + ); else if (pair.second.isNull()) - toggleSwitch.ClearValue(winrt::Control::IsEnabledProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + toggleSwitchXD, + XD::XamlPropertyIndex::Control_IsEnabled + ); } else if (propertyName == "value") { if (propertyValue.isBool()) - toggleSwitch.IsOn(propertyValue.asBool()); + XamlDirectInstance::GetXamlDirect().SetBooleanProperty( + toggleSwitchXD, + XD::XamlPropertyIndex::ToggleSwitch_IsOn, + propertyValue.asBool() + ); else if (pair.second.isNull()) - toggleSwitch.ClearValue(winrt::ToggleSwitch::IsOnProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + toggleSwitchXD, + XD::XamlPropertyIndex::ToggleSwitch_IsOn + ); } } diff --git a/vnext/ReactUWP/Views/TextInputViewManager.cpp b/vnext/ReactUWP/Views/TextInputViewManager.cpp index 492dc07cc1d..a1d3c818aa1 100644 --- a/vnext/ReactUWP/Views/TextInputViewManager.cpp +++ b/vnext/ReactUWP/Views/TextInputViewManager.cpp @@ -18,6 +18,8 @@ #include #include +#include + namespace winrt { using namespace Windows::Foundation; using namespace Windows::UI::Xaml; @@ -94,12 +96,6 @@ class TextInputShadowNode : public ShadowNodeBase uint32_t m_mostRecentEventCount{ 0 }; // EventCount from javascript }; -enum class TextInputCommands -{ - SetFocus = 1, - Blur = 2, -}; - void TextInputShadowNode::createView() { Super::createView(); @@ -220,36 +216,67 @@ void TextInputShadowNode::updateProperties(const folly::dynamic&& props) return; auto control = textBox.as(); + + auto textBoxXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(textBox); + auto controlXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(control); + for (auto& pair : props.items()) { const std::string& propertyName = pair.first.getString(); const folly::dynamic& propertyValue = pair.second; - if (TryUpdateFontProperties(control, propertyName, propertyValue)) + auto fontPropIdx = XD::XamlPropertyIndex::Control_FontSize; + if (propertyName == "fontFamily") + { + fontPropIdx = XD::XamlPropertyIndex::Control_FontFamily; + } + else if (propertyName == "fontWeight") + { + fontPropIdx = XD::XamlPropertyIndex::Control_FontWeight; + } + else if (propertyName == "fontStyle") + { + fontPropIdx = XD::XamlPropertyIndex::Control_FontStyle; + } + + if (TryUpdateFontProperties(controlXD, propertyName, propertyValue, fontPropIdx)) { continue; } - else if (TryUpdateTextAlignment(textBox, propertyName, propertyValue)) + else if (TryUpdateTextAlignment(controlXD, propertyName, propertyValue, XD::XamlPropertyIndex::TextBox_TextAlignment)) { continue; } - else if (TryUpdateCharacterSpacing(control, propertyName, propertyValue)) + else if (TryUpdateCharacterSpacing(controlXD, propertyName, propertyValue, XD::XamlPropertyIndex::Control_CharacterSpacing)) { continue; } else if (propertyName == "multiline") { if (propertyValue.isBool()) - textBox.TextWrapping(propertyValue.asBool() ? winrt::TextWrapping::Wrap : winrt::TextWrapping::NoWrap); + XamlDirectInstance::GetXamlDirect().SetEnumProperty( + textBoxXD, XD::XamlPropertyIndex::TextBox_TextWrapping, + static_cast(propertyValue.asBool() ? winrt::TextWrapping::Wrap : winrt::TextWrapping::NoWrap) + ); else if (propertyValue.isNull()) - textBox.ClearValue(winrt::TextBox::TextWrappingProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + textBoxXD, + XD::XamlPropertyIndex::TextBox_TextWrapping + ); } else if (propertyName == "allowFontScaling") { if (propertyValue.isBool()) - textBox.IsTextScaleFactorEnabled(propertyValue.asBool()); + XamlDirectInstance::GetXamlDirect().SetBooleanProperty( + textBoxXD, + XD::XamlPropertyIndex::Control_IsTextScaleFactorEnabled, + propertyValue.asBool() + ); else if (propertyValue.isNull()) - textBox.ClearValue(winrt::Control::IsTextScaleFactorEnabledProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + textBoxXD, + XD::XamlPropertyIndex::Control_IsTextScaleFactorEnabled + ); } else if (propertyName == "clearTextOnFocus") { @@ -259,32 +286,63 @@ void TextInputShadowNode::updateProperties(const folly::dynamic&& props) else if (propertyName == "editable") { if (propertyValue.isBool()) - textBox.IsReadOnly(!propertyValue.asBool()); + XamlDirectInstance::GetXamlDirect().SetBooleanProperty( + textBoxXD, + XD::XamlPropertyIndex::TextBox_IsReadOnly, + !propertyValue.asBool() + ); else if (propertyValue.isNull()) - textBox.ClearValue(winrt::TextBox::IsReadOnlyProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + textBoxXD, + XD::XamlPropertyIndex::TextBox_IsReadOnly + ); } else if (propertyName == "maxLength") { if (propertyValue.isNumber()) - textBox.MaxLength(static_cast(propertyValue.asDouble())); + XamlDirectInstance::GetXamlDirect().SetInt32Property( + textBoxXD, + XD::XamlPropertyIndex::TextBox_MaxLength, + static_cast(propertyValue.asDouble()) + ); else if (propertyValue.isNull()) - textBox.ClearValue(winrt::TextBox::MaxLengthProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + textBoxXD, + XD::XamlPropertyIndex::TextBox_MaxLength + ); } else if (propertyName == "placeholder") { if (propertyValue.isString()) - textBox.PlaceholderText(asHstring(propertyValue)); + XamlDirectInstance::GetXamlDirect().SetStringProperty( + textBoxXD, + XD::XamlPropertyIndex::TextBox_PlaceholderText, + asHstring(propertyValue) + ); else if (propertyValue.isNull()) - textBox.ClearValue(winrt::TextBox::PlaceholderTextProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + textBoxXD, + XD::XamlPropertyIndex::TextBox_PlaceholderText + ); } else if (propertyName == "placeholderTextColor") { if (textBox.try_as()) { + if (propertyValue.isNumber()) - textBox.PlaceholderForeground(SolidColorBrushFrom(propertyValue)); + { + XamlDirectInstance::GetXamlDirect().SetColorProperty( + textBoxXD, + XD::XamlPropertyIndex::TextBox_PlaceholderForeground, + SolidColorBrushFrom(propertyValue).Color() + ); + } else if (propertyValue.isNull()) - textBox.ClearValue(winrt::TextBox::PlaceholderForegroundProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + textBoxXD, + XD::XamlPropertyIndex::TextBox_PlaceholderForeground + ); } } else if (propertyName == "scrollEnabled") @@ -292,8 +350,16 @@ void TextInputShadowNode::updateProperties(const folly::dynamic&& props) if (propertyValue.isBool() && textBox.TextWrapping() == winrt::TextWrapping::Wrap) { auto scrollMode = propertyValue.asBool() ? winrt::ScrollMode::Auto : winrt::ScrollMode::Disabled; - winrt::ScrollViewer::SetVerticalScrollMode(textBox, scrollMode); - winrt::ScrollViewer::SetHorizontalScrollMode(textBox, scrollMode); + XamlDirectInstance::GetXamlDirect().SetEnumProperty( + textBoxXD, + XD::XamlPropertyIndex::ScrollViewer_VerticalScrollMode, + static_cast(scrollMode) + ); + XamlDirectInstance::GetXamlDirect().SetEnumProperty( + textBoxXD, + XD::XamlPropertyIndex::ScrollViewer_HorizontalScrollMode, + static_cast(scrollMode) + ); } } else if (propertyName == "selection") @@ -307,11 +373,20 @@ void TextInputShadowNode::updateProperties(const folly::dynamic&& props) } } else if (propertyName == "selectionColor") - { + { if (propertyValue.isNumber()) - textBox.SelectionHighlightColor(SolidColorBrushFrom(propertyValue)); + { + XamlDirectInstance::GetXamlDirect().SetColorProperty( + textBoxXD, + XD::XamlPropertyIndex::TextBox_SelectionHighlightColor, + SolidColorBrushFrom(propertyValue).Color() + ); + } else if (propertyValue.isNull()) - textBox.ClearValue(winrt::TextBox::SelectionHighlightColorProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + textBoxXD, + XD::XamlPropertyIndex::TextBox_SelectionHighlightColor + ); } else if (propertyName == "selectTextOnFocus") { @@ -321,9 +396,16 @@ void TextInputShadowNode::updateProperties(const folly::dynamic&& props) else if (propertyName == "spellCheck") { if (propertyValue.isBool()) - textBox.IsSpellCheckEnabled(propertyValue.asBool()); + XamlDirectInstance::GetXamlDirect().SetBooleanProperty( + textBoxXD, + XD::XamlPropertyIndex::TextBox_IsSpellCheckEnabled, + propertyValue.asBool() + ); else if (propertyValue.isNull()) - textBox.ClearValue(winrt::TextBox::IsSpellCheckEnabledProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + textBoxXD, + XD::XamlPropertyIndex::TextBox_IsSpellCheckEnabled + ); } else if (propertyName == "text") { @@ -331,15 +413,25 @@ void TextInputShadowNode::updateProperties(const folly::dynamic&& props) { if (propertyValue.isString()) { - auto oldValue = textBox.Text(); + auto oldValue = XamlDirectInstance::GetXamlDirect().GetStringProperty( + textBoxXD, + XD::XamlPropertyIndex::TextBox_Text + ); auto newValue = asHstring(propertyValue); if (oldValue != newValue) { - textBox.Text(newValue); + XamlDirectInstance::GetXamlDirect().SetStringProperty( + textBoxXD, + XD::XamlPropertyIndex::TextBox_Text, + newValue + ); } } else if (propertyValue.isNull()) - textBox.ClearValue(winrt::TextBox::TextProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + textBoxXD, + XD::XamlPropertyIndex::TextBox_Text + ); } } else if (propertyName == "mostRecentEventCount") @@ -365,18 +457,6 @@ const char* TextInputViewManager::GetName() const return "RCTTextInput"; } -folly::dynamic TextInputViewManager::GetCommands() const -{ - auto commands = Super::GetCommands(); - commands.update(folly::dynamic::object - ("SetFocus", static_cast>(TextInputCommands::SetFocus)) - ); - commands.update(folly::dynamic::object - ("Blur", static_cast>(TextInputCommands::Blur)) - ); - return commands; -} - folly::dynamic TextInputViewManager::GetNativeProps() const { auto props = Super::GetNativeProps(); @@ -433,16 +513,24 @@ void TextInputViewManager::DispatchCommand(XamlView viewToUpdate, int64_t comman if (textBox == nullptr) return; - switch (static_cast(commandId)) + switch (static_cast(commandId)) { - case TextInputCommands::SetFocus: + case FocusCommand::SetFocus: { textBox.Focus(winrt::FocusState::Programmatic); break; } - case TextInputCommands::Blur: + case FocusCommand::Blur: { + auto focusedUIElement = winrt::FocusManager::GetFocusedElement(); + if (focusedUIElement == nullptr) + break; + + // Verify that the textBox hasn't already lost focus. + if (focusedUIElement.try_as() != textBox) + break; + auto content = winrt::Windows::UI::Xaml::Window::Current().Content(); if (content == nullptr) break; diff --git a/vnext/ReactUWP/Views/TextInputViewManager.h b/vnext/ReactUWP/Views/TextInputViewManager.h index c833f6334c2..af72b2d0f1f 100644 --- a/vnext/ReactUWP/Views/TextInputViewManager.h +++ b/vnext/ReactUWP/Views/TextInputViewManager.h @@ -14,7 +14,6 @@ class TextInputViewManager : public ControlViewManager TextInputViewManager(const std::shared_ptr& reactInstance); const char* GetName() const override; - folly::dynamic GetCommands() const override; folly::dynamic GetNativeProps() const override; folly::dynamic GetExportedCustomDirectEventTypeConstants() const override; facebook::react::ShadowNode* createShadow() const override; diff --git a/vnext/ReactUWP/Views/TextViewManager.cpp b/vnext/ReactUWP/Views/TextViewManager.cpp index 98fa04d7aba..25d9ac9fe7a 100644 --- a/vnext/ReactUWP/Views/TextViewManager.cpp +++ b/vnext/ReactUWP/Views/TextViewManager.cpp @@ -14,6 +14,8 @@ #include #include +#include + namespace winrt { using namespace Windows::UI; using namespace Windows::UI::Xaml; @@ -49,7 +51,11 @@ const char* TextViewManager::GetName() const XamlView TextViewManager::CreateViewCore(int64_t tag) { auto textBlock = winrt::TextBlock(); - textBlock.TextWrapping(winrt::TextWrapping::Wrap); // Default behavior in React Native + XamlDirectInstance::GetXamlDirect().SetEnumProperty( + XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(textBlock), + XD::XamlPropertyIndex::TextBlock_TextWrapping, + static_cast(winrt::TextWrapping::Wrap) + ); return textBlock; } @@ -59,75 +65,126 @@ void TextViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const folly if (textBlock == nullptr) return; + auto textBlockXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(textBlock); + for (const auto& pair : reactDiffMap.items()) { const std::string& propertyName = pair.first.getString(); const folly::dynamic& propertyValue = pair.second; - if (TryUpdateForeground(textBlock, propertyName, propertyValue)) + auto fontPropIdx = XD::XamlPropertyIndex::TextBlock_FontSize; + if (propertyName == "fontFamily") + { + fontPropIdx = XD::XamlPropertyIndex::TextBlock_FontFamily; + } + else if (propertyName == "fontWeight") + { + fontPropIdx = XD::XamlPropertyIndex::TextBlock_FontWeight; + } + else if (propertyName == "fontStyle") + { + fontPropIdx = XD::XamlPropertyIndex::TextBlock_FontStyle; + } + + if (TryUpdateForeground(textBlockXD, propertyName, propertyValue, XD::XamlPropertyIndex::TextBlock_Foreground)) { continue; } - else if (TryUpdateFontProperties(textBlock, propertyName, propertyValue)) + else if (TryUpdateFontProperties(textBlockXD, propertyName, propertyValue, fontPropIdx)) { continue; } - else if (TryUpdatePadding(nodeToUpdate, textBlock, propertyName, propertyValue)) + else if (TryUpdatePadding(nodeToUpdate, textBlockXD, propertyName, propertyValue, XD::XamlPropertyIndex::TextBlock_Padding)) { continue; } - else if (TryUpdateTextAlignment(textBlock, propertyName, propertyValue)) + else if (TryUpdateTextAlignment(textBlockXD, propertyName, propertyValue, XD::XamlPropertyIndex::TextBlock_TextAlignment)) { continue; } - else if (TryUpdateTextTrimming(textBlock, propertyName, propertyValue)) + else if (TryUpdateTextTrimming(textBlockXD, propertyName, propertyValue, XD::XamlPropertyIndex::TextBlock_TextTrimming)) { continue; } - else if (TryUpdateTextDecorationLine(textBlock, propertyName, propertyValue)) + else if (TryUpdateTextDecorationLine(textBlockXD, propertyName, propertyValue, XD::XamlPropertyIndex::TextBlock_TextDecorations)) { continue; } - else if (TryUpdateCharacterSpacing(textBlock, propertyName, propertyValue)) + else if (TryUpdateCharacterSpacing(textBlockXD, propertyName, propertyValue, XD::XamlPropertyIndex::TextBlock_CharacterSpacing)) { continue; } else if (propertyName == "numberOfLines") { if (propertyValue.isNumber()) - textBlock.MaxLines(static_cast(propertyValue.asDouble())); + XamlDirectInstance::GetXamlDirect().SetInt32Property( + textBlockXD, + XD::XamlPropertyIndex::TextBlock_MaxLines, + static_cast(propertyValue.asDouble()) + ); else if (propertyValue.isNull()) - textBlock.ClearValue(winrt::TextBlock::MaxLinesProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + textBlockXD, + XD::XamlPropertyIndex::TextBlock_MaxLines + ); } else if (propertyName == "lineHeight") { if (propertyValue.isNumber()) - textBlock.LineHeight(static_cast(propertyValue.asDouble())); + XamlDirectInstance::GetXamlDirect().SetDoubleProperty( + textBlockXD, + XD::XamlPropertyIndex::TextBlock_LineHeight, + propertyValue.asDouble() + ); else if (propertyValue.isNull()) - textBlock.ClearValue(winrt::TextBlock::LineHeightProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + textBlockXD, + XD::XamlPropertyIndex::TextBlock_LineHeight + ); } else if (propertyName == "selectable") { if (propertyValue.isBool()) - textBlock.IsTextSelectionEnabled(propertyValue.asBool()); + XamlDirectInstance::GetXamlDirect().SetBooleanProperty( + textBlockXD, + XD::XamlPropertyIndex::TextBlock_IsTextSelectionEnabled, + propertyValue.asBool() + ); else if (propertyValue.isNull()) - textBlock.ClearValue(winrt::TextBlock::IsTextSelectionEnabledProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + textBlockXD, + XD::XamlPropertyIndex::TextBlock_IsTextSelectionEnabled + ); } else if (propertyName == "allowFontScaling") { if (propertyValue.isBool()) - textBlock.IsTextScaleFactorEnabled(propertyValue.asBool()); + XamlDirectInstance::GetXamlDirect().SetBooleanProperty( + textBlockXD, + XD::XamlPropertyIndex::TextBlock_IsTextScaleFactorEnabled, + propertyValue.asBool() + ); else - textBlock.ClearValue(winrt::TextBlock::IsTextScaleFactorEnabledProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + textBlockXD, + XD::XamlPropertyIndex::TextBlock_IsTextScaleFactorEnabled + ); } else if (propertyName == "selectionColor") { if (propertyValue.isNumber()) { - textBlock.SelectionHighlightColor(SolidColorBrushFrom(propertyValue)); + XamlDirectInstance::GetXamlDirect().SetColorProperty( + textBlockXD, + XD::XamlPropertyIndex::TextBlock_SelectionHighlightColor, + SolidColorBrushFrom(propertyValue).Color() + ); } else - textBlock.ClearValue(winrt::TextBlock::SelectionHighlightColorProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + textBlockXD, + XD::XamlPropertyIndex::TextBlock_SelectionHighlightColor + ); } } @@ -136,21 +193,39 @@ void TextViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const folly void TextViewManager::AddView(XamlView parent, XamlView child, int64_t index) { - auto textBlock(parent.as()); - auto childInline(child.as()); - textBlock.Inlines().InsertAt(static_cast(index), childInline); + auto textBlockXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(parent.as()); + auto childInlineXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(child.as()); + auto textBlockInlinesXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObjectProperty( + textBlockXD, + XD::XamlPropertyIndex::TextBlock_Inlines + ); + XamlDirectInstance::GetXamlDirect().InsertIntoCollectionAt( + textBlockInlinesXD, + static_cast(index), childInlineXD + ); } void TextViewManager::RemoveAllChildren(XamlView parent) { - auto textBlock(parent.as()); - textBlock.Inlines().Clear(); + auto textBlockXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(parent.as()); + auto textBlockInlinesXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObjectProperty( + textBlockXD, + XD::XamlPropertyIndex::TextBlock_Inlines + ); + XamlDirectInstance::GetXamlDirect().ClearCollection(textBlockInlinesXD); } void TextViewManager::RemoveChildAt(XamlView parent, int64_t index) { - auto textBlock(parent.as()); - return textBlock.Inlines().RemoveAt(static_cast(index)); + auto textBlockXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(parent.as()); + auto textBlockInlinesXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObjectProperty( + textBlockXD, + XD::XamlPropertyIndex::TextBlock_Inlines + ); + XamlDirectInstance::GetXamlDirect().RemoveFromCollectionAt( + textBlockInlinesXD, + static_cast(index) + ); } YGMeasureFunc TextViewManager::GetYogaCustomMeasureFunc() const diff --git a/vnext/ReactUWP/Views/ViewControl.cpp b/vnext/ReactUWP/Views/ViewControl.cpp index 9355117ec4f..abfa3878bf3 100644 --- a/vnext/ReactUWP/Views/ViewControl.cpp +++ b/vnext/ReactUWP/Views/ViewControl.cpp @@ -4,95 +4,37 @@ #include "pch.h" #include "ViewControl.h" - -#include -#include -#include +#include "DynamicAutomationPeer.h" namespace winrt { -using namespace Windows::UI; -using namespace Windows::UI::Xaml; -using namespace Windows::UI::Xaml::Controls; -using namespace Windows::UI::Xaml::Interop; -using namespace Windows::UI::Xaml::Media; -using namespace Windows::Foundation; + using namespace Windows::UI::Xaml::Automation::Peers; } -namespace react { namespace uwp { - -ViewControl::ViewControl() +namespace winrt::react::uwp::implementation { -} -/*static*/ winrt::com_ptr ViewControl::Create() +ViewControl::ViewControl() : Super() { - return winrt::make_self(); } -winrt::Windows::UI::Xaml::Automation::Peers::AutomationPeer ViewControl::OnCreateAutomationPeer() +winrt::AutomationPeer ViewControl::OnCreateAutomationPeer() { - auto dyn = winrt::make(*this); - return dyn; + return winrt::make(*this); } -} } // namespace react::uwp - -namespace winrt::react::uwp::implementation +winrt::react::uwp::ViewPanel ViewControl::GetPanel() const { - DynamicAutomationPeer::DynamicAutomationPeer(Windows::UI::Xaml::FrameworkElement const& owner) - : Super(owner) - { - } + auto child = Content(); - Windows::UI::Xaml::Automation::Peers::AutomationControlType DynamicAutomationPeer::GetAutomationControlTypeCore() const - { - auto viewControl = Owner().as<::react::uwp::ViewControl>(); + if (auto border = child.try_as()) + { + child = border.Child(); + } - switch(viewControl->AccessibilityRole()) - { - case ::react::uwp::AccessibilityRoles::Button: - case ::react::uwp::AccessibilityRoles::ImageButton: - return winrt::Windows::UI::Xaml::Automation::Peers::AutomationControlType::Button; - case ::react::uwp::AccessibilityRoles::Link: - return winrt::Windows::UI::Xaml::Automation::Peers::AutomationControlType::Hyperlink; - case ::react::uwp::AccessibilityRoles::Image: - return winrt::Windows::UI::Xaml::Automation::Peers::AutomationControlType::Image; - case ::react::uwp::AccessibilityRoles::KeyboardKey: - return winrt::Windows::UI::Xaml::Automation::Peers::AutomationControlType::Custom; - case ::react::uwp::AccessibilityRoles::Text: - case ::react::uwp::AccessibilityRoles::Summary: - case ::react::uwp::AccessibilityRoles::Header: - return winrt::Windows::UI::Xaml::Automation::Peers::AutomationControlType::Text; - case ::react::uwp::AccessibilityRoles::Adjustable: - return winrt::Windows::UI::Xaml::Automation::Peers::AutomationControlType::Slider; - case ::react::uwp::AccessibilityRoles::Search: - case ::react::uwp::AccessibilityRoles::Unknown: - default: - return winrt::Windows::UI::Xaml::Automation::Peers::AutomationControlType::Group; - } - } + auto panel = child.try_as(); + assert(panel != nullptr); - Windows::Foundation::IInspectable DynamicAutomationPeer::GetPatternCore(Windows::UI::Xaml::Automation::Peers::PatternInterface const& patternInterface) const - { - auto viewControl = Owner().as<::react::uwp::ViewControl>(); - - if (patternInterface == Windows::UI::Xaml::Automation::Peers::PatternInterface::Invoke && - (viewControl->AccessibilityRole() == ::react::uwp::AccessibilityRoles::Button || - viewControl->AccessibilityRole() == ::react::uwp::AccessibilityRoles::ImageButton)) - { - return *this; - } - - return nullptr; - } - - - void DynamicAutomationPeer::Invoke() const - { - auto viewControl = Owner().as<::react::uwp::ViewControl>(); - auto invokeHandler = viewControl->AccessibilityInvoke(); - if (invokeHandler) - invokeHandler(); - } + return panel; +} } diff --git a/vnext/ReactUWP/Views/ViewControl.h b/vnext/ReactUWP/Views/ViewControl.h index 9f06c3432f8..55259992e4b 100644 --- a/vnext/ReactUWP/Views/ViewControl.h +++ b/vnext/ReactUWP/Views/ViewControl.h @@ -3,71 +3,36 @@ #pragma once -#include +#include -#include -#include +#include #include -#include -#include -namespace react { -namespace uwp { +#include "cppwinrt/ViewControl.g.h" +namespace winrt::react::uwp::implementation +{ // -// ViewControl is ViewViewManager's ContentControl but with a custom AutomationPeer -// using DynamicAutomationPeer (See below) +// ViewControl is a ContentControl that ViewViewManager uses to wrap a ViewPanel +// when we want that ViewPanel to be keyboard focusable // -struct ViewControl : winrt::Windows::UI::Xaml::Controls::ContentControlT +struct ViewControl : ViewControlT { - using Super = winrt::Windows::UI::Xaml::Controls::ContentControlT; -private: + using Super = ViewControlT; +public: // Constructors ViewControl(); -public: - static winrt::com_ptr Create(); - template friend auto winrt::make_self(Args&&... args); - winrt::Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer(); - // Public Methods - AccessibilityRoles AccessibilityRole() { return m_accessibilityRole; } - void AccessibilityRole(AccessibilityRoles role) { m_accessibilityRole = role; } - - using AccessibilityInvokeEventHandler = std::function; - const AccessibilityInvokeEventHandler& AccessibilityInvoke() { return m_accessibilityInvokeHandler; } - void AccessibilityInvoke(AccessibilityInvokeEventHandler&& handler) - { - m_accessibilityInvokeHandler = std::move(handler); - } - -private: - AccessibilityRoles m_accessibilityRole = AccessibilityRoles::None; - AccessibilityInvokeEventHandler m_accessibilityInvokeHandler = nullptr; + winrt::react::uwp::ViewPanel GetPanel() const; }; -}} // namespace react::uwp +} // winrt::react::uwp::implementation - -#include "cppwinrt/react.uwp.DynamicAutomationPeer.g.h" -namespace winrt::react::uwp::implementation +namespace winrt::react::uwp::factory_implementation { -// -// DynamicAutomationPeer refers to the owner ViewControl to determine what type control -// it appears to be for accessibility tools -// -struct DynamicAutomationPeer : DynamicAutomationPeerT -{ - using Super = DynamicAutomationPeerT; - - DynamicAutomationPeer() = delete; - DynamicAutomationPeer(Windows::UI::Xaml::FrameworkElement const& owner); - - Windows::UI::Xaml::Automation::Peers::AutomationControlType GetAutomationControlTypeCore() const; - Windows::Foundation::IInspectable GetPatternCore(Windows::UI::Xaml::Automation::Peers::PatternInterface const& patternInterface) const; - - void Invoke() const; -}; -} // namespace winrt::react::uwp::implementation - + struct ViewControl : ViewControlT + { + }; +} diff --git a/vnext/ReactUWP/Views/ViewManagerBase.cpp b/vnext/ReactUWP/Views/ViewManagerBase.cpp index 0ddccbb09b3..0d4c1802870 100644 --- a/vnext/ReactUWP/Views/ViewManagerBase.cpp +++ b/vnext/ReactUWP/Views/ViewManagerBase.cpp @@ -24,6 +24,9 @@ namespace react { namespace uwp { float GetConstrainedResult(float constrainTo, float measuredSize, YGMeasureMode measureMode) { + // Round up to workaround truncation inside yoga + measuredSize = ceil(measuredSize); + if (measureMode == YGMeasureMode::YGMeasureModeExactly) return constrainTo; if (measureMode == YGMeasureMode::YGMeasureModeAtMost) @@ -92,6 +95,8 @@ dynamic ViewManagerBase::GetNativeProps() const folly::dynamic props = folly::dynamic::object(); props.update(folly::dynamic::object ("onLayout", "function") + ("keyDownEvents", "array") + ("keyUpEvents", "array") ); return props; } @@ -142,6 +147,10 @@ dynamic ViewManagerBase::GetExportedCustomBubblingEventTypeConstants() const "TouchMove", "TouchCancel", "TouchEnd", + + // Keyboard events + "KeyUp", + "KeyDown", }; folly::dynamic bubblingEvents = folly::dynamic::object(); @@ -229,6 +238,14 @@ void ViewManagerBase::UpdateProperties(ShadowNodeBase* nodeToUpdate, const dynam { nodeToUpdate->m_onLayout = !propertyValue.isNull() && propertyValue.asBool(); } + else if (propertyName == "keyDownEvents") + { + nodeToUpdate->UpdateHandledKeyboardEvents(propertyName, propertyValue); + } + else if (propertyName == "keyUpEvents") + { + nodeToUpdate->UpdateHandledKeyboardEvents(propertyName, propertyValue); + } } } @@ -248,12 +265,12 @@ void ViewManagerBase::SetLayoutProps(ShadowNodeBase& nodeToUpdate, XamlView view // TODO: Assert return; } + auto fe = element.as(); // Set Position & Size Properties ViewPanel::SetLeft(element, left); ViewPanel::SetTop(element, top); - auto fe = element.as(); fe.Width(width); fe.Height(height); @@ -262,18 +279,18 @@ void ViewManagerBase::SetLayoutProps(ShadowNodeBase& nodeToUpdate, XamlView view { int64_t tag = GetTag(viewToUpdate); folly::dynamic layout = folly::dynamic::object - ("x", left) - ("y", top) - ("height", height) - ("width", width); + ("x", left) + ("y", top) + ("height", height) + ("width", width); folly::dynamic eventData = folly::dynamic::object - ("target", tag) - ("layout", std::move(layout)); + ("target", tag) + ("layout", std::move(layout)); auto instance = m_wkReactInstance.lock(); if (instance != nullptr) - instance->DispatchEvent(tag, "topLayout", std::move(eventData)); + instance->DispatchEvent(tag, "topLayout", std::move(eventData)); } } @@ -292,4 +309,5 @@ bool ViewManagerBase::IsNativeControlWithSelfLayout() const return GetYogaCustomMeasureFunc() != nullptr; } + } } diff --git a/vnext/ReactUWP/Views/ViewPanel.cpp b/vnext/ReactUWP/Views/ViewPanel.cpp index f0750e74ff0..6f8e5fd4dd4 100644 --- a/vnext/ReactUWP/Views/ViewPanel.cpp +++ b/vnext/ReactUWP/Views/ViewPanel.cpp @@ -4,50 +4,38 @@ #include "pch.h" #include "ViewPanel.h" +#include "DynamicAutomationPeer.h" #include #include +#include + namespace winrt { using namespace Windows::UI; using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Automation::Peers; using namespace Windows::UI::Xaml::Controls; using namespace Windows::UI::Xaml::Interop; using namespace Windows::UI::Xaml::Media; using namespace Windows::Foundation; } // namespace winrt -namespace react -{ -namespace uwp +namespace winrt::react::uwp::implementation { const winrt::TypeName viewPanelTypeName{ winrt::hstring{L"ViewPanel"}, winrt::TypeKind::Metadata}; -ViewPanel::ViewPanel() -{ -} - -/*static*/ winrt::com_ptr ViewPanel::Create() +ViewPanel::ViewPanel() : Super() { - return winrt::make_self(); } -/*static*/ winrt::DependencyProperty ViewPanel::BackgroundProperty() +winrt::AutomationPeer ViewPanel::OnCreateAutomationPeer() { - static winrt::DependencyProperty s_backgroundProperty = - winrt::DependencyProperty::Register( - L"Background", - winrt::xaml_typename(), - viewPanelTypeName, - winrt::PropertyMetadata( - winrt::SolidColorBrush(), - ViewPanel::VisualPropertyChanged)); - - return s_backgroundProperty; + return winrt::make(*this); } /*static*/ void ViewPanel::VisualPropertyChanged(winrt::DependencyObject sender, winrt::DependencyPropertyChangedEventArgs e) @@ -64,6 +52,20 @@ ViewPanel::ViewPanel() element.InvalidateArrange(); } +/*static*/ winrt::DependencyProperty ViewPanel::ViewBackgroundProperty() +{ + static winrt::DependencyProperty s_viewBackgroundProperty = + winrt::DependencyProperty::Register( + L"ViewBackground", + winrt::xaml_typename(), + viewPanelTypeName, + winrt::PropertyMetadata( + winrt::SolidColorBrush(), + ViewPanel::VisualPropertyChanged)); + + return s_viewBackgroundProperty; +} + /*static*/ winrt::DependencyProperty ViewPanel::BorderThicknessProperty() { static winrt::DependencyProperty s_borderThicknessProperty = @@ -122,7 +124,7 @@ ViewPanel::ViewPanel() /*static*/ winrt::DependencyProperty ViewPanel::LeftProperty() { - static winrt::DependencyProperty s_topProperty = + static winrt::DependencyProperty s_LeftProperty = winrt::DependencyProperty::RegisterAttached( L"Left", winrt::xaml_typename(), @@ -131,7 +133,7 @@ ViewPanel::ViewPanel() winrt::box_value((double)0), ViewPanel::PositionPropertyChanged)); - return s_topProperty; + return s_LeftProperty; } /*static*/ winrt::DependencyProperty ViewPanel::ClipChildrenProperty() @@ -148,13 +150,13 @@ ViewPanel::ViewPanel() return s_clipChildrenProperty; } -/*static*/ void ViewPanel::SetTop(winrt::Windows::UI::Xaml::UIElement &element, double value) +/*static*/ void ViewPanel::SetTop(winrt::Windows::UI::Xaml::UIElement const& element, double value) { element.SetValue(TopProperty(), winrt::box_value(value)); element.InvalidateArrange(); } -/*static*/ void ViewPanel::SetLeft(winrt::Windows::UI::Xaml::UIElement &element, double value) +/*static*/ void ViewPanel::SetLeft(winrt::Windows::UI::Xaml::UIElement const& element, double value) { element.SetValue(LeftProperty(), winrt::box_value(value)); element.InvalidateArrange(); @@ -216,30 +218,33 @@ winrt::Size ViewPanel::ArrangeOverride(winrt::Size finalSize) void ViewPanel::InsertAt(uint32_t const index, winrt::UIElement const &value) const { - Children().InsertAt(index, value); + const auto childrenXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(Children()); + const auto valueXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(value); + XamlDirectInstance::GetXamlDirect().InsertIntoCollectionAt(childrenXD, index, valueXD); } void ViewPanel::RemoveAt(uint32_t const index) const { - Children().RemoveAt(index); + const auto childrenXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(Children()); + XamlDirectInstance::GetXamlDirect().RemoveFromCollectionAt(childrenXD, index); } void ViewPanel::Remove(winrt::UIElement element) const { - uint32_t index; - - if (Children().IndexOf(element, index)) - Children().RemoveAt(index); + const auto childrenXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(Children()); + const auto elementXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(element); + XamlDirectInstance::GetXamlDirect().RemoveFromCollection(childrenXD, elementXD); } void ViewPanel::Clear() const { - Children().Clear(); + const auto childrenXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(Children()); + XamlDirectInstance::GetXamlDirect().ClearCollection(childrenXD); } -void ViewPanel::Background(winrt::Brush const& value) +void ViewPanel::ViewBackground(winrt::Brush const &value) { - SetValue(BackgroundProperty(), winrt::box_value(value)); + SetValue(ViewBackgroundProperty(), winrt::box_value(value)); } void ViewPanel::BorderThickness(winrt::Thickness const &value) @@ -249,7 +254,7 @@ void ViewPanel::BorderThickness(winrt::Thickness const &value) void ViewPanel::BorderBrush(winrt::Brush const &value) { - SetValue(BorderBrushProperty(), value); + SetValue(BorderBrushProperty(), winrt::box_value(value)); } void ViewPanel::CornerRadius(winrt::CornerRadius const &value) @@ -283,7 +288,7 @@ void ViewPanel::FinalizeProperties() const auto unsetValue = winrt::DependencyProperty::UnsetValue(); - bool hasBackground = ReadLocalValue(BackgroundProperty()) != unsetValue; + bool hasBackground = ReadLocalValue(ViewBackgroundProperty()) != unsetValue; bool hasBorderBrush = ReadLocalValue(BorderBrushProperty()) != unsetValue; bool hasBorderThickness = ReadLocalValue(BorderThicknessProperty()) != unsetValue; bool hasCornerRadius = ReadLocalValue(CornerRadiusProperty()) != unsetValue; @@ -312,34 +317,65 @@ void ViewPanel::FinalizeProperties() m_hasOuterBorder = false; } + auto m_borderXD = XamlDirectInstance::GetXamlDirect().CreateInstance(XD::XamlTypeIndex::Border); + // Border element if (scenario != Scenario::NoBorder) { // Ensure Border is created if (m_border == nullptr) { - m_border = winrt::Border(); - // Add border as the top child if using as inner border if (scenario == Scenario::InnerBorder) - Children().Append(m_border); + { + const auto childrenXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(Children()); + XamlDirectInstance::GetXamlDirect().AddToCollection(childrenXD, m_borderXD); + } + } + else + { + m_borderXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(m_border); } + // TODO: Can Binding be used here? if (hasBorderBrush) - m_border.BorderBrush(BorderBrush()); + { + XamlDirectInstance::GetXamlDirect().SetColorProperty( + m_borderXD, + XD::XamlPropertyIndex::Border_BorderBrush, + BorderBrush().as().Color() + ); + } else - m_border.ClearValue(winrt::Border::BorderBrushProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + m_borderXD, + XD::XamlPropertyIndex::Border_BorderBrush + ); if (hasBorderThickness) - m_border.BorderThickness(BorderThickness()); + XamlDirectInstance::GetXamlDirect().SetThicknessProperty( + m_borderXD, + XD::XamlPropertyIndex::Border_BorderThickness, + BorderThickness() + ); else - m_border.ClearValue(winrt::Border::BorderThicknessProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + m_borderXD, + XD::XamlPropertyIndex::Border_BorderThickness + ); if (hasCornerRadius) - m_border.CornerRadius(CornerRadius()); + XamlDirectInstance::GetXamlDirect().SetCornerRadiusProperty( + m_borderXD, + XD::XamlPropertyIndex::Border_CornerRadius, + CornerRadius() + ); else - m_border.ClearValue(winrt::Border::CornerRadiusProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + m_borderXD, + XD::XamlPropertyIndex::Border_CornerRadius + ); } else if (m_border != nullptr) { @@ -350,10 +386,21 @@ void ViewPanel::FinalizeProperties() if (scenario == Scenario::OuterBorder) { + m_borderXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(m_border); + if (hasBackground) - m_border.Background(Background()); + { + XamlDirectInstance::GetXamlDirect().SetColorProperty( + m_borderXD, + XD::XamlPropertyIndex::Border_Background, + ViewBackground().as().Color() + ); + } else - m_border.ClearValue(winrt::Border::BackgroundProperty()); + XamlDirectInstance::GetXamlDirect().ClearProperty( + m_borderXD, + XD::XamlPropertyIndex::Border_Background + ); ClearValue(winrt::Panel::BackgroundProperty()); } @@ -361,12 +408,7 @@ void ViewPanel::FinalizeProperties() { // Set any background on this Panel if (hasBackground) - SetValue(winrt::Panel::BackgroundProperty(), Background()); - else - ClearValue(winrt::Panel::BackgroundProperty()); - // Set any background on this Panel - if (hasBackground) - SetValue(winrt::Panel::BackgroundProperty(), Background()); + SetValue(winrt::Panel::BackgroundProperty(), ViewBackground()); else ClearValue(winrt::Panel::BackgroundProperty()); } @@ -398,5 +440,4 @@ void ViewPanel::UpdateClip(winrt::Size& finalSize) } } -} // namespace uwp -} // namespace react +} // namespace winrt::react::uwp::implementation diff --git a/vnext/ReactUWP/Views/ViewPanel.h b/vnext/ReactUWP/Views/ViewPanel.h index 4ae5333e85f..a71a81d7012 100644 --- a/vnext/ReactUWP/Views/ViewPanel.h +++ b/vnext/ReactUWP/Views/ViewPanel.h @@ -4,23 +4,27 @@ #pragma once #include +#include #include #include -namespace react { namespace uwp { +#include "cppwinrt/ViewPanel.g.h" -struct ViewPanel : winrt::Windows::UI::Xaml::Controls::PanelT +namespace winrt::react::uwp::implementation { - using Super = winrt::Windows::UI::Xaml::Controls::PanelT; -private: - // Constructors - ViewPanel(); -public: - static winrt::com_ptr Create(); +// +// ViewPanel is our custom Panel used by ViewViewManager +// +struct ViewPanel : ViewPanelT +{ + using Super = ViewPanelT; public: - template friend auto winrt::make_self(Args&&... args); + // Constructors + ViewPanel(); + + winrt::Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer(); // Overrides virtual winrt::Windows::Foundation::Size MeasureOverride(winrt::Windows::Foundation::Size availableSize); @@ -35,8 +39,8 @@ struct ViewPanel : winrt::Windows::UI::Xaml::Controls::PanelT winrt::Windows::UI::Xaml::Controls::Border GetOuterBorder(); // Public Properties - winrt::Windows::UI::Xaml::Media::Brush Background() { return GetValue(BackgroundProperty()).try_as(); } - void Background(winrt::Windows::UI::Xaml::Media::Brush const& value); + winrt::Windows::UI::Xaml::Media::Brush ViewBackground() { return GetValue(ViewBackgroundProperty()).as(); } + void ViewBackground(winrt::Windows::UI::Xaml::Media::Brush const& value); winrt::Windows::UI::Xaml::Thickness BorderThickness() { return winrt::unbox_value(GetValue(BorderThicknessProperty())); } void BorderThickness(winrt::Windows::UI::Xaml::Thickness const& value); @@ -50,22 +54,21 @@ struct ViewPanel : winrt::Windows::UI::Xaml::Controls::PanelT bool ClipChildren() { return winrt::unbox_value(GetValue(ClipChildrenProperty())); } void ClipChildren(bool value); -public: // ViewPanel Properties - static winrt::Windows::UI::Xaml::DependencyProperty BorderBrushProperty(); + static winrt::Windows::UI::Xaml::DependencyProperty ViewBackgroundProperty(); static winrt::Windows::UI::Xaml::DependencyProperty BorderThicknessProperty(); + static winrt::Windows::UI::Xaml::DependencyProperty BorderBrushProperty(); static winrt::Windows::UI::Xaml::DependencyProperty CornerRadiusProperty(); - static winrt::Windows::UI::Xaml::DependencyProperty BackgroundProperty(); static winrt::Windows::UI::Xaml::DependencyProperty ClipChildrenProperty(); // Attached Properties static winrt::Windows::UI::Xaml::DependencyProperty TopProperty(); - static void SetTop(winrt::Windows::UI::Xaml::UIElement& element, double value); - static double GetTop(winrt::Windows::UI::Xaml::UIElement& element) { return winrt::unbox_value(element.GetValue(TopProperty())); } + static void SetTop(winrt::Windows::UI::Xaml::UIElement const& element, double value); + static double GetTop(winrt::Windows::UI::Xaml::UIElement const& element) { return winrt::unbox_value(element.GetValue(TopProperty())); } static winrt::Windows::UI::Xaml::DependencyProperty LeftProperty(); - static void SetLeft(winrt::Windows::UI::Xaml::UIElement& element, double value); - static double GetLeft(winrt::Windows::UI::Xaml::UIElement& element) { return winrt::unbox_value(element.GetValue(LeftProperty())); } + static void SetLeft(winrt::Windows::UI::Xaml::UIElement const& element, double value); + static double GetLeft(winrt::Windows::UI::Xaml::UIElement const& element) { return winrt::unbox_value(element.GetValue(LeftProperty())); } private: void Remove(winrt::Windows::UI::Xaml::UIElement element) const; @@ -73,17 +76,37 @@ struct ViewPanel : winrt::Windows::UI::Xaml::Controls::PanelT void UpdateClip(winrt::Windows::Foundation::Size& finalSize); private: - // Properties: Background is not managed as a DP so it won't conflict with the parent Background property. - //std::optional m_optBackgroundBrush; bool m_propertiesChanged { false }; // Child Elements winrt::Windows::UI::Xaml::Controls::Border m_border { nullptr }; bool m_hasOuterBorder; +private: + winrt::react::uwp::AccessibilityRoles m_accessibilityRole = winrt::react::uwp::AccessibilityRoles::None; + bool m_accessibilityStates[static_cast(winrt::react::uwp::AccessibilityStates::CountStates)] = { }; + + winrt::react::uwp::AccessibilityInvokeEventHandler m_accessibilityInvokeHandler = { nullptr }; + private: static void VisualPropertyChanged(winrt::Windows::UI::Xaml::DependencyObject sender, winrt::Windows::UI::Xaml::DependencyPropertyChangedEventArgs e); static void PositionPropertyChanged(winrt::Windows::UI::Xaml::DependencyObject sender, winrt::Windows::UI::Xaml::DependencyPropertyChangedEventArgs e); }; -} } +} + +namespace winrt::react::uwp::factory_implementation +{ + struct ViewPanel : ViewPanelT + { + }; +} + +namespace react::uwp +{ + // BUG: Calling static members on winrt::react::uwp::ViewPanel fails to call + // down into winrt::react::uwp::implementation::ViewPanel because of how we're + // using cppwinrt. This workaround is so that consumers in react::uwp can just call ViewPanel + + using ViewPanel = winrt::react::uwp::implementation::ViewPanel; +} diff --git a/vnext/ReactUWP/Views/ViewViewManager.cpp b/vnext/ReactUWP/Views/ViewViewManager.cpp index 86868153f98..7a8d739f6d7 100644 --- a/vnext/ReactUWP/Views/ViewViewManager.cpp +++ b/vnext/ReactUWP/Views/ViewViewManager.cpp @@ -6,10 +6,12 @@ #include "ViewViewManager.h" #include "ViewControl.h" -#include "ViewPanel.h" + +#include "DynamicAutomationProperties.h" #include #include +#include #include #include @@ -20,6 +22,8 @@ #include #include +#include + #if defined(_DEBUG) // Currently only used for tagging controls in debug #include @@ -58,7 +62,7 @@ class ViewShadowNode : public ShadowNodeBase m_enableFocusRing = enable; if (IsControl()) - GetControl()->UseSystemFocusVisuals(m_enableFocusRing); + GetControl().UseSystemFocusVisuals(m_enableFocusRing); } int32_t TabIndex() { return m_tabIndex; } @@ -67,40 +71,41 @@ class ViewShadowNode : public ShadowNodeBase m_tabIndex = tabIndex; if (IsControl()) - GetControl()->TabIndex(m_tabIndex); + GetControl().TabIndex(m_tabIndex); } bool OnClick() { return m_onClick; } void OnClick(bool isSet) { m_onClick = isSet; } - AccessibilityRoles AccessibilityRole() { return m_accessibilityRole; } - void AccessibilityRole(AccessibilityRoles role) - { - m_accessibilityRole = role; - if (IsControl()) - GetControl()->AccessibilityRole(role); - } - - bool AccessibilityState(AccessibilityStates state) { return m_accessibilityStates[state]; } - void AccessibilityState(AccessibilityStates state, bool value) - { - m_accessibilityStates[state] = value; - } - void AddView(ShadowNode& child, int64_t index) override { - GetViewPanel()->InsertAt(static_cast(index), static_cast(child).GetView().as()); + GetViewPanel().InsertAt(static_cast(index), static_cast(child).GetView().as()); } void RemoveChildAt(int64_t indexToRemove) override { if (indexToRemove == static_cast(indexToRemove)) - GetViewPanel()->RemoveAt(static_cast(indexToRemove)); + GetViewPanel().RemoveAt(static_cast(indexToRemove)); } void removeAllChildren() override { - GetViewPanel()->Clear(); + GetViewPanel().Clear(); + + XamlView current = m_view; + + if (IsControl()) + { + auto control = m_view.as(); + current = control.Content().as(); + control.Content(nullptr); + } + + if (HasOuterBorder()) + { + auto border = current.try_as(); + border.Child(nullptr); + } } void ReplaceChild(XamlView oldChildView, XamlView newChildView) override @@ -109,10 +114,10 @@ class ViewShadowNode : public ShadowNodeBase if (pPanel != nullptr) { uint32_t index; - if (pPanel->Children().IndexOf(oldChildView.as(), index)) + if (pPanel.Children().IndexOf(oldChildView.as(), index)) { - pPanel->RemoveAt(index); - pPanel->InsertAt(index, newChildView.as()); + pPanel.RemoveAt(index); + pPanel.InsertAt(index, newChildView.as()); } else { @@ -124,15 +129,12 @@ class ViewShadowNode : public ShadowNodeBase void RefreshProperties() { // The view may have been replaced, so transfer properties stored on the shadow node to the view - AccessibilityRole(AccessibilityRole()); - AccessibilityState(AccessibilityStates::Disabled, AccessibilityState(AccessibilityStates::Disabled)); - AccessibilityState(AccessibilityStates::Selected, AccessibilityState(AccessibilityStates::Selected)); EnableFocusRing(EnableFocusRing()); TabIndex(TabIndex()); static_cast(GetViewManager())->RefreshTransformMatrix(this); } - winrt::com_ptr GetViewPanel() + winrt::react::uwp::ViewPanel GetViewPanel() { XamlView current = m_view; @@ -148,15 +150,15 @@ class ViewShadowNode : public ShadowNodeBase current = border.Child().try_as(); } - auto panel = current.try_as(); + auto panel = current.try_as(); assert(panel != nullptr); - return std::move(panel); + return panel; } - winrt::impl::com_ref GetControl() + winrt::react::uwp::ViewControl GetControl() { - return IsControl() ? m_view.as() : nullptr; + return IsControl() ? m_view.as() : nullptr; } private: @@ -166,8 +168,6 @@ class ViewShadowNode : public ShadowNodeBase bool m_enableFocusRing = true; bool m_onClick = false; int32_t m_tabIndex = std::numeric_limits::max(); - AccessibilityRoles m_accessibilityRole = AccessibilityRoles::None; - bool m_accessibilityStates[AccessibilityStates::CountStates] = { false, false }; }; @@ -205,19 +205,19 @@ void ViewViewManager::DispatchEvent(int64_t viewTag, std::string eventName, foll XamlView ViewViewManager::CreateViewControl(int64_t tag) { // Create the ViewControl as the outer/containing element, nest the ViewPanel, set default properties - auto contentControlPtr = ViewControl::Create(); + auto contentControl = winrt::make(); - contentControlPtr->GotFocus([=](auto &&, auto &&) + contentControl.GotFocus([=](auto &&, auto &&) { DispatchEvent(tag, "topFocus", std::move(folly::dynamic::object("target", tag))); }); - contentControlPtr->LostFocus([=](auto &&, auto &&) + contentControl.LostFocus([=](auto &&, auto &&) { DispatchEvent(tag, "topBlur", std::move(folly::dynamic::object("target", tag))); }); - contentControlPtr->KeyDown([=](auto &&, winrt::KeyRoutedEventArgs const& e) + contentControl.KeyDown([=](auto &&, winrt::KeyRoutedEventArgs const& e) { if (e.Key() == winrt::VirtualKey::Enter || e.Key() == winrt::VirtualKey::Space) { @@ -237,7 +237,19 @@ XamlView ViewViewManager::CreateViewControl(int64_t tag) } }); - contentControlPtr->AccessibilityInvoke([=]() + return contentControl.try_as(); +} + +XamlView ViewViewManager::CreateViewCore(int64_t tag) +{ + auto panel = winrt::make(); + XamlDirectInstance::GetXamlDirect().SetEnumProperty( + XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(panel), + XD::XamlPropertyIndex::FrameworkElement_VerticalAlignment, + static_cast(winrt::VerticalAlignment::Top) + ); + + DynamicAutomationProperties::SetAccessibilityInvokeEventHandler(panel, [=]() { auto instance = m_wkReactInstance.lock(); if (instance != nullptr) @@ -253,15 +265,6 @@ XamlView ViewViewManager::CreateViewControl(int64_t tag) } }); - return contentControlPtr->try_as(); -} - -XamlView ViewViewManager::CreateViewCore(int64_t tag) -{ - XamlView newViewPanelXamlView(ViewPanel::Create().as()); - auto panel = newViewPanelXamlView.as(); - panel->VerticalAlignment(winrt::VerticalAlignment::Top); - return panel.as(); } @@ -294,21 +297,32 @@ void ViewViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const folly auto pPanel = pViewShadowNode->GetViewPanel(); if (pPanel != nullptr) { + auto pPanelXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(pPanel); for (const auto& pair : reactDiffMap.items()) { const std::string& propertyName = pair.first.getString(); const folly::dynamic& propertyValue = pair.second; + auto borderPropXD = propertyName == "borderColor" ? XD::XamlPropertyIndex::RelativePanel_BorderBrush : XD::XamlPropertyIndex::RelativePanel_BorderThickness; - if (TryUpdateBackgroundBrush(*pPanel, propertyName, propertyValue)) + if (propertyName == "backgroundColor") { - continue; + if (propertyValue.isNumber()) + XamlDirectInstance::GetXamlDirect().SetColorProperty( + pPanelXD, + XD::XamlPropertyIndex::Panel_Background, + SolidColorBrushFrom(propertyValue).Color() + ); + else if (propertyValue.isNull()) + XamlDirectInstance::GetXamlDirect().ClearProperty( + pPanelXD, + XD::XamlPropertyIndex::Panel_Background + ); } - else - if (TryUpdateBorderProperties(nodeToUpdate, *pPanel, propertyName, propertyValue)) + else if (TryUpdateBorderProperties(nodeToUpdate, pPanelXD, propertyName, propertyValue, borderPropXD)) { continue; } - else if (TryUpdateCornerRadius(nodeToUpdate, *pPanel, propertyName, propertyValue)) + else if (TryUpdateCornerRadius(nodeToUpdate, pPanelXD, propertyName, propertyValue, XD::XamlPropertyIndex::RelativePanel_CornerRadius)) { continue; } @@ -325,7 +339,7 @@ void ViewViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const folly if (propertyValue.isString()) { bool clipChildren = propertyValue.getString() == "hidden"; - pPanel->ClipChildren(clipChildren); + pPanel.ClipChildren(clipChildren); } } else if (propertyName == "pointerEvents") @@ -333,7 +347,11 @@ void ViewViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const folly if (propertyValue.isString()) { bool hitTestable = propertyValue.getString() != "none"; - pPanel->IsHitTestVisible(hitTestable); + XamlDirectInstance::GetXamlDirect().SetBooleanProperty( + pPanelXD, + XD::XamlPropertyIndex::UIElement_IsHitTestVisible, + hitTestable + ); } } else if (propertyName == "acceptsKeyboardFocus") @@ -341,65 +359,6 @@ void ViewViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const folly if (propertyValue.isBool()) shouldBeControl = propertyValue.getBool(); } - else if (propertyName == "accessibilityRole") - { - // FUTURE having an accessibilityRole shouldBeControl to support - // non-Touchable scenarios - if (propertyValue.isString()) - { - const std::string& role = propertyValue.getString(); - if (role == "none") - pViewShadowNode->AccessibilityRole(AccessibilityRoles::None); - else if (role == "button") - pViewShadowNode->AccessibilityRole(AccessibilityRoles::Button); - else if (role == "link") - pViewShadowNode->AccessibilityRole(AccessibilityRoles::Link); - else if (role == "search") - pViewShadowNode->AccessibilityRole(AccessibilityRoles::Search); - else if (role == "image") - pViewShadowNode->AccessibilityRole(AccessibilityRoles::Image); - else if (role == "keyboardkey") - pViewShadowNode->AccessibilityRole(AccessibilityRoles::KeyboardKey); - else if (role == "text") - pViewShadowNode->AccessibilityRole(AccessibilityRoles::Text); - else if (role == "adjustable") - pViewShadowNode->AccessibilityRole(AccessibilityRoles::Adjustable); - else if (role == "imagebutton") - pViewShadowNode->AccessibilityRole(AccessibilityRoles::ImageButton); - else if (role == "header") - pViewShadowNode->AccessibilityRole(AccessibilityRoles::Header); - else if (role == "summary") - pViewShadowNode->AccessibilityRole(AccessibilityRoles::Summary); - else - pViewShadowNode->AccessibilityRole(AccessibilityRoles::Unknown); - } - else if (propertyValue.isNull()) - { - pViewShadowNode->AccessibilityRole(AccessibilityRoles::None); - } - } - else if (propertyName == "accessibilityStates") - { - // FUTURE having an accessibilityStates shouldBeControl to support - // non-Touchable scenarios - bool disabled = false; - bool selected = false; - if (propertyValue.isArray()) - { - for (const auto& state : propertyValue) - { - if (!state.isString()) - continue; - if (state.getString() == "disabled") - disabled = true; - else if (state.getString() == "selected") - selected = true; - } - } - - pViewShadowNode->AccessibilityState(AccessibilityStates::Disabled, disabled); - pViewShadowNode->AccessibilityState(AccessibilityStates::Selected, selected); - } else if (propertyName == "enableFocusRing") { if (propertyValue.isBool()) @@ -425,18 +384,18 @@ void ViewViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const folly Super::UpdateProperties(nodeToUpdate, reactDiffMap); - pPanel->FinalizeProperties(); + pPanel.FinalizeProperties(); - TryUpdateView(pViewShadowNode, pPanel.get(), shouldBeControl); + TryUpdateView(pViewShadowNode, pPanel, shouldBeControl); } -void ViewViewManager::TryUpdateView(ViewShadowNode* pViewShadowNode, ViewPanel* pPanel, bool useControl) +void ViewViewManager::TryUpdateView(ViewShadowNode* pViewShadowNode, winrt::react::uwp::ViewPanel& pPanel, bool useControl) { auto instance = m_wkReactInstance.lock(); if (instance == nullptr) return; - bool hasOuterBorder = pPanel->GetOuterBorder() != nullptr; + bool hasOuterBorder = pPanel.GetOuterBorder() != nullptr; // This short-circuits all of the update code when we have the same hierarchy if (!pViewShadowNode->ShouldUpdateView(useControl, hasOuterBorder)) @@ -465,25 +424,25 @@ void ViewViewManager::TryUpdateView(ViewShadowNode* pViewShadowNode, ViewPanel* } else if (pViewShadowNode->IsControl()) { - pViewShadowNode->GetControl()->Content(nullptr); + pViewShadowNode->GetControl().Content(nullptr); } // 2. If need outer border decide if it's our new root, else clean up old outer border if (hasOuterBorder) { if (!useControl) - newXamlView = pPanel->GetOuterBorder().try_as(); + newXamlView = pPanel.GetOuterBorder().try_as(); } else if (pViewShadowNode->HasOuterBorder()) { - winrt::Border outerBorder = pPanel->GetOuterBorder(); + winrt::Border outerBorder = pPanel.GetOuterBorder(); if (outerBorder.Child() != nullptr) - outerBorder.Child(pPanel->try_as()); + outerBorder.Child(pPanel.try_as()); } // 3. Determine if the ViewPanel itself should be our root if (!useControl && !hasOuterBorder) - newXamlView = pPanel->try_as(); + newXamlView = pPanel.try_as(); // ASSERT: One of the three scenarios should be true and we should have a root to use assert(newXamlView != nullptr); @@ -492,7 +451,7 @@ void ViewViewManager::TryUpdateView(ViewShadowNode* pViewShadowNode, ViewPanel* TransferProperties(oldXamlView, newXamlView); // Since we transferred properties to the new view we need to make the call to finalize - pPanel->FinalizeProperties(); + pPanel.FinalizeProperties(); // Update the meta-data in the shadow node pViewShadowNode->IsControl(useControl); @@ -517,19 +476,19 @@ void ViewViewManager::TryUpdateView(ViewShadowNode* pViewShadowNode, ViewPanel* } // Ensure parenting is setup properly - auto visualRoot = pPanel->try_as(); + auto visualRoot = pPanel.try_as(); if (hasOuterBorder) { - winrt::Border outerBorder = pPanel->GetOuterBorder(); + winrt::Border outerBorder = pPanel.GetOuterBorder(); if (outerBorder.Child() == nullptr) - outerBorder.Child(pPanel->try_as()); + outerBorder.Child(pPanel.try_as()); visualRoot = outerBorder; } if (useControl) - pViewShadowNode->GetControl()->Content(visualRoot); + pViewShadowNode->GetControl().Content(visualRoot); } void ViewViewManager::SetLayoutProps(ShadowNodeBase& nodeToUpdate, XamlView viewToUpdate, float left, float top, float width, float height) @@ -539,9 +498,9 @@ void ViewViewManager::SetLayoutProps(ShadowNodeBase& nodeToUpdate, XamlView view auto* pViewShadowNode = static_cast(&nodeToUpdate); if (pViewShadowNode->IsControl()) { - auto pPanel = pViewShadowNode->GetViewPanel(); - pPanel->Width(width); - pPanel->Height(height); + auto pPanelXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(pViewShadowNode->GetViewPanel()); + XamlDirectInstance::GetXamlDirect().SetDoubleProperty(pPanelXD, XD::XamlPropertyIndex::FrameworkElement_Width, width); + XamlDirectInstance::GetXamlDirect().SetDoubleProperty(pPanelXD, XD::XamlPropertyIndex::FrameworkElement_Height, height); } Super::SetLayoutProps(nodeToUpdate, viewToUpdate, left, top, width, height); diff --git a/vnext/ReactUWP/Views/ViewViewManager.h b/vnext/ReactUWP/Views/ViewViewManager.h index dbaf4536460..eec225a1007 100644 --- a/vnext/ReactUWP/Views/ViewViewManager.h +++ b/vnext/ReactUWP/Views/ViewViewManager.h @@ -3,12 +3,12 @@ #pragma once +#include #include namespace react { namespace uwp { class ViewShadowNode; -struct ViewPanel; class ViewViewManager : public FrameworkElementViewManager { @@ -29,7 +29,7 @@ class ViewViewManager : public FrameworkElementViewManager protected: XamlView CreateViewCore(int64_t tag) override; - void TryUpdateView(ViewShadowNode* viewShadowNode, ViewPanel* pPanel, bool useControl); + void TryUpdateView(ViewShadowNode* viewShadowNode, winrt::react::uwp::ViewPanel& pPanel, bool useControl); private: void DispatchEvent(int64_t viewTag, std::string eventName, folly::dynamic&& eventData); diff --git a/vnext/ReactUWP/Views/VirtualTextViewManager.cpp b/vnext/ReactUWP/Views/VirtualTextViewManager.cpp index 7c824d23ce7..4c5e6be035e 100644 --- a/vnext/ReactUWP/Views/VirtualTextViewManager.cpp +++ b/vnext/ReactUWP/Views/VirtualTextViewManager.cpp @@ -12,11 +12,14 @@ #include #include +#include + namespace winrt { using namespace Windows::UI; using namespace Windows::UI::Xaml; using namespace Windows::UI::Xaml::Controls; using namespace Windows::UI::Xaml::Documents; + } namespace react { namespace uwp { @@ -42,22 +45,38 @@ void VirtualTextViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, cons if (span == nullptr) return; + auto spanXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(span.as()); + for (const auto& pair : reactDiffMap.items()) { const std::string& propertyName = pair.first.getString(); const folly::dynamic& propertyValue = pair.second; + auto fontPropIdx = XD::XamlPropertyIndex::TextElement_FontSize; + if (propertyName == "fontFamily") + { + fontPropIdx = XD::XamlPropertyIndex::TextElement_FontFamily; + } + else if (propertyName == "fontWeight") + { + fontPropIdx = XD::XamlPropertyIndex::TextElement_FontWeight; + } + else if (propertyName == "fontStyle") + { + fontPropIdx = XD::XamlPropertyIndex::TextElement_FontStyle; + } + // FUTURE: In the future cppwinrt will generate code where static methods on base types can // be called. For now we specify the base type explicitly - if (TryUpdateForeground(span, propertyName, propertyValue)) + if (TryUpdateForeground(spanXD, propertyName, propertyValue, XD::XamlPropertyIndex::TextElement_Foreground)) { continue; } - else if (TryUpdateFontProperties(span, propertyName, propertyValue)) + else if (TryUpdateFontProperties(spanXD, propertyName, propertyValue, fontPropIdx)) { continue; } - else if (TryUpdateCharacterSpacing(span, propertyName, propertyValue)) + else if (TryUpdateCharacterSpacing(spanXD, propertyName, propertyValue, XD::XamlPropertyIndex::TextElement_CharacterSpacing)) { continue; } @@ -69,20 +88,26 @@ void VirtualTextViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, cons void VirtualTextViewManager::AddView(XamlView parent, XamlView child, int64_t index) { auto span(parent.as()); - auto childInline(child.as()); - span.Inlines().InsertAt(static_cast(index), childInline); + auto spanXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(span); + auto inlines = XamlDirectInstance::GetXamlDirect().GetXamlDirectObjectProperty(spanXD, XD::XamlPropertyIndex::Span_Inlines); + auto childXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(child); + XamlDirectInstance::GetXamlDirect().InsertIntoCollectionAt(inlines, static_cast(index), childXD); } void VirtualTextViewManager::RemoveAllChildren(XamlView parent) { auto span(parent.as()); - span.Inlines().Clear(); + auto spanXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(span); + auto inlines = XamlDirectInstance::GetXamlDirect().GetXamlDirectObjectProperty(spanXD, XD::XamlPropertyIndex::Span_Inlines); + XamlDirectInstance::GetXamlDirect().ClearCollection(inlines); } void VirtualTextViewManager::RemoveChildAt(XamlView parent, int64_t index) { auto span(parent.as()); - return span.Inlines().RemoveAt(static_cast(index)); + auto spanXD = XamlDirectInstance::GetXamlDirect().GetXamlDirectObject(span); + auto inlines = XamlDirectInstance::GetXamlDirect().GetXamlDirectObjectProperty(spanXD, XD::XamlPropertyIndex::Span_Inlines); + XamlDirectInstance::GetXamlDirect().RemoveFromCollectionAt(inlines, static_cast(index)); } bool VirtualTextViewManager::RequiresYogaNode() const diff --git a/vnext/ReactUWP/Views/cppwinrt/Microsoft.UI.Composition.Effects.BorderEffect.g.h b/vnext/ReactUWP/Views/cppwinrt/BorderEffect.g.h similarity index 91% rename from vnext/ReactUWP/Views/cppwinrt/Microsoft.UI.Composition.Effects.BorderEffect.g.h rename to vnext/ReactUWP/Views/cppwinrt/BorderEffect.g.h index b2f6cc4eae1..b92fa0d67fa 100644 --- a/vnext/ReactUWP/Views/cppwinrt/Microsoft.UI.Composition.Effects.BorderEffect.g.h +++ b/vnext/ReactUWP/Views/cppwinrt/BorderEffect.g.h @@ -1,4 +1,4 @@ -// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.180821.2 +// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.190111.3 #pragma once @@ -38,9 +38,9 @@ struct WINRT_EBO BorderEffect_base : implements - using default_interface_t = typename default_interface::type; -} - -namespace winrt -{ - template - using default_interface = typename impl::default_interface::type; -} -#endif - namespace winrt::react::uwp::implementation { template -struct WINRT_EBO DynamicAutomationPeer_base : implements, +struct WINRT_EBO DynamicAutomationPeer_base : implements, impl::require, impl::base, Windows::UI::Xaml::Automation::Peers::IAutomationPeerOverridesT, Windows::UI::Xaml::Automation::Peers::IAutomationPeerOverrides2T, Windows::UI::Xaml::Automation::Peers::IAutomationPeerOverrides3T, Windows::UI::Xaml::Automation::Peers::IAutomationPeerOverrides4T, Windows::UI::Xaml::Automation::Peers::IAutomationPeerOverrides5T, Windows::UI::Xaml::Automation::Peers::IAutomationPeerOverrides6T, Windows::UI::Xaml::Automation::Peers::IAutomationPeerOverrides8T, Windows::UI::Xaml::Automation::Peers::IAutomationPeerOverrides9T @@ -86,9 +75,9 @@ struct WINRT_EBO DynamicAutomationPeerT : implements +struct WINRT_EBO DynamicAutomationProperties_base : implements +{ + using base_type = DynamicAutomationProperties_base; + using class_type = react::uwp::DynamicAutomationProperties; + using implements_type = typename DynamicAutomationProperties_base::implements_type; + using implements_type::implements_type; + +#if _MSC_VER < 1914 + operator class_type() const noexcept + { + static_assert(std::is_same_v::type, default_interface>); + class_type result{ nullptr }; + attach_abi(result, detach_abi(static_cast>(*this))); + return result; + } +#else + operator impl::producer_ref const() const noexcept + { + return { to_abi>(this) }; + } +#endif + + hstring GetRuntimeClassName() const + { + return L"react.uwp.DynamicAutomationProperties"; + } +}; + +} + +namespace winrt::react::uwp::factory_implementation { + +template +struct WINRT_EBO DynamicAutomationPropertiesT : implements +{ + using instance_type = react::uwp::DynamicAutomationProperties; + + hstring GetRuntimeClassName() const + { + return L"react.uwp.DynamicAutomationProperties"; + } + + Windows::Foundation::IInspectable ActivateInstance() const + { + throw hresult_not_implemented(); + } + + Windows::UI::Xaml::DependencyProperty AccessibilityRoleProperty() + { + return T::AccessibilityRoleProperty(); + } + + void SetAccessibilityRole(Windows::UI::Xaml::UIElement const& element, react::uwp::AccessibilityRoles const& value) + { + T::SetAccessibilityRole(element, value); + } + + react::uwp::AccessibilityRoles GetAccessibilityRole(Windows::UI::Xaml::UIElement const& element) + { + return T::GetAccessibilityRole(element); + } + + Windows::UI::Xaml::DependencyProperty AccessibilityStateDisabledProperty() + { + return T::AccessibilityStateDisabledProperty(); + } + + void SetAccessibilityStateDisabled(Windows::UI::Xaml::UIElement const& element, bool value) + { + T::SetAccessibilityStateDisabled(element, value); + } + + bool GetAccessibilityStateDisabled(Windows::UI::Xaml::UIElement const& element) + { + return T::GetAccessibilityStateDisabled(element); + } + + Windows::UI::Xaml::DependencyProperty AccessibilityStateSelectedProperty() + { + return T::AccessibilityStateSelectedProperty(); + } + + void SetAccessibilityStateSelected(Windows::UI::Xaml::UIElement const& element, bool value) + { + T::SetAccessibilityStateSelected(element, value); + } + + bool GetAccessibilityStateSelected(Windows::UI::Xaml::UIElement const& element) + { + return T::GetAccessibilityStateSelected(element); + } + + Windows::UI::Xaml::DependencyProperty AccessibilityInvokeEventHandlerProperty() + { + return T::AccessibilityInvokeEventHandlerProperty(); + } + + void SetAccessibilityInvokeEventHandler(Windows::UI::Xaml::UIElement const& element, react::uwp::AccessibilityInvokeEventHandler const& value) + { + T::SetAccessibilityInvokeEventHandler(element, value); + } + + react::uwp::AccessibilityInvokeEventHandler GetAccessibilityInvokeEventHandler(Windows::UI::Xaml::UIElement const& element) + { + return T::GetAccessibilityInvokeEventHandler(element); + } +}; + +} + +#if defined(WINRT_FORCE_INCLUDE_DYNAMICAUTOMATIONPROPERTIES_XAML_G_H) || __has_include("DynamicAutomationProperties.xaml.g.h") + +#include "DynamicAutomationProperties.xaml.g.h" + +#else + +namespace winrt::react::uwp::implementation +{ + template + using DynamicAutomationPropertiesT = DynamicAutomationProperties_base; +} + +#endif diff --git a/vnext/ReactUWP/Views/cppwinrt/ViewControl.g.h b/vnext/ReactUWP/Views/cppwinrt/ViewControl.g.h new file mode 100644 index 00000000000..c448f99bcca --- /dev/null +++ b/vnext/ReactUWP/Views/cppwinrt/ViewControl.g.h @@ -0,0 +1,85 @@ +// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.190111.3 + +#pragma once + +#include "winrt/Windows.UI.Xaml.h" +#include "winrt/Windows.UI.Xaml.Automation.Provider.h" +#include "winrt/Windows.UI.Xaml.Controls.h" +#include "winrt/Windows.UI.Xaml.Media.h" +#include "winrt/Windows.UI.Composition.h" +#include "winrt/Windows.UI.Xaml.Automation.Peers.h" +#include "winrt/react.uwp.h" + +namespace winrt::react::uwp::implementation { + +template +struct WINRT_EBO ViewControl_base : implements, + impl::require, + impl::base, + Windows::UI::Xaml::Controls::IContentControlOverridesT, Windows::UI::Xaml::Controls::IControlOverridesT, Windows::UI::Xaml::Controls::IControlOverrides6T, Windows::UI::Xaml::IFrameworkElementOverridesT, Windows::UI::Xaml::IFrameworkElementOverrides2T, Windows::UI::Xaml::IUIElementOverridesT, Windows::UI::Xaml::IUIElementOverrides7T, Windows::UI::Xaml::IUIElementOverrides8T, Windows::UI::Xaml::IUIElementOverrides9T +{ + using base_type = ViewControl_base; + using class_type = react::uwp::ViewControl; + using implements_type = typename ViewControl_base::implements_type; + using implements_type::implements_type; + using composable_base = Windows::UI::Xaml::Controls::ContentControl; +#if _MSC_VER < 1914 + operator class_type() const noexcept + { + static_assert(std::is_same_v::type, default_interface>); + class_type result{ nullptr }; + attach_abi(result, detach_abi(static_cast>(*this))); + return result; + } +#else + operator impl::producer_ref const() const noexcept + { + return { to_abi>(this) }; + } +#endif + + hstring GetRuntimeClassName() const + { + return L"react.uwp.ViewControl"; + } + ViewControl_base() + { + impl::call_factory([&](auto&& f) { f.CreateInstance(*this, this->m_inner); }); + } +}; + +} + +namespace winrt::react::uwp::factory_implementation { + +template +struct WINRT_EBO ViewControlT : implements +{ + using instance_type = react::uwp::ViewControl; + + hstring GetRuntimeClassName() const + { + return L"react.uwp.ViewControl"; + } + + Windows::Foundation::IInspectable ActivateInstance() const + { + return make(); + } +}; + +} + +#if defined(WINRT_FORCE_INCLUDE_VIEWCONTROL_XAML_G_H) || __has_include("ViewControl.xaml.g.h") + +#include "ViewControl.xaml.g.h" + +#else + +namespace winrt::react::uwp::implementation +{ + template + using ViewControlT = ViewControl_base; +} + +#endif diff --git a/vnext/ReactUWP/Views/cppwinrt/ViewPanel.g.h b/vnext/ReactUWP/Views/cppwinrt/ViewPanel.g.h new file mode 100644 index 00000000000..3ba36fc29e3 --- /dev/null +++ b/vnext/ReactUWP/Views/cppwinrt/ViewPanel.g.h @@ -0,0 +1,140 @@ +// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.190111.3 + +#pragma once + +#include "winrt/Windows.UI.Xaml.h" +#include "winrt/Windows.UI.Xaml.Automation.Provider.h" +#include "winrt/Windows.UI.Xaml.Controls.h" +#include "winrt/Windows.UI.Xaml.Media.h" +#include "winrt/Windows.UI.Composition.h" +#include "winrt/Windows.UI.Xaml.Automation.Peers.h" +#include "winrt/react.uwp.h" + +namespace winrt::react::uwp::implementation { + +template +struct WINRT_EBO ViewPanel_base : implements, + impl::require, + impl::base, + Windows::UI::Xaml::IFrameworkElementOverridesT, Windows::UI::Xaml::IFrameworkElementOverrides2T, Windows::UI::Xaml::IUIElementOverridesT, Windows::UI::Xaml::IUIElementOverrides7T, Windows::UI::Xaml::IUIElementOverrides8T, Windows::UI::Xaml::IUIElementOverrides9T +{ + using base_type = ViewPanel_base; + using class_type = react::uwp::ViewPanel; + using implements_type = typename ViewPanel_base::implements_type; + using implements_type::implements_type; + using composable_base = Windows::UI::Xaml::Controls::Panel; +#if _MSC_VER < 1914 + operator class_type() const noexcept + { + static_assert(std::is_same_v::type, default_interface>); + class_type result{ nullptr }; + attach_abi(result, detach_abi(static_cast>(*this))); + return result; + } +#else + operator impl::producer_ref const() const noexcept + { + return { to_abi>(this) }; + } +#endif + + hstring GetRuntimeClassName() const + { + return L"react.uwp.ViewPanel"; + } + ViewPanel_base() + { + impl::call_factory([&](auto&& f) { f.CreateInstance(*this, this->m_inner); }); + } +}; + +} + +namespace winrt::react::uwp::factory_implementation { + +template +struct WINRT_EBO ViewPanelT : implements +{ + using instance_type = react::uwp::ViewPanel; + + hstring GetRuntimeClassName() const + { + return L"react.uwp.ViewPanel"; + } + + Windows::Foundation::IInspectable ActivateInstance() const + { + return make(); + } + + Windows::UI::Xaml::DependencyProperty ViewBackgroundProperty() + { + return T::ViewBackgroundProperty(); + } + + Windows::UI::Xaml::DependencyProperty BorderThicknessProperty() + { + return T::BorderThicknessProperty(); + } + + Windows::UI::Xaml::DependencyProperty BorderBrushProperty() + { + return T::BorderBrushProperty(); + } + + Windows::UI::Xaml::DependencyProperty CornerRadiusProperty() + { + return T::CornerRadiusProperty(); + } + + Windows::UI::Xaml::DependencyProperty ClipChildrenProperty() + { + return T::ClipChildrenProperty(); + } + + Windows::UI::Xaml::DependencyProperty TopProperty() + { + return T::TopProperty(); + } + + void SetTop(Windows::UI::Xaml::UIElement const& element, double value) + { + T::SetTop(element, value); + } + + double GetTop(Windows::UI::Xaml::UIElement const& element) + { + return T::GetTop(element); + } + + Windows::UI::Xaml::DependencyProperty LeftProperty() + { + return T::LeftProperty(); + } + + void SetLeft(Windows::UI::Xaml::UIElement const& element, double value) + { + T::SetLeft(element, value); + } + + double GetLeft(Windows::UI::Xaml::UIElement const& element) + { + return T::GetLeft(element); + } +}; + +} + +#if defined(WINRT_FORCE_INCLUDE_VIEWPANEL_XAML_G_H) || __has_include("ViewPanel.xaml.g.h") + +#include "ViewPanel.xaml.g.h" + +#else + +namespace winrt::react::uwp::implementation +{ + template + using ViewPanelT = ViewPanel_base; +} + +#endif diff --git a/vnext/ReactUWP/Views/cppwinrt/ViewPanel.idl b/vnext/ReactUWP/Views/cppwinrt/ViewPanel.idl new file mode 100644 index 00000000000..b3dcacfe96a --- /dev/null +++ b/vnext/ReactUWP/Views/cppwinrt/ViewPanel.idl @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// This file was used to generate the files in the cppwinrt subfolders +// +// If you modify this file, be sure to run buildcppwinrt.cmd in this folder +// to generate new headers + +import "DynamicAutomationPeer.idl"; + +namespace react.uwp +{ + [default_interface] + [webhosthidden] + runtimeclass ViewPanel : Windows.UI.Xaml.Controls.Panel + { + // Constructors + ViewPanel(); + + // Public Methods + void InsertAt(UInt32 index, Windows.UI.Xaml.UIElement value); + void RemoveAt(UInt32 index); + void Clear(); + + void FinalizeProperties(); + Windows.UI.Xaml.Controls.Border GetOuterBorder(); + + // Public Properties + Windows.UI.Xaml.Media.Brush ViewBackground { get; set; }; + Windows.UI.Xaml.Thickness BorderThickness { get; set; }; + Windows.UI.Xaml.Media.Brush BorderBrush { get; set; }; + Windows.UI.Xaml.CornerRadius CornerRadius { get; set; }; + Boolean ClipChildren { get; set; }; + + // ViewPanel Properties + static Windows.UI.Xaml.DependencyProperty ViewBackgroundProperty { get; }; + static Windows.UI.Xaml.DependencyProperty BorderThicknessProperty { get; }; + static Windows.UI.Xaml.DependencyProperty BorderBrushProperty { get; }; + static Windows.UI.Xaml.DependencyProperty CornerRadiusProperty { get; }; + static Windows.UI.Xaml.DependencyProperty ClipChildrenProperty { get; }; + + // Attached Properties + static Windows.UI.Xaml.DependencyProperty TopProperty { get; }; + static void SetTop(Windows.UI.Xaml.UIElement element, Double value); + static Double GetTop(Windows.UI.Xaml.UIElement element); + + static Windows.UI.Xaml.DependencyProperty LeftProperty { get; }; + static void SetLeft(Windows.UI.Xaml.UIElement element, Double value); + static Double GetLeft(Windows.UI.Xaml.UIElement element); + } + + [default_interface] + [webhosthidden] + runtimeclass ViewControl : Windows.UI.Xaml.Controls.ContentControl + { + ViewControl(); + + ViewPanel GetPanel(); + } +} diff --git a/vnext/ReactUWP/Views/cppwinrt/buildcppwinrt.cmd b/vnext/ReactUWP/Views/cppwinrt/buildcppwinrt.cmd new file mode 100644 index 00000000000..c75f24d3426 --- /dev/null +++ b/vnext/ReactUWP/Views/cppwinrt/buildcppwinrt.cmd @@ -0,0 +1,83 @@ +:: Copyright (c) Microsoft Corporation. All rights reserved. +:: Licensed under the MIT License. + +:: Until we get cppwinrt support properly included in ReactUWP, this script +:: will manually build the headers we need from each idl in this directory. + +@echo off +setlocal enabledelayedexpansion + +set TargetSDK=10.0.18362.0 + +set FoundationDir=%WindowsSdkDir%References\%TargetSDK%\Windows.Foundation.FoundationContract\3.0.0.0 +set FoundationRef=%FoundationDir%\Windows.Foundation.FoundationContract.winmd + +set UniversalApiDir=%WindowsSdkDir%References\%TargetSDK%\Windows.Foundation.UniversalApiContract\8.0.0.0 +set UniversalApiRef=%UniversalApiDir%\Windows.Foundation.UniversalApiContract.winmd + +pushd %~dp0 + +call :GetAbsolute "..\..\..\target\cppwinrt" +set TargetDir=%absolute% + +echo. +echo ### Initializing target dir ### +echo. +if not exist "%TargetDir%" call mkdir "%TargetDir%" +if exist "%TargetDir%" call del /s /q "%TargetDir%\*" + +echo. +echo ### Building winmds from idls ### +echo. + +for %%f in (*.idl) do ( + call :BuildWinmd %%f +) + +echo. +echo ### Merge winmds ### +echo. +if not exist "%TargetDir%\merged" call mkdir "%TargetDir%\merged" +call mdmerge -metadata_dir "%FoundationDir%\." -metadata_dir "%UniversalApiDir%\." -o "%TargetDir%\merged" -i "%TargetDir%" -partial + +echo. +echo ### Building headers from winmds ### + +for %%w in ("%TargetDir%\merged\*.winmd") do ( + call :BuildHeaders %%w +) + +echo. +echo ### Copy generated files into ReactUWP ### +echo. +call xcopy /Y "%TargetDir%\*.h" .\ +call xcopy /Y "%TargetDir%\winrt\*.h" .\winrt\ +call xcopy /Y "%TargetDir%\winrt\impl\*.h" .\winrt\impl\ +call xcopy /Y "%TargetDir%\module.g.cpp" ..\ + +echo. +echo ### Stubbed out implmentations (*.h and *. cpp) are in "%TargetDir%\sources" ### +echo. + +popd +goto :end + +:BuildWinmd +echo. +echo Building winmd for "%~1" +call midlrt /metadata_dir "%FoundationDir%" /winrt /W1 /nologo /char signed /env win32 /nomidl /ns_prefix /enum_class /h "NUL" /dlldata "NUL" /iid "NUL" /proxy "NUL" /notlb /client none /server none /target "NT60" /reference "%FoundationRef%" /reference "%UniversalApiRef%" /winmd "%TargetDir%\%~n1.winmd" %~1 +exit /b + +:BuildHeaders +echo. +echo Building headers for "%~1" +call cppwinrt -overwrite -prefix -comp "%TargetDir%\sources" -in "%~1" -ref %TargetSDK% -out %TargetDir% +exit /b + +:GetAbsolute +set absolute=%~f1 +exit /b + +:end +endlocal +exit /b \ No newline at end of file diff --git a/vnext/ReactUWP/Views/cppwinrt/reactuwp.idl b/vnext/ReactUWP/Views/cppwinrt/reactuwp.idl deleted file mode 100644 index 72e9f702277..00000000000 --- a/vnext/ReactUWP/Views/cppwinrt/reactuwp.idl +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// This file was used to generate the files in the cppwinrt subfolders -// -// in the future this should be run through cppwinrt.exe but thats not currently -// possible with the multiple build systems react uwp needs to support. - -namespace react.uwp -{ - [default_interface] - runtimeclass DynamicAutomationPeer : - Windows.UI.Xaml.Automation.Peers.FrameworkElementAutomationPeer, - Windows.UI.Xaml.Automation.Provider.IInvokeProvider - { - DynamicAutomationPeer(Windows.UI.Xaml.FrameworkElement owner); - } -} diff --git a/vnext/ReactUWP/Views/cppwinrt/winrt/Microsoft.UI.Composition.Effects.h b/vnext/ReactUWP/Views/cppwinrt/winrt/Microsoft.UI.Composition.Effects.h index 74807d7bbb1..8e23dd1d685 100644 --- a/vnext/ReactUWP/Views/cppwinrt/winrt/Microsoft.UI.Composition.Effects.h +++ b/vnext/ReactUWP/Views/cppwinrt/winrt/Microsoft.UI.Composition.Effects.h @@ -1,12 +1,11 @@ -// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.180821.2 +// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.190111.3 #pragma once #include "winrt/base.h" -#ifndef OLD_CPPWINRT -static_assert(winrt::check_version(CPPWINRT_VERSION, "1.0.180821.2"), "Mismatched component and base headers."); -#endif + +static_assert(winrt::check_version(CPPWINRT_VERSION, "1.0.190111.3"), "Mismatched component and base headers."); #include "winrt/Windows.Foundation.h" #include "winrt/Windows.Foundation.Collections.h" #include "winrt/impl/Windows.Graphics.Effects.2.h" diff --git a/vnext/ReactUWP/Views/cppwinrt/winrt/impl/Microsoft.UI.Composition.Effects.0.h b/vnext/ReactUWP/Views/cppwinrt/winrt/impl/Microsoft.UI.Composition.Effects.0.h index e9170387437..1758fc5efa0 100644 --- a/vnext/ReactUWP/Views/cppwinrt/winrt/impl/Microsoft.UI.Composition.Effects.0.h +++ b/vnext/ReactUWP/Views/cppwinrt/winrt/impl/Microsoft.UI.Composition.Effects.0.h @@ -1,4 +1,4 @@ -// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.180821.2 +// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.190111.3 #pragma once diff --git a/vnext/ReactUWP/Views/cppwinrt/winrt/impl/Microsoft.UI.Composition.Effects.1.h b/vnext/ReactUWP/Views/cppwinrt/winrt/impl/Microsoft.UI.Composition.Effects.1.h index e1937a49e98..fb82e5ceed4 100644 --- a/vnext/ReactUWP/Views/cppwinrt/winrt/impl/Microsoft.UI.Composition.Effects.1.h +++ b/vnext/ReactUWP/Views/cppwinrt/winrt/impl/Microsoft.UI.Composition.Effects.1.h @@ -1,4 +1,4 @@ -// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.180821.2 +// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.190111.3 #pragma once #include "winrt/impl/Windows.Graphics.Effects.0.h" diff --git a/vnext/ReactUWP/Views/cppwinrt/winrt/impl/Microsoft.UI.Composition.Effects.2.h b/vnext/ReactUWP/Views/cppwinrt/winrt/impl/Microsoft.UI.Composition.Effects.2.h index 402bcd08ece..e427ddc1baf 100644 --- a/vnext/ReactUWP/Views/cppwinrt/winrt/impl/Microsoft.UI.Composition.Effects.2.h +++ b/vnext/ReactUWP/Views/cppwinrt/winrt/impl/Microsoft.UI.Composition.Effects.2.h @@ -1,4 +1,4 @@ -// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.180821.2 +// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.190111.3 #pragma once #include "winrt/impl/Windows.Graphics.Effects.1.h" diff --git a/vnext/ReactUWP/Views/cppwinrt/winrt/impl/react.uwp.0.h b/vnext/ReactUWP/Views/cppwinrt/winrt/impl/react.uwp.0.h index 3c5a6abdf3e..20b1694bc5b 100644 --- a/vnext/ReactUWP/Views/cppwinrt/winrt/impl/react.uwp.0.h +++ b/vnext/ReactUWP/Views/cppwinrt/winrt/impl/react.uwp.0.h @@ -1,18 +1,73 @@ -// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.180821.2 +// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.190111.3 #pragma once WINRT_EXPORT namespace winrt::Windows::UI::Xaml { +struct CornerRadius; +struct DependencyProperty; struct FrameworkElement; +struct Thickness; +struct UIElement; + +} + +WINRT_EXPORT namespace winrt::Windows::UI::Xaml::Automation::Provider { + +struct IRawElementProviderSimple; + +} + +WINRT_EXPORT namespace winrt::Windows::UI::Xaml::Controls { + +struct Border; + +} + +WINRT_EXPORT namespace winrt::Windows::UI::Xaml::Media { + +struct Brush; } WINRT_EXPORT namespace winrt::react::uwp { +enum class AccessibilityRoles : int32_t +{ + None = 0, + Button = 1, + Link = 2, + Search = 3, + Image = 4, + KeyboardKey = 5, + Text = 6, + Adjustable = 7, + ImageButton = 8, + Header = 9, + Summary = 10, + Unknown = 11, + CountRoles = 12, +}; + +enum class AccessibilityStates : int32_t +{ + Selected = 0, + Disabled = 1, + CountStates = 2, +}; + struct IDynamicAutomationPeer; struct IDynamicAutomationPeerFactory; +struct IDynamicAutomationProperties; +struct IDynamicAutomationPropertiesStatics; +struct IViewControl; +struct IViewPanel; +struct IViewPanelStatics; struct DynamicAutomationPeer; +struct DynamicAutomationProperties; +struct ViewControl; +struct ViewPanel; +struct AccessibilityInvokeEventHandler; } @@ -20,13 +75,44 @@ namespace winrt::impl { template <> struct category{ using type = interface_category; }; template <> struct category{ using type = interface_category; }; +template <> struct category{ using type = interface_category; }; +template <> struct category{ using type = interface_category; }; +template <> struct category{ using type = interface_category; }; +template <> struct category{ using type = interface_category; }; +template <> struct category{ using type = interface_category; }; template <> struct category{ using type = class_category; }; +template <> struct category{ using type = class_category; }; +template <> struct category{ using type = class_category; }; +template <> struct category{ using type = class_category; }; +template <> struct category{ using type = enum_category; }; +template <> struct category{ using type = enum_category; }; +template <> struct category{ using type = delegate_category; }; template <> struct name{ static constexpr auto & value{ L"react.uwp.IDynamicAutomationPeer" }; }; template <> struct name{ static constexpr auto & value{ L"react.uwp.IDynamicAutomationPeerFactory" }; }; +template <> struct name{ static constexpr auto & value{ L"react.uwp.IDynamicAutomationProperties" }; }; +template <> struct name{ static constexpr auto & value{ L"react.uwp.IDynamicAutomationPropertiesStatics" }; }; +template <> struct name{ static constexpr auto & value{ L"react.uwp.IViewControl" }; }; +template <> struct name{ static constexpr auto & value{ L"react.uwp.IViewPanel" }; }; +template <> struct name{ static constexpr auto & value{ L"react.uwp.IViewPanelStatics" }; }; template <> struct name{ static constexpr auto & value{ L"react.uwp.DynamicAutomationPeer" }; }; +template <> struct name{ static constexpr auto & value{ L"react.uwp.DynamicAutomationProperties" }; }; +template <> struct name{ static constexpr auto & value{ L"react.uwp.ViewControl" }; }; +template <> struct name{ static constexpr auto & value{ L"react.uwp.ViewPanel" }; }; +template <> struct name{ static constexpr auto & value{ L"react.uwp.AccessibilityRoles" }; }; +template <> struct name{ static constexpr auto & value{ L"react.uwp.AccessibilityStates" }; }; +template <> struct name{ static constexpr auto & value{ L"react.uwp.AccessibilityInvokeEventHandler" }; }; template <> struct guid_storage{ static constexpr guid value{ 0x96D2FA46,0xD93B,0x5EB4,{ 0x9E,0xD8,0xFC,0x60,0x2C,0xB5,0xB7,0x8F } }; }; template <> struct guid_storage{ static constexpr guid value{ 0x0F0A64B1,0xCCEF,0x54F1,{ 0xB9,0x05,0x0C,0x58,0x26,0xCB,0x6C,0xC4 } }; }; +template <> struct guid_storage{ static constexpr guid value{ 0xB70AAC96,0x549C,0x52C1,{ 0xA1,0x24,0xAE,0x0C,0xA4,0x96,0xC8,0x05 } }; }; +template <> struct guid_storage{ static constexpr guid value{ 0xA92AD1FD,0xB630,0x5CDB,{ 0x85,0x61,0x9F,0xEC,0xEC,0xA8,0xB9,0x66 } }; }; +template <> struct guid_storage{ static constexpr guid value{ 0xDD899021,0xA952,0x5F5A,{ 0xA5,0xC1,0xAC,0x9E,0x85,0x08,0x09,0xBD } }; }; +template <> struct guid_storage{ static constexpr guid value{ 0x46487875,0x5C11,0x5EBE,{ 0xAA,0x1A,0xC7,0xC9,0x70,0xCF,0x46,0x02 } }; }; +template <> struct guid_storage{ static constexpr guid value{ 0xF820A53A,0x6DFD,0x53F9,{ 0xA1,0x96,0x40,0xA4,0xED,0x81,0x8B,0x80 } }; }; +template <> struct guid_storage{ static constexpr guid value{ 0xCF396F1D,0x7B41,0x5E44,{ 0xB2,0xD5,0xBA,0xB5,0x86,0xC7,0xEE,0x33 } }; }; template <> struct default_interface{ using type = react::uwp::IDynamicAutomationPeer; }; +template <> struct default_interface{ using type = react::uwp::IDynamicAutomationProperties; }; +template <> struct default_interface{ using type = react::uwp::IViewControl; }; +template <> struct default_interface{ using type = react::uwp::IViewPanel; }; template <> struct abi{ struct type : IInspectable { @@ -37,6 +123,70 @@ template <> struct abi{ struct type : virtual int32_t WINRT_CALL CreateInstance(void* owner, void** value) noexcept = 0; };}; +template <> struct abi{ struct type : IInspectable +{ +};}; + +template <> struct abi{ struct type : IInspectable +{ + virtual int32_t WINRT_CALL get_AccessibilityRoleProperty(void** value) noexcept = 0; + virtual int32_t WINRT_CALL SetAccessibilityRole(void* element, react::uwp::AccessibilityRoles value) noexcept = 0; + virtual int32_t WINRT_CALL GetAccessibilityRole(void* element, react::uwp::AccessibilityRoles* result) noexcept = 0; + virtual int32_t WINRT_CALL get_AccessibilityStateDisabledProperty(void** value) noexcept = 0; + virtual int32_t WINRT_CALL SetAccessibilityStateDisabled(void* element, bool value) noexcept = 0; + virtual int32_t WINRT_CALL GetAccessibilityStateDisabled(void* element, bool* result) noexcept = 0; + virtual int32_t WINRT_CALL get_AccessibilityStateSelectedProperty(void** value) noexcept = 0; + virtual int32_t WINRT_CALL SetAccessibilityStateSelected(void* element, bool value) noexcept = 0; + virtual int32_t WINRT_CALL GetAccessibilityStateSelected(void* element, bool* result) noexcept = 0; + virtual int32_t WINRT_CALL get_AccessibilityInvokeEventHandlerProperty(void** value) noexcept = 0; + virtual int32_t WINRT_CALL SetAccessibilityInvokeEventHandler(void* element, void* value) noexcept = 0; + virtual int32_t WINRT_CALL GetAccessibilityInvokeEventHandler(void* element, void** result) noexcept = 0; +};}; + +template <> struct abi{ struct type : IInspectable +{ + virtual int32_t WINRT_CALL GetPanel(void** result) noexcept = 0; +};}; + +template <> struct abi{ struct type : IInspectable +{ + virtual int32_t WINRT_CALL InsertAt(uint32_t index, void* value) noexcept = 0; + virtual int32_t WINRT_CALL RemoveAt(uint32_t index) noexcept = 0; + virtual int32_t WINRT_CALL Clear() noexcept = 0; + virtual int32_t WINRT_CALL FinalizeProperties() noexcept = 0; + virtual int32_t WINRT_CALL GetOuterBorder(void** result) noexcept = 0; + virtual int32_t WINRT_CALL get_ViewBackground(void** value) noexcept = 0; + virtual int32_t WINRT_CALL put_ViewBackground(void* value) noexcept = 0; + virtual int32_t WINRT_CALL get_BorderThickness(struct struct_Windows_UI_Xaml_Thickness* value) noexcept = 0; + virtual int32_t WINRT_CALL put_BorderThickness(struct struct_Windows_UI_Xaml_Thickness value) noexcept = 0; + virtual int32_t WINRT_CALL get_BorderBrush(void** value) noexcept = 0; + virtual int32_t WINRT_CALL put_BorderBrush(void* value) noexcept = 0; + virtual int32_t WINRT_CALL get_CornerRadius(struct struct_Windows_UI_Xaml_CornerRadius* value) noexcept = 0; + virtual int32_t WINRT_CALL put_CornerRadius(struct struct_Windows_UI_Xaml_CornerRadius value) noexcept = 0; + virtual int32_t WINRT_CALL get_ClipChildren(bool* value) noexcept = 0; + virtual int32_t WINRT_CALL put_ClipChildren(bool value) noexcept = 0; +};}; + +template <> struct abi{ struct type : IInspectable +{ + virtual int32_t WINRT_CALL get_ViewBackgroundProperty(void** value) noexcept = 0; + virtual int32_t WINRT_CALL get_BorderThicknessProperty(void** value) noexcept = 0; + virtual int32_t WINRT_CALL get_BorderBrushProperty(void** value) noexcept = 0; + virtual int32_t WINRT_CALL get_CornerRadiusProperty(void** value) noexcept = 0; + virtual int32_t WINRT_CALL get_ClipChildrenProperty(void** value) noexcept = 0; + virtual int32_t WINRT_CALL get_TopProperty(void** value) noexcept = 0; + virtual int32_t WINRT_CALL SetTop(void* element, double value) noexcept = 0; + virtual int32_t WINRT_CALL GetTop(void* element, double* result) noexcept = 0; + virtual int32_t WINRT_CALL get_LeftProperty(void** value) noexcept = 0; + virtual int32_t WINRT_CALL SetLeft(void* element, double value) noexcept = 0; + virtual int32_t WINRT_CALL GetLeft(void* element, double* result) noexcept = 0; +};}; + +template <> struct abi{ struct type : IUnknown +{ + virtual int32_t WINRT_CALL Invoke() noexcept = 0; +};}; + template struct consume_react_uwp_IDynamicAutomationPeer { @@ -50,4 +200,73 @@ struct consume_react_uwp_IDynamicAutomationPeerFactory }; template <> struct consume { template using type = consume_react_uwp_IDynamicAutomationPeerFactory; }; +template +struct consume_react_uwp_IDynamicAutomationProperties +{ +}; +template <> struct consume { template using type = consume_react_uwp_IDynamicAutomationProperties; }; + +template +struct consume_react_uwp_IDynamicAutomationPropertiesStatics +{ + Windows::UI::Xaml::DependencyProperty AccessibilityRoleProperty() const; + void SetAccessibilityRole(Windows::UI::Xaml::UIElement const& element, react::uwp::AccessibilityRoles const& value) const; + react::uwp::AccessibilityRoles GetAccessibilityRole(Windows::UI::Xaml::UIElement const& element) const; + Windows::UI::Xaml::DependencyProperty AccessibilityStateDisabledProperty() const; + void SetAccessibilityStateDisabled(Windows::UI::Xaml::UIElement const& element, bool value) const; + bool GetAccessibilityStateDisabled(Windows::UI::Xaml::UIElement const& element) const; + Windows::UI::Xaml::DependencyProperty AccessibilityStateSelectedProperty() const; + void SetAccessibilityStateSelected(Windows::UI::Xaml::UIElement const& element, bool value) const; + bool GetAccessibilityStateSelected(Windows::UI::Xaml::UIElement const& element) const; + Windows::UI::Xaml::DependencyProperty AccessibilityInvokeEventHandlerProperty() const; + void SetAccessibilityInvokeEventHandler(Windows::UI::Xaml::UIElement const& element, react::uwp::AccessibilityInvokeEventHandler const& value) const; + react::uwp::AccessibilityInvokeEventHandler GetAccessibilityInvokeEventHandler(Windows::UI::Xaml::UIElement const& element) const; +}; +template <> struct consume { template using type = consume_react_uwp_IDynamicAutomationPropertiesStatics; }; + +template +struct consume_react_uwp_IViewControl +{ + react::uwp::ViewPanel GetPanel() const; +}; +template <> struct consume { template using type = consume_react_uwp_IViewControl; }; + +template +struct consume_react_uwp_IViewPanel +{ + void InsertAt(uint32_t index, Windows::UI::Xaml::UIElement const& value) const; + void RemoveAt(uint32_t index) const; + void Clear() const; + void FinalizeProperties() const; + Windows::UI::Xaml::Controls::Border GetOuterBorder() const; + Windows::UI::Xaml::Media::Brush ViewBackground() const; + void ViewBackground(Windows::UI::Xaml::Media::Brush const& value) const; + Windows::UI::Xaml::Thickness BorderThickness() const; + void BorderThickness(Windows::UI::Xaml::Thickness const& value) const; + Windows::UI::Xaml::Media::Brush BorderBrush() const; + void BorderBrush(Windows::UI::Xaml::Media::Brush const& value) const; + Windows::UI::Xaml::CornerRadius CornerRadius() const; + void CornerRadius(Windows::UI::Xaml::CornerRadius const& value) const; + bool ClipChildren() const; + void ClipChildren(bool value) const; +}; +template <> struct consume { template using type = consume_react_uwp_IViewPanel; }; + +template +struct consume_react_uwp_IViewPanelStatics +{ + Windows::UI::Xaml::DependencyProperty ViewBackgroundProperty() const; + Windows::UI::Xaml::DependencyProperty BorderThicknessProperty() const; + Windows::UI::Xaml::DependencyProperty BorderBrushProperty() const; + Windows::UI::Xaml::DependencyProperty CornerRadiusProperty() const; + Windows::UI::Xaml::DependencyProperty ClipChildrenProperty() const; + Windows::UI::Xaml::DependencyProperty TopProperty() const; + void SetTop(Windows::UI::Xaml::UIElement const& element, double value) const; + double GetTop(Windows::UI::Xaml::UIElement const& element) const; + Windows::UI::Xaml::DependencyProperty LeftProperty() const; + void SetLeft(Windows::UI::Xaml::UIElement const& element, double value) const; + double GetLeft(Windows::UI::Xaml::UIElement const& element) const; +}; +template <> struct consume { template using type = consume_react_uwp_IViewPanelStatics; }; + } diff --git a/vnext/ReactUWP/Views/cppwinrt/winrt/impl/react.uwp.1.h b/vnext/ReactUWP/Views/cppwinrt/winrt/impl/react.uwp.1.h index 554da7aca6d..f814999f234 100644 --- a/vnext/ReactUWP/Views/cppwinrt/winrt/impl/react.uwp.1.h +++ b/vnext/ReactUWP/Views/cppwinrt/winrt/impl/react.uwp.1.h @@ -1,9 +1,12 @@ -// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.180821.2 +// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.190111.3 #pragma once #include "winrt/impl/Windows.UI.Xaml.0.h" -#include "winrt/impl/Windows.UI.Xaml.Automation.Peers.0.h" #include "winrt/impl/Windows.UI.Xaml.Automation.Provider.0.h" +#include "winrt/impl/Windows.UI.Xaml.Controls.0.h" +#include "winrt/impl/Windows.UI.Xaml.Media.0.h" +#include "winrt/impl/Windows.UI.Composition.0.h" +#include "winrt/impl/Windows.UI.Xaml.Automation.Peers.0.h" #include "winrt/impl/react.uwp.0.h" WINRT_EXPORT namespace winrt::react::uwp { @@ -22,4 +25,39 @@ struct WINRT_EBO IDynamicAutomationPeerFactory : IDynamicAutomationPeerFactory(std::nullptr_t = nullptr) noexcept {} }; +struct WINRT_EBO IDynamicAutomationProperties : + Windows::Foundation::IInspectable, + impl::consume_t +{ + IDynamicAutomationProperties(std::nullptr_t = nullptr) noexcept {} +}; + +struct WINRT_EBO IDynamicAutomationPropertiesStatics : + Windows::Foundation::IInspectable, + impl::consume_t +{ + IDynamicAutomationPropertiesStatics(std::nullptr_t = nullptr) noexcept {} +}; + +struct WINRT_EBO IViewControl : + Windows::Foundation::IInspectable, + impl::consume_t +{ + IViewControl(std::nullptr_t = nullptr) noexcept {} +}; + +struct WINRT_EBO IViewPanel : + Windows::Foundation::IInspectable, + impl::consume_t +{ + IViewPanel(std::nullptr_t = nullptr) noexcept {} +}; + +struct WINRT_EBO IViewPanelStatics : + Windows::Foundation::IInspectable, + impl::consume_t +{ + IViewPanelStatics(std::nullptr_t = nullptr) noexcept {} +}; + } diff --git a/vnext/ReactUWP/Views/cppwinrt/winrt/impl/react.uwp.2.h b/vnext/ReactUWP/Views/cppwinrt/winrt/impl/react.uwp.2.h index 90dd61ed04f..9417a19af89 100644 --- a/vnext/ReactUWP/Views/cppwinrt/winrt/impl/react.uwp.2.h +++ b/vnext/ReactUWP/Views/cppwinrt/winrt/impl/react.uwp.2.h @@ -1,13 +1,27 @@ -// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.180821.2 +// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.190111.3 #pragma once #include "winrt/impl/Windows.UI.Xaml.1.h" -#include "winrt/impl/Windows.UI.Xaml.Automation.Peers.1.h" #include "winrt/impl/Windows.UI.Xaml.Automation.Provider.1.h" +#include "winrt/impl/Windows.UI.Xaml.Controls.1.h" +#include "winrt/impl/Windows.UI.Xaml.Media.1.h" +#include "winrt/impl/Windows.UI.Composition.1.h" +#include "winrt/impl/Windows.UI.Xaml.Automation.Peers.1.h" #include "winrt/impl/react.uwp.1.h" WINRT_EXPORT namespace winrt::react::uwp { +struct AccessibilityInvokeEventHandler : Windows::Foundation::IUnknown +{ + AccessibilityInvokeEventHandler(std::nullptr_t = nullptr) noexcept {} + template AccessibilityInvokeEventHandler(L lambda); + template AccessibilityInvokeEventHandler(F* function); + template AccessibilityInvokeEventHandler(O* object, M method); + template AccessibilityInvokeEventHandler(com_ptr&& object, M method); + template AccessibilityInvokeEventHandler(weak_ref&& object, M method); + void operator()() const; +}; + } namespace winrt::impl { @@ -19,10 +33,57 @@ WINRT_EXPORT namespace winrt::react::uwp { struct WINRT_EBO DynamicAutomationPeer : react::uwp::IDynamicAutomationPeer, impl::base, - impl::require + impl::require { DynamicAutomationPeer(std::nullptr_t) noexcept {} DynamicAutomationPeer(Windows::UI::Xaml::FrameworkElement const& owner); }; +struct WINRT_EBO DynamicAutomationProperties : + react::uwp::IDynamicAutomationProperties +{ + DynamicAutomationProperties(std::nullptr_t) noexcept {} + static Windows::UI::Xaml::DependencyProperty AccessibilityRoleProperty(); + static void SetAccessibilityRole(Windows::UI::Xaml::UIElement const& element, react::uwp::AccessibilityRoles const& value); + static react::uwp::AccessibilityRoles GetAccessibilityRole(Windows::UI::Xaml::UIElement const& element); + static Windows::UI::Xaml::DependencyProperty AccessibilityStateDisabledProperty(); + static void SetAccessibilityStateDisabled(Windows::UI::Xaml::UIElement const& element, bool value); + static bool GetAccessibilityStateDisabled(Windows::UI::Xaml::UIElement const& element); + static Windows::UI::Xaml::DependencyProperty AccessibilityStateSelectedProperty(); + static void SetAccessibilityStateSelected(Windows::UI::Xaml::UIElement const& element, bool value); + static bool GetAccessibilityStateSelected(Windows::UI::Xaml::UIElement const& element); + static Windows::UI::Xaml::DependencyProperty AccessibilityInvokeEventHandlerProperty(); + static void SetAccessibilityInvokeEventHandler(Windows::UI::Xaml::UIElement const& element, react::uwp::AccessibilityInvokeEventHandler const& value); + static react::uwp::AccessibilityInvokeEventHandler GetAccessibilityInvokeEventHandler(Windows::UI::Xaml::UIElement const& element); +}; + +struct WINRT_EBO ViewControl : + react::uwp::IViewControl, + impl::base, + impl::require +{ + ViewControl(std::nullptr_t) noexcept {} + ViewControl(); +}; + +struct WINRT_EBO ViewPanel : + react::uwp::IViewPanel, + impl::base, + impl::require +{ + ViewPanel(std::nullptr_t) noexcept {} + ViewPanel(); + static Windows::UI::Xaml::DependencyProperty ViewBackgroundProperty(); + static Windows::UI::Xaml::DependencyProperty BorderThicknessProperty(); + static Windows::UI::Xaml::DependencyProperty BorderBrushProperty(); + static Windows::UI::Xaml::DependencyProperty CornerRadiusProperty(); + static Windows::UI::Xaml::DependencyProperty ClipChildrenProperty(); + static Windows::UI::Xaml::DependencyProperty TopProperty(); + static void SetTop(Windows::UI::Xaml::UIElement const& element, double value); + static double GetTop(Windows::UI::Xaml::UIElement const& element); + static Windows::UI::Xaml::DependencyProperty LeftProperty(); + static void SetLeft(Windows::UI::Xaml::UIElement const& element, double value); + static double GetLeft(Windows::UI::Xaml::UIElement const& element); +}; + } diff --git a/vnext/ReactUWP/Views/cppwinrt/winrt/react.uwp.h b/vnext/ReactUWP/Views/cppwinrt/winrt/react.uwp.h index ef33ee94c47..f03a55dd876 100644 --- a/vnext/ReactUWP/Views/cppwinrt/winrt/react.uwp.h +++ b/vnext/ReactUWP/Views/cppwinrt/winrt/react.uwp.h @@ -1,17 +1,19 @@ -// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.180821.2 +// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.190111.3 #pragma once #include "winrt/base.h" -#ifndef OLD_CPPWINRT -static_assert(winrt::check_version(CPPWINRT_VERSION, "1.0.180821.2"), "Mismatched component and base headers."); -#endif + +static_assert(winrt::check_version(CPPWINRT_VERSION, "1.0.190111.3"), "Mismatched component and base headers."); #include "winrt/Windows.Foundation.h" #include "winrt/Windows.Foundation.Collections.h" #include "winrt/impl/Windows.UI.Xaml.2.h" -#include "winrt/impl/Windows.UI.Xaml.Automation.Peers.2.h" #include "winrt/impl/Windows.UI.Xaml.Automation.Provider.2.h" +#include "winrt/impl/Windows.UI.Xaml.Controls.2.h" +#include "winrt/impl/Windows.UI.Xaml.Media.2.h" +#include "winrt/impl/Windows.UI.Composition.2.h" +#include "winrt/impl/Windows.UI.Xaml.Automation.Peers.2.h" #include "winrt/impl/react.uwp.2.h" namespace winrt::impl { @@ -23,6 +25,271 @@ template react::uwp::DynamicAutomationPeer consume_react_uwp_IDynam return value; } +template Windows::UI::Xaml::DependencyProperty consume_react_uwp_IDynamicAutomationPropertiesStatics::AccessibilityRoleProperty() const +{ + Windows::UI::Xaml::DependencyProperty value{ nullptr }; + check_hresult(WINRT_SHIM(react::uwp::IDynamicAutomationPropertiesStatics)->get_AccessibilityRoleProperty(put_abi(value))); + return value; +} + +template void consume_react_uwp_IDynamicAutomationPropertiesStatics::SetAccessibilityRole(Windows::UI::Xaml::UIElement const& element, react::uwp::AccessibilityRoles const& value) const +{ + check_hresult(WINRT_SHIM(react::uwp::IDynamicAutomationPropertiesStatics)->SetAccessibilityRole(get_abi(element), get_abi(value))); +} + +template react::uwp::AccessibilityRoles consume_react_uwp_IDynamicAutomationPropertiesStatics::GetAccessibilityRole(Windows::UI::Xaml::UIElement const& element) const +{ + react::uwp::AccessibilityRoles result{}; + check_hresult(WINRT_SHIM(react::uwp::IDynamicAutomationPropertiesStatics)->GetAccessibilityRole(get_abi(element), put_abi(result))); + return result; +} + +template Windows::UI::Xaml::DependencyProperty consume_react_uwp_IDynamicAutomationPropertiesStatics::AccessibilityStateDisabledProperty() const +{ + Windows::UI::Xaml::DependencyProperty value{ nullptr }; + check_hresult(WINRT_SHIM(react::uwp::IDynamicAutomationPropertiesStatics)->get_AccessibilityStateDisabledProperty(put_abi(value))); + return value; +} + +template void consume_react_uwp_IDynamicAutomationPropertiesStatics::SetAccessibilityStateDisabled(Windows::UI::Xaml::UIElement const& element, bool value) const +{ + check_hresult(WINRT_SHIM(react::uwp::IDynamicAutomationPropertiesStatics)->SetAccessibilityStateDisabled(get_abi(element), value)); +} + +template bool consume_react_uwp_IDynamicAutomationPropertiesStatics::GetAccessibilityStateDisabled(Windows::UI::Xaml::UIElement const& element) const +{ + bool result{}; + check_hresult(WINRT_SHIM(react::uwp::IDynamicAutomationPropertiesStatics)->GetAccessibilityStateDisabled(get_abi(element), &result)); + return result; +} + +template Windows::UI::Xaml::DependencyProperty consume_react_uwp_IDynamicAutomationPropertiesStatics::AccessibilityStateSelectedProperty() const +{ + Windows::UI::Xaml::DependencyProperty value{ nullptr }; + check_hresult(WINRT_SHIM(react::uwp::IDynamicAutomationPropertiesStatics)->get_AccessibilityStateSelectedProperty(put_abi(value))); + return value; +} + +template void consume_react_uwp_IDynamicAutomationPropertiesStatics::SetAccessibilityStateSelected(Windows::UI::Xaml::UIElement const& element, bool value) const +{ + check_hresult(WINRT_SHIM(react::uwp::IDynamicAutomationPropertiesStatics)->SetAccessibilityStateSelected(get_abi(element), value)); +} + +template bool consume_react_uwp_IDynamicAutomationPropertiesStatics::GetAccessibilityStateSelected(Windows::UI::Xaml::UIElement const& element) const +{ + bool result{}; + check_hresult(WINRT_SHIM(react::uwp::IDynamicAutomationPropertiesStatics)->GetAccessibilityStateSelected(get_abi(element), &result)); + return result; +} + +template Windows::UI::Xaml::DependencyProperty consume_react_uwp_IDynamicAutomationPropertiesStatics::AccessibilityInvokeEventHandlerProperty() const +{ + Windows::UI::Xaml::DependencyProperty value{ nullptr }; + check_hresult(WINRT_SHIM(react::uwp::IDynamicAutomationPropertiesStatics)->get_AccessibilityInvokeEventHandlerProperty(put_abi(value))); + return value; +} + +template void consume_react_uwp_IDynamicAutomationPropertiesStatics::SetAccessibilityInvokeEventHandler(Windows::UI::Xaml::UIElement const& element, react::uwp::AccessibilityInvokeEventHandler const& value) const +{ + check_hresult(WINRT_SHIM(react::uwp::IDynamicAutomationPropertiesStatics)->SetAccessibilityInvokeEventHandler(get_abi(element), get_abi(value))); +} + +template react::uwp::AccessibilityInvokeEventHandler consume_react_uwp_IDynamicAutomationPropertiesStatics::GetAccessibilityInvokeEventHandler(Windows::UI::Xaml::UIElement const& element) const +{ + react::uwp::AccessibilityInvokeEventHandler result{ nullptr }; + check_hresult(WINRT_SHIM(react::uwp::IDynamicAutomationPropertiesStatics)->GetAccessibilityInvokeEventHandler(get_abi(element), put_abi(result))); + return result; +} + +template react::uwp::ViewPanel consume_react_uwp_IViewControl::GetPanel() const +{ + react::uwp::ViewPanel result{ nullptr }; + check_hresult(WINRT_SHIM(react::uwp::IViewControl)->GetPanel(put_abi(result))); + return result; +} + +template void consume_react_uwp_IViewPanel::InsertAt(uint32_t index, Windows::UI::Xaml::UIElement const& value) const +{ + check_hresult(WINRT_SHIM(react::uwp::IViewPanel)->InsertAt(index, get_abi(value))); +} + +template void consume_react_uwp_IViewPanel::RemoveAt(uint32_t index) const +{ + check_hresult(WINRT_SHIM(react::uwp::IViewPanel)->RemoveAt(index)); +} + +template void consume_react_uwp_IViewPanel::Clear() const +{ + check_hresult(WINRT_SHIM(react::uwp::IViewPanel)->Clear()); +} + +template void consume_react_uwp_IViewPanel::FinalizeProperties() const +{ + check_hresult(WINRT_SHIM(react::uwp::IViewPanel)->FinalizeProperties()); +} + +template Windows::UI::Xaml::Controls::Border consume_react_uwp_IViewPanel::GetOuterBorder() const +{ + Windows::UI::Xaml::Controls::Border result{ nullptr }; + check_hresult(WINRT_SHIM(react::uwp::IViewPanel)->GetOuterBorder(put_abi(result))); + return result; +} + +template Windows::UI::Xaml::Media::Brush consume_react_uwp_IViewPanel::ViewBackground() const +{ + Windows::UI::Xaml::Media::Brush value{ nullptr }; + check_hresult(WINRT_SHIM(react::uwp::IViewPanel)->get_ViewBackground(put_abi(value))); + return value; +} + +template void consume_react_uwp_IViewPanel::ViewBackground(Windows::UI::Xaml::Media::Brush const& value) const +{ + check_hresult(WINRT_SHIM(react::uwp::IViewPanel)->put_ViewBackground(get_abi(value))); +} + +template Windows::UI::Xaml::Thickness consume_react_uwp_IViewPanel::BorderThickness() const +{ + Windows::UI::Xaml::Thickness value{}; + check_hresult(WINRT_SHIM(react::uwp::IViewPanel)->get_BorderThickness(put_abi(value))); + return value; +} + +template void consume_react_uwp_IViewPanel::BorderThickness(Windows::UI::Xaml::Thickness const& value) const +{ + check_hresult(WINRT_SHIM(react::uwp::IViewPanel)->put_BorderThickness(get_abi(value))); +} + +template Windows::UI::Xaml::Media::Brush consume_react_uwp_IViewPanel::BorderBrush() const +{ + Windows::UI::Xaml::Media::Brush value{ nullptr }; + check_hresult(WINRT_SHIM(react::uwp::IViewPanel)->get_BorderBrush(put_abi(value))); + return value; +} + +template void consume_react_uwp_IViewPanel::BorderBrush(Windows::UI::Xaml::Media::Brush const& value) const +{ + check_hresult(WINRT_SHIM(react::uwp::IViewPanel)->put_BorderBrush(get_abi(value))); +} + +template Windows::UI::Xaml::CornerRadius consume_react_uwp_IViewPanel::CornerRadius() const +{ + Windows::UI::Xaml::CornerRadius value{}; + check_hresult(WINRT_SHIM(react::uwp::IViewPanel)->get_CornerRadius(put_abi(value))); + return value; +} + +template void consume_react_uwp_IViewPanel::CornerRadius(Windows::UI::Xaml::CornerRadius const& value) const +{ + check_hresult(WINRT_SHIM(react::uwp::IViewPanel)->put_CornerRadius(get_abi(value))); +} + +template bool consume_react_uwp_IViewPanel::ClipChildren() const +{ + bool value{}; + check_hresult(WINRT_SHIM(react::uwp::IViewPanel)->get_ClipChildren(&value)); + return value; +} + +template void consume_react_uwp_IViewPanel::ClipChildren(bool value) const +{ + check_hresult(WINRT_SHIM(react::uwp::IViewPanel)->put_ClipChildren(value)); +} + +template Windows::UI::Xaml::DependencyProperty consume_react_uwp_IViewPanelStatics::ViewBackgroundProperty() const +{ + Windows::UI::Xaml::DependencyProperty value{ nullptr }; + check_hresult(WINRT_SHIM(react::uwp::IViewPanelStatics)->get_ViewBackgroundProperty(put_abi(value))); + return value; +} + +template Windows::UI::Xaml::DependencyProperty consume_react_uwp_IViewPanelStatics::BorderThicknessProperty() const +{ + Windows::UI::Xaml::DependencyProperty value{ nullptr }; + check_hresult(WINRT_SHIM(react::uwp::IViewPanelStatics)->get_BorderThicknessProperty(put_abi(value))); + return value; +} + +template Windows::UI::Xaml::DependencyProperty consume_react_uwp_IViewPanelStatics::BorderBrushProperty() const +{ + Windows::UI::Xaml::DependencyProperty value{ nullptr }; + check_hresult(WINRT_SHIM(react::uwp::IViewPanelStatics)->get_BorderBrushProperty(put_abi(value))); + return value; +} + +template Windows::UI::Xaml::DependencyProperty consume_react_uwp_IViewPanelStatics::CornerRadiusProperty() const +{ + Windows::UI::Xaml::DependencyProperty value{ nullptr }; + check_hresult(WINRT_SHIM(react::uwp::IViewPanelStatics)->get_CornerRadiusProperty(put_abi(value))); + return value; +} + +template Windows::UI::Xaml::DependencyProperty consume_react_uwp_IViewPanelStatics::ClipChildrenProperty() const +{ + Windows::UI::Xaml::DependencyProperty value{ nullptr }; + check_hresult(WINRT_SHIM(react::uwp::IViewPanelStatics)->get_ClipChildrenProperty(put_abi(value))); + return value; +} + +template Windows::UI::Xaml::DependencyProperty consume_react_uwp_IViewPanelStatics::TopProperty() const +{ + Windows::UI::Xaml::DependencyProperty value{ nullptr }; + check_hresult(WINRT_SHIM(react::uwp::IViewPanelStatics)->get_TopProperty(put_abi(value))); + return value; +} + +template void consume_react_uwp_IViewPanelStatics::SetTop(Windows::UI::Xaml::UIElement const& element, double value) const +{ + check_hresult(WINRT_SHIM(react::uwp::IViewPanelStatics)->SetTop(get_abi(element), value)); +} + +template double consume_react_uwp_IViewPanelStatics::GetTop(Windows::UI::Xaml::UIElement const& element) const +{ + double result{}; + check_hresult(WINRT_SHIM(react::uwp::IViewPanelStatics)->GetTop(get_abi(element), &result)); + return result; +} + +template Windows::UI::Xaml::DependencyProperty consume_react_uwp_IViewPanelStatics::LeftProperty() const +{ + Windows::UI::Xaml::DependencyProperty value{ nullptr }; + check_hresult(WINRT_SHIM(react::uwp::IViewPanelStatics)->get_LeftProperty(put_abi(value))); + return value; +} + +template void consume_react_uwp_IViewPanelStatics::SetLeft(Windows::UI::Xaml::UIElement const& element, double value) const +{ + check_hresult(WINRT_SHIM(react::uwp::IViewPanelStatics)->SetLeft(get_abi(element), value)); +} + +template double consume_react_uwp_IViewPanelStatics::GetLeft(Windows::UI::Xaml::UIElement const& element) const +{ + double result{}; + check_hresult(WINRT_SHIM(react::uwp::IViewPanelStatics)->GetLeft(get_abi(element), &result)); + return result; +} + +template <> struct delegate +{ + template + struct type : implements_delegate + { + type(H&& handler) : implements_delegate(std::forward(handler)) {} + + int32_t WINRT_CALL Invoke() noexcept final + { + try + { + (*this)(); + return 0; + } + catch (...) + { + return to_hresult(); + } + } + }; +}; + template struct produce : produce_base {}; @@ -44,30 +311,1476 @@ struct produce : produce_base +struct produce : produce_base +{}; -WINRT_EXPORT namespace winrt::react::uwp { +template +struct produce : produce_base +{ + int32_t WINRT_CALL get_AccessibilityRoleProperty(void** value) noexcept final + { + try + { + *value = nullptr; + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(AccessibilityRoleProperty, WINRT_WRAP(Windows::UI::Xaml::DependencyProperty)); + *value = detach_from(this->shim().AccessibilityRoleProperty()); + return 0; + } + catch (...) { return to_hresult(); } + } -inline DynamicAutomationPeer::DynamicAutomationPeer(Windows::UI::Xaml::FrameworkElement const& owner) : - DynamicAutomationPeer(impl::call_factory([&](auto&& f) { return f.CreateInstance(owner); })) -{} + int32_t WINRT_CALL SetAccessibilityRole(void* element, react::uwp::AccessibilityRoles value) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(SetAccessibilityRole, WINRT_WRAP(void), Windows::UI::Xaml::UIElement const&, react::uwp::AccessibilityRoles const&); + this->shim().SetAccessibilityRole(*reinterpret_cast(&element), *reinterpret_cast(&value)); + return 0; + } + catch (...) { return to_hresult(); } + } -} + int32_t WINRT_CALL GetAccessibilityRole(void* element, react::uwp::AccessibilityRoles* result) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(GetAccessibilityRole, WINRT_WRAP(react::uwp::AccessibilityRoles), Windows::UI::Xaml::UIElement const&); + *result = detach_from(this->shim().GetAccessibilityRole(*reinterpret_cast(&element))); + return 0; + } + catch (...) { return to_hresult(); } + } -namespace winrt::impl { + int32_t WINRT_CALL get_AccessibilityStateDisabledProperty(void** value) noexcept final + { + try + { + *value = nullptr; + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(AccessibilityStateDisabledProperty, WINRT_WRAP(Windows::UI::Xaml::DependencyProperty)); + *value = detach_from(this->shim().AccessibilityStateDisabledProperty()); + return 0; + } + catch (...) { return to_hresult(); } + } -} + int32_t WINRT_CALL SetAccessibilityStateDisabled(void* element, bool value) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(SetAccessibilityStateDisabled, WINRT_WRAP(void), Windows::UI::Xaml::UIElement const&, bool); + this->shim().SetAccessibilityStateDisabled(*reinterpret_cast(&element), value); + return 0; + } + catch (...) { return to_hresult(); } + } -WINRT_EXPORT namespace winrt::experimental::reflect { + int32_t WINRT_CALL GetAccessibilityStateDisabled(void* element, bool* result) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(GetAccessibilityStateDisabled, WINRT_WRAP(bool), Windows::UI::Xaml::UIElement const&); + *result = detach_from(this->shim().GetAccessibilityStateDisabled(*reinterpret_cast(&element))); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL get_AccessibilityStateSelectedProperty(void** value) noexcept final + { + try + { + *value = nullptr; + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(AccessibilityStateSelectedProperty, WINRT_WRAP(Windows::UI::Xaml::DependencyProperty)); + *value = detach_from(this->shim().AccessibilityStateSelectedProperty()); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL SetAccessibilityStateSelected(void* element, bool value) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(SetAccessibilityStateSelected, WINRT_WRAP(void), Windows::UI::Xaml::UIElement const&, bool); + this->shim().SetAccessibilityStateSelected(*reinterpret_cast(&element), value); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL GetAccessibilityStateSelected(void* element, bool* result) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(GetAccessibilityStateSelected, WINRT_WRAP(bool), Windows::UI::Xaml::UIElement const&); + *result = detach_from(this->shim().GetAccessibilityStateSelected(*reinterpret_cast(&element))); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL get_AccessibilityInvokeEventHandlerProperty(void** value) noexcept final + { + try + { + *value = nullptr; + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(AccessibilityInvokeEventHandlerProperty, WINRT_WRAP(Windows::UI::Xaml::DependencyProperty)); + *value = detach_from(this->shim().AccessibilityInvokeEventHandlerProperty()); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL SetAccessibilityInvokeEventHandler(void* element, void* value) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(SetAccessibilityInvokeEventHandler, WINRT_WRAP(void), Windows::UI::Xaml::UIElement const&, react::uwp::AccessibilityInvokeEventHandler const&); + this->shim().SetAccessibilityInvokeEventHandler(*reinterpret_cast(&element), *reinterpret_cast(&value)); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL GetAccessibilityInvokeEventHandler(void* element, void** result) noexcept final + { + try + { + *result = nullptr; + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(GetAccessibilityInvokeEventHandler, WINRT_WRAP(react::uwp::AccessibilityInvokeEventHandler), Windows::UI::Xaml::UIElement const&); + *result = detach_from(this->shim().GetAccessibilityInvokeEventHandler(*reinterpret_cast(&element))); + return 0; + } + catch (...) { return to_hresult(); } + } +}; + +template +struct produce : produce_base +{ + int32_t WINRT_CALL GetPanel(void** result) noexcept final + { + try + { + *result = nullptr; + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(GetPanel, WINRT_WRAP(react::uwp::ViewPanel)); + *result = detach_from(this->shim().GetPanel()); + return 0; + } + catch (...) { return to_hresult(); } + } +}; + +template +struct produce : produce_base +{ + int32_t WINRT_CALL InsertAt(uint32_t index, void* value) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(InsertAt, WINRT_WRAP(void), uint32_t, Windows::UI::Xaml::UIElement const&); + this->shim().InsertAt(index, *reinterpret_cast(&value)); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL RemoveAt(uint32_t index) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(RemoveAt, WINRT_WRAP(void), uint32_t); + this->shim().RemoveAt(index); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL Clear() noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(Clear, WINRT_WRAP(void)); + this->shim().Clear(); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL FinalizeProperties() noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(FinalizeProperties, WINRT_WRAP(void)); + this->shim().FinalizeProperties(); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL GetOuterBorder(void** result) noexcept final + { + try + { + *result = nullptr; + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(GetOuterBorder, WINRT_WRAP(Windows::UI::Xaml::Controls::Border)); + *result = detach_from(this->shim().GetOuterBorder()); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL get_ViewBackground(void** value) noexcept final + { + try + { + *value = nullptr; + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(ViewBackground, WINRT_WRAP(Windows::UI::Xaml::Media::Brush)); + *value = detach_from(this->shim().ViewBackground()); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL put_ViewBackground(void* value) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(ViewBackground, WINRT_WRAP(void), Windows::UI::Xaml::Media::Brush const&); + this->shim().ViewBackground(*reinterpret_cast(&value)); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL get_BorderThickness(struct struct_Windows_UI_Xaml_Thickness* value) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(BorderThickness, WINRT_WRAP(Windows::UI::Xaml::Thickness)); + *value = detach_from(this->shim().BorderThickness()); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL put_BorderThickness(struct struct_Windows_UI_Xaml_Thickness value) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(BorderThickness, WINRT_WRAP(void), Windows::UI::Xaml::Thickness const&); + this->shim().BorderThickness(*reinterpret_cast(&value)); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL get_BorderBrush(void** value) noexcept final + { + try + { + *value = nullptr; + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(BorderBrush, WINRT_WRAP(Windows::UI::Xaml::Media::Brush)); + *value = detach_from(this->shim().BorderBrush()); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL put_BorderBrush(void* value) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(BorderBrush, WINRT_WRAP(void), Windows::UI::Xaml::Media::Brush const&); + this->shim().BorderBrush(*reinterpret_cast(&value)); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL get_CornerRadius(struct struct_Windows_UI_Xaml_CornerRadius* value) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(CornerRadius, WINRT_WRAP(Windows::UI::Xaml::CornerRadius)); + *value = detach_from(this->shim().CornerRadius()); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL put_CornerRadius(struct struct_Windows_UI_Xaml_CornerRadius value) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(CornerRadius, WINRT_WRAP(void), Windows::UI::Xaml::CornerRadius const&); + this->shim().CornerRadius(*reinterpret_cast(&value)); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL get_ClipChildren(bool* value) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(ClipChildren, WINRT_WRAP(bool)); + *value = detach_from(this->shim().ClipChildren()); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL put_ClipChildren(bool value) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(ClipChildren, WINRT_WRAP(void), bool); + this->shim().ClipChildren(value); + return 0; + } + catch (...) { return to_hresult(); } + } +}; + +template +struct produce : produce_base +{ + int32_t WINRT_CALL get_ViewBackgroundProperty(void** value) noexcept final + { + try + { + *value = nullptr; + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(ViewBackgroundProperty, WINRT_WRAP(Windows::UI::Xaml::DependencyProperty)); + *value = detach_from(this->shim().ViewBackgroundProperty()); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL get_BorderThicknessProperty(void** value) noexcept final + { + try + { + *value = nullptr; + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(BorderThicknessProperty, WINRT_WRAP(Windows::UI::Xaml::DependencyProperty)); + *value = detach_from(this->shim().BorderThicknessProperty()); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL get_BorderBrushProperty(void** value) noexcept final + { + try + { + *value = nullptr; + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(BorderBrushProperty, WINRT_WRAP(Windows::UI::Xaml::DependencyProperty)); + *value = detach_from(this->shim().BorderBrushProperty()); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL get_CornerRadiusProperty(void** value) noexcept final + { + try + { + *value = nullptr; + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(CornerRadiusProperty, WINRT_WRAP(Windows::UI::Xaml::DependencyProperty)); + *value = detach_from(this->shim().CornerRadiusProperty()); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL get_ClipChildrenProperty(void** value) noexcept final + { + try + { + *value = nullptr; + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(ClipChildrenProperty, WINRT_WRAP(Windows::UI::Xaml::DependencyProperty)); + *value = detach_from(this->shim().ClipChildrenProperty()); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL get_TopProperty(void** value) noexcept final + { + try + { + *value = nullptr; + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(TopProperty, WINRT_WRAP(Windows::UI::Xaml::DependencyProperty)); + *value = detach_from(this->shim().TopProperty()); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL SetTop(void* element, double value) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(SetTop, WINRT_WRAP(void), Windows::UI::Xaml::UIElement const&, double); + this->shim().SetTop(*reinterpret_cast(&element), value); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL GetTop(void* element, double* result) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(GetTop, WINRT_WRAP(double), Windows::UI::Xaml::UIElement const&); + *result = detach_from(this->shim().GetTop(*reinterpret_cast(&element))); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL get_LeftProperty(void** value) noexcept final + { + try + { + *value = nullptr; + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(LeftProperty, WINRT_WRAP(Windows::UI::Xaml::DependencyProperty)); + *value = detach_from(this->shim().LeftProperty()); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL SetLeft(void* element, double value) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(SetLeft, WINRT_WRAP(void), Windows::UI::Xaml::UIElement const&, double); + this->shim().SetLeft(*reinterpret_cast(&element), value); + return 0; + } + catch (...) { return to_hresult(); } + } + + int32_t WINRT_CALL GetLeft(void* element, double* result) noexcept final + { + try + { + typename D::abi_guard guard(this->shim()); + WINRT_ASSERT_DECLARATION(GetLeft, WINRT_WRAP(double), Windows::UI::Xaml::UIElement const&); + *result = detach_from(this->shim().GetLeft(*reinterpret_cast(&element))); + return 0; + } + catch (...) { return to_hresult(); } + } +}; + +} + +WINRT_EXPORT namespace winrt::react::uwp { + +inline DynamicAutomationPeer::DynamicAutomationPeer(Windows::UI::Xaml::FrameworkElement const& owner) : + DynamicAutomationPeer(impl::call_factory([&](auto&& f) { return f.CreateInstance(owner); })) +{} + +inline Windows::UI::Xaml::DependencyProperty DynamicAutomationProperties::AccessibilityRoleProperty() +{ + return impl::call_factory([&](auto&& f) { return f.AccessibilityRoleProperty(); }); +} + +inline void DynamicAutomationProperties::SetAccessibilityRole(Windows::UI::Xaml::UIElement const& element, react::uwp::AccessibilityRoles const& value) +{ + impl::call_factory([&](auto&& f) { return f.SetAccessibilityRole(element, value); }); +} + +inline react::uwp::AccessibilityRoles DynamicAutomationProperties::GetAccessibilityRole(Windows::UI::Xaml::UIElement const& element) +{ + return impl::call_factory([&](auto&& f) { return f.GetAccessibilityRole(element); }); +} + +inline Windows::UI::Xaml::DependencyProperty DynamicAutomationProperties::AccessibilityStateDisabledProperty() +{ + return impl::call_factory([&](auto&& f) { return f.AccessibilityStateDisabledProperty(); }); +} + +inline void DynamicAutomationProperties::SetAccessibilityStateDisabled(Windows::UI::Xaml::UIElement const& element, bool value) +{ + impl::call_factory([&](auto&& f) { return f.SetAccessibilityStateDisabled(element, value); }); +} + +inline bool DynamicAutomationProperties::GetAccessibilityStateDisabled(Windows::UI::Xaml::UIElement const& element) +{ + return impl::call_factory([&](auto&& f) { return f.GetAccessibilityStateDisabled(element); }); +} + +inline Windows::UI::Xaml::DependencyProperty DynamicAutomationProperties::AccessibilityStateSelectedProperty() +{ + return impl::call_factory([&](auto&& f) { return f.AccessibilityStateSelectedProperty(); }); +} + +inline void DynamicAutomationProperties::SetAccessibilityStateSelected(Windows::UI::Xaml::UIElement const& element, bool value) +{ + impl::call_factory([&](auto&& f) { return f.SetAccessibilityStateSelected(element, value); }); +} + +inline bool DynamicAutomationProperties::GetAccessibilityStateSelected(Windows::UI::Xaml::UIElement const& element) +{ + return impl::call_factory([&](auto&& f) { return f.GetAccessibilityStateSelected(element); }); +} + +inline Windows::UI::Xaml::DependencyProperty DynamicAutomationProperties::AccessibilityInvokeEventHandlerProperty() +{ + return impl::call_factory([&](auto&& f) { return f.AccessibilityInvokeEventHandlerProperty(); }); +} + +inline void DynamicAutomationProperties::SetAccessibilityInvokeEventHandler(Windows::UI::Xaml::UIElement const& element, react::uwp::AccessibilityInvokeEventHandler const& value) +{ + impl::call_factory([&](auto&& f) { return f.SetAccessibilityInvokeEventHandler(element, value); }); +} + +inline react::uwp::AccessibilityInvokeEventHandler DynamicAutomationProperties::GetAccessibilityInvokeEventHandler(Windows::UI::Xaml::UIElement const& element) +{ + return impl::call_factory([&](auto&& f) { return f.GetAccessibilityInvokeEventHandler(element); }); +} + +inline ViewControl::ViewControl() : + ViewControl(impl::call_factory([](auto&& f) { return f.template ActivateInstance(); })) +{} + +inline ViewPanel::ViewPanel() : + ViewPanel(impl::call_factory([](auto&& f) { return f.template ActivateInstance(); })) +{} + +inline Windows::UI::Xaml::DependencyProperty ViewPanel::ViewBackgroundProperty() +{ + return impl::call_factory([&](auto&& f) { return f.ViewBackgroundProperty(); }); +} + +inline Windows::UI::Xaml::DependencyProperty ViewPanel::BorderThicknessProperty() +{ + return impl::call_factory([&](auto&& f) { return f.BorderThicknessProperty(); }); +} + +inline Windows::UI::Xaml::DependencyProperty ViewPanel::BorderBrushProperty() +{ + return impl::call_factory([&](auto&& f) { return f.BorderBrushProperty(); }); +} + +inline Windows::UI::Xaml::DependencyProperty ViewPanel::CornerRadiusProperty() +{ + return impl::call_factory([&](auto&& f) { return f.CornerRadiusProperty(); }); +} + +inline Windows::UI::Xaml::DependencyProperty ViewPanel::ClipChildrenProperty() +{ + return impl::call_factory([&](auto&& f) { return f.ClipChildrenProperty(); }); +} + +inline Windows::UI::Xaml::DependencyProperty ViewPanel::TopProperty() +{ + return impl::call_factory([&](auto&& f) { return f.TopProperty(); }); +} + +inline void ViewPanel::SetTop(Windows::UI::Xaml::UIElement const& element, double value) +{ + impl::call_factory([&](auto&& f) { return f.SetTop(element, value); }); +} + +inline double ViewPanel::GetTop(Windows::UI::Xaml::UIElement const& element) +{ + return impl::call_factory([&](auto&& f) { return f.GetTop(element); }); +} + +inline Windows::UI::Xaml::DependencyProperty ViewPanel::LeftProperty() +{ + return impl::call_factory([&](auto&& f) { return f.LeftProperty(); }); +} + +inline void ViewPanel::SetLeft(Windows::UI::Xaml::UIElement const& element, double value) +{ + impl::call_factory([&](auto&& f) { return f.SetLeft(element, value); }); +} + +inline double ViewPanel::GetLeft(Windows::UI::Xaml::UIElement const& element) +{ + return impl::call_factory([&](auto&& f) { return f.GetLeft(element); }); +} + +template AccessibilityInvokeEventHandler::AccessibilityInvokeEventHandler(L handler) : + AccessibilityInvokeEventHandler(impl::make_delegate(std::forward(handler))) +{} + +template AccessibilityInvokeEventHandler::AccessibilityInvokeEventHandler(F* handler) : + AccessibilityInvokeEventHandler([=](auto&&... args) { return handler(args...); }) +{} + +template AccessibilityInvokeEventHandler::AccessibilityInvokeEventHandler(O* object, M method) : + AccessibilityInvokeEventHandler([=](auto&&... args) { return ((*object).*(method))(args...); }) +{} + +template AccessibilityInvokeEventHandler::AccessibilityInvokeEventHandler(com_ptr&& object, M method) : + AccessibilityInvokeEventHandler([o = std::move(object), method](auto&&... args) { return ((*o).*(method))(args...); }) +{} + +template AccessibilityInvokeEventHandler::AccessibilityInvokeEventHandler(weak_ref&& object, M method) : + AccessibilityInvokeEventHandler([o = std::move(object), method](auto&&... args) { if (auto s = o.get()) { ((*s).*(method))(args...); } }) +{} + +inline void AccessibilityInvokeEventHandler::operator()() const +{ + check_hresult((*(impl::abi_t**)this)->Invoke()); +} + +} + +namespace winrt::impl { + +struct property_react_uwp_IDynamicAutomationPropertiesStatics +{ struct named { + struct AccessibilityInvokeEventHandlerProperty + { + struct name { static constexpr std::wstring_view value{ L"AccessibilityInvokeEventHandlerProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::IDynamicAutomationPropertiesStatics; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.AccessibilityInvokeEventHandlerProperty(); + } + }; + }; + struct AccessibilityRoleProperty + { + struct name { static constexpr std::wstring_view value{ L"AccessibilityRoleProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::IDynamicAutomationPropertiesStatics; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.AccessibilityRoleProperty(); + } + }; + }; + struct AccessibilityStateDisabledProperty + { + struct name { static constexpr std::wstring_view value{ L"AccessibilityStateDisabledProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::IDynamicAutomationPropertiesStatics; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.AccessibilityStateDisabledProperty(); + } + }; + }; + struct AccessibilityStateSelectedProperty + { + struct name { static constexpr std::wstring_view value{ L"AccessibilityStateSelectedProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::IDynamicAutomationPropertiesStatics; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.AccessibilityStateSelectedProperty(); + } + }; + };}; + struct list { using type = impl::typelist; }; +}; + +struct property_react_uwp_IViewPanel +{ struct named { + struct BorderBrush + { + struct name { static constexpr std::wstring_view value{ L"BorderBrush"sv }; }; + using property_type = winrt::Windows::UI::Xaml::Media::Brush; + using target_type = winrt::react::uwp::IViewPanel; + + using is_readable = std::true_type; + using is_writable = std::true_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.BorderBrush(); + } + }; + struct setter + { + template + void operator()(target_type const& target, Value&& value) const + { + target.BorderBrush(std::forward(value)); + } + }; + }; + struct BorderThickness + { + struct name { static constexpr std::wstring_view value{ L"BorderThickness"sv }; }; + using property_type = winrt::Windows::UI::Xaml::Thickness; + using target_type = winrt::react::uwp::IViewPanel; + + using is_readable = std::true_type; + using is_writable = std::true_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.BorderThickness(); + } + }; + struct setter + { + template + void operator()(target_type const& target, Value&& value) const + { + target.BorderThickness(std::forward(value)); + } + }; + }; + struct ClipChildren + { + struct name { static constexpr std::wstring_view value{ L"ClipChildren"sv }; }; + using property_type = bool; + using target_type = winrt::react::uwp::IViewPanel; + + using is_readable = std::true_type; + using is_writable = std::true_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.ClipChildren(); + } + }; + struct setter + { + template + void operator()(target_type const& target, Value&& value) const + { + target.ClipChildren(std::forward(value)); + } + }; + }; + struct CornerRadius + { + struct name { static constexpr std::wstring_view value{ L"CornerRadius"sv }; }; + using property_type = winrt::Windows::UI::Xaml::CornerRadius; + using target_type = winrt::react::uwp::IViewPanel; + + using is_readable = std::true_type; + using is_writable = std::true_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.CornerRadius(); + } + }; + struct setter + { + template + void operator()(target_type const& target, Value&& value) const + { + target.CornerRadius(std::forward(value)); + } + }; + }; + struct ViewBackground + { + struct name { static constexpr std::wstring_view value{ L"ViewBackground"sv }; }; + using property_type = winrt::Windows::UI::Xaml::Media::Brush; + using target_type = winrt::react::uwp::IViewPanel; + + using is_readable = std::true_type; + using is_writable = std::true_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.ViewBackground(); + } + }; + struct setter + { + template + void operator()(target_type const& target, Value&& value) const + { + target.ViewBackground(std::forward(value)); + } + }; + };}; + struct list { using type = impl::typelist; }; +}; + +struct property_react_uwp_IViewPanelStatics +{ struct named { + struct BorderBrushProperty + { + struct name { static constexpr std::wstring_view value{ L"BorderBrushProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::IViewPanelStatics; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.BorderBrushProperty(); + } + }; + }; + struct BorderThicknessProperty + { + struct name { static constexpr std::wstring_view value{ L"BorderThicknessProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::IViewPanelStatics; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.BorderThicknessProperty(); + } + }; + }; + struct ClipChildrenProperty + { + struct name { static constexpr std::wstring_view value{ L"ClipChildrenProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::IViewPanelStatics; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.ClipChildrenProperty(); + } + }; + }; + struct CornerRadiusProperty + { + struct name { static constexpr std::wstring_view value{ L"CornerRadiusProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::IViewPanelStatics; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.CornerRadiusProperty(); + } + }; + }; + struct LeftProperty + { + struct name { static constexpr std::wstring_view value{ L"LeftProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::IViewPanelStatics; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.LeftProperty(); + } + }; + }; + struct TopProperty + { + struct name { static constexpr std::wstring_view value{ L"TopProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::IViewPanelStatics; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.TopProperty(); + } + }; + }; + struct ViewBackgroundProperty + { + struct name { static constexpr std::wstring_view value{ L"ViewBackgroundProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::IViewPanelStatics; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.ViewBackgroundProperty(); + } + }; + };}; + struct list { using type = impl::typelist; }; +}; + +struct property_react_uwp_DynamicAutomationPeer +{ struct named { + struct IsSelected + { + struct name { static constexpr std::wstring_view value{ L"IsSelected"sv }; }; + using property_type = bool; + using target_type = winrt::react::uwp::DynamicAutomationPeer; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.IsSelected(); + } + }; + }; + struct SelectionContainer + { + struct name { static constexpr std::wstring_view value{ L"SelectionContainer"sv }; }; + using property_type = winrt::Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple; + using target_type = winrt::react::uwp::DynamicAutomationPeer; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.SelectionContainer(); + } + }; + }; + struct CanSelectMultiple + { + struct name { static constexpr std::wstring_view value{ L"CanSelectMultiple"sv }; }; + using property_type = bool; + using target_type = winrt::react::uwp::DynamicAutomationPeer; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.CanSelectMultiple(); + } + }; + }; + struct IsSelectionRequired + { + struct name { static constexpr std::wstring_view value{ L"IsSelectionRequired"sv }; }; + using property_type = bool; + using target_type = winrt::react::uwp::DynamicAutomationPeer; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.IsSelectionRequired(); + } + }; + };}; + struct list { using type = impl::typelist; }; +}; + +struct property_react_uwp_DynamicAutomationProperties +{ struct named { + struct AccessibilityInvokeEventHandlerProperty + { + struct name { static constexpr std::wstring_view value{ L"AccessibilityInvokeEventHandlerProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::DynamicAutomationProperties; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::true_type; + struct getter + { + auto operator()() const + { + return target_type::AccessibilityInvokeEventHandlerProperty(); + } + }; + }; + struct AccessibilityRoleProperty + { + struct name { static constexpr std::wstring_view value{ L"AccessibilityRoleProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::DynamicAutomationProperties; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::true_type; + struct getter + { + auto operator()() const + { + return target_type::AccessibilityRoleProperty(); + } + }; + }; + struct AccessibilityStateDisabledProperty + { + struct name { static constexpr std::wstring_view value{ L"AccessibilityStateDisabledProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::DynamicAutomationProperties; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::true_type; + struct getter + { + auto operator()() const + { + return target_type::AccessibilityStateDisabledProperty(); + } + }; + }; + struct AccessibilityStateSelectedProperty + { + struct name { static constexpr std::wstring_view value{ L"AccessibilityStateSelectedProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::DynamicAutomationProperties; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::true_type; + struct getter + { + auto operator()() const + { + return target_type::AccessibilityStateSelectedProperty(); + } + }; + };}; + struct list { using type = impl::typelist; }; +}; + +struct property_react_uwp_ViewPanel +{ struct named { + struct ViewBackground + { + struct name { static constexpr std::wstring_view value{ L"ViewBackground"sv }; }; + using property_type = winrt::Windows::UI::Xaml::Media::Brush; + using target_type = winrt::react::uwp::ViewPanel; + + using is_readable = std::true_type; + using is_writable = std::true_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.ViewBackground(); + } + }; + struct setter + { + template + void operator()(target_type const& target, Value&& value) const + { + target.ViewBackground(std::forward(value)); + } + }; + }; + struct CornerRadius + { + struct name { static constexpr std::wstring_view value{ L"CornerRadius"sv }; }; + using property_type = winrt::Windows::UI::Xaml::CornerRadius; + using target_type = winrt::react::uwp::ViewPanel; + + using is_readable = std::true_type; + using is_writable = std::true_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.CornerRadius(); + } + }; + struct setter + { + template + void operator()(target_type const& target, Value&& value) const + { + target.CornerRadius(std::forward(value)); + } + }; + }; + struct ClipChildren + { + struct name { static constexpr std::wstring_view value{ L"ClipChildren"sv }; }; + using property_type = bool; + using target_type = winrt::react::uwp::ViewPanel; + + using is_readable = std::true_type; + using is_writable = std::true_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.ClipChildren(); + } + }; + struct setter + { + template + void operator()(target_type const& target, Value&& value) const + { + target.ClipChildren(std::forward(value)); + } + }; + }; + struct BorderThickness + { + struct name { static constexpr std::wstring_view value{ L"BorderThickness"sv }; }; + using property_type = winrt::Windows::UI::Xaml::Thickness; + using target_type = winrt::react::uwp::ViewPanel; + + using is_readable = std::true_type; + using is_writable = std::true_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.BorderThickness(); + } + }; + struct setter + { + template + void operator()(target_type const& target, Value&& value) const + { + target.BorderThickness(std::forward(value)); + } + }; + }; + struct BorderBrush + { + struct name { static constexpr std::wstring_view value{ L"BorderBrush"sv }; }; + using property_type = winrt::Windows::UI::Xaml::Media::Brush; + using target_type = winrt::react::uwp::ViewPanel; + + using is_readable = std::true_type; + using is_writable = std::true_type; + using is_static = std::false_type; + struct getter + { + auto operator()(target_type const& target) const + { + return target.BorderBrush(); + } + }; + struct setter + { + template + void operator()(target_type const& target, Value&& value) const + { + target.BorderBrush(std::forward(value)); + } + }; + }; + struct BorderBrushProperty + { + struct name { static constexpr std::wstring_view value{ L"BorderBrushProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::ViewPanel; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::true_type; + struct getter + { + auto operator()() const + { + return target_type::BorderBrushProperty(); + } + }; + }; + struct BorderThicknessProperty + { + struct name { static constexpr std::wstring_view value{ L"BorderThicknessProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::ViewPanel; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::true_type; + struct getter + { + auto operator()() const + { + return target_type::BorderThicknessProperty(); + } + }; + }; + struct ClipChildrenProperty + { + struct name { static constexpr std::wstring_view value{ L"ClipChildrenProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::ViewPanel; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::true_type; + struct getter + { + auto operator()() const + { + return target_type::ClipChildrenProperty(); + } + }; + }; + struct CornerRadiusProperty + { + struct name { static constexpr std::wstring_view value{ L"CornerRadiusProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::ViewPanel; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::true_type; + struct getter + { + auto operator()() const + { + return target_type::CornerRadiusProperty(); + } + }; + }; + struct LeftProperty + { + struct name { static constexpr std::wstring_view value{ L"LeftProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::ViewPanel; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::true_type; + struct getter + { + auto operator()() const + { + return target_type::LeftProperty(); + } + }; + }; + struct TopProperty + { + struct name { static constexpr std::wstring_view value{ L"TopProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::ViewPanel; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::true_type; + struct getter + { + auto operator()() const + { + return target_type::TopProperty(); + } + }; + }; + struct ViewBackgroundProperty + { + struct name { static constexpr std::wstring_view value{ L"ViewBackgroundProperty"sv }; }; + using property_type = winrt::Windows::UI::Xaml::DependencyProperty; + using target_type = winrt::react::uwp::ViewPanel; + + using is_readable = std::true_type; + using is_writable = std::false_type; + using is_static = std::true_type; + struct getter + { + auto operator()() const + { + return target_type::ViewBackgroundProperty(); + } + }; + };}; + struct list { using type = impl::typelist; }; +}; + +} + +WINRT_EXPORT namespace winrt::experimental::reflect { +template <> struct named_property : impl::property_react_uwp_IDynamicAutomationPropertiesStatics::named {}; +template <> struct properties : impl::property_react_uwp_IDynamicAutomationPropertiesStatics::list {}; +template <> struct named_property : impl::property_react_uwp_IViewPanel::named {}; +template <> struct properties : impl::property_react_uwp_IViewPanel::list {}; +template <> struct named_property : impl::property_react_uwp_IViewPanelStatics::named {}; +template <> struct properties : impl::property_react_uwp_IViewPanelStatics::list {}; +template <> struct named_property : impl::property_react_uwp_DynamicAutomationPeer::named {}; +template <> struct properties : impl::property_react_uwp_DynamicAutomationPeer::list {}; +template <> struct named_property : impl::property_react_uwp_DynamicAutomationProperties::named {}; +template <> struct properties : impl::property_react_uwp_DynamicAutomationProperties::list {}; +template <> struct named_property : impl::property_react_uwp_ViewPanel::named {}; +template <> struct properties : impl::property_react_uwp_ViewPanel::list {}; + +template <> +struct base_type { using type = Windows::UI::Xaml::Automation::Peers::FrameworkElementAutomationPeer; }; +template <> +struct base_type { using type = Windows::UI::Xaml::Controls::ContentControl; }; +template <> +struct base_type { using type = Windows::UI::Xaml::Controls::Panel; };template <> struct get_enumerator_names +{ + static constexpr std::array value{{ + {L"None", 4}, + {L"Button", 6}, + {L"Link", 4}, + {L"Search", 6}, + {L"Image", 5}, + {L"KeyboardKey", 11}, + {L"Text", 4}, + {L"Adjustable", 10}, + {L"ImageButton", 11}, + {L"Header", 6}, + {L"Summary", 7}, + {L"Unknown", 7}, + {L"CountRoles", 10}, }}; +}; +template <> struct get_enumerator_values +{ + static constexpr std::array value{{ + react::uwp::AccessibilityRoles::None, + react::uwp::AccessibilityRoles::Button, + react::uwp::AccessibilityRoles::Link, + react::uwp::AccessibilityRoles::Search, + react::uwp::AccessibilityRoles::Image, + react::uwp::AccessibilityRoles::KeyboardKey, + react::uwp::AccessibilityRoles::Text, + react::uwp::AccessibilityRoles::Adjustable, + react::uwp::AccessibilityRoles::ImageButton, + react::uwp::AccessibilityRoles::Header, + react::uwp::AccessibilityRoles::Summary, + react::uwp::AccessibilityRoles::Unknown, + react::uwp::AccessibilityRoles::CountRoles, }}; +}; +template <> struct get_enumerator_names +{ + static constexpr std::array value{{ + {L"Selected", 8}, + {L"Disabled", 8}, + {L"CountStates", 11}, }}; +}; +template <> struct get_enumerator_values +{ + static constexpr std::array value{{ + react::uwp::AccessibilityStates::Selected, + react::uwp::AccessibilityStates::Disabled, + react::uwp::AccessibilityStates::CountStates, }}; +}; -template <> -struct base_type { using type = Windows::UI::Xaml::Automation::Peers::FrameworkElementAutomationPeer; }; } WINRT_EXPORT namespace std { template<> struct hash : winrt::impl::hash_base {}; template<> struct hash : winrt::impl::hash_base {}; +template<> struct hash : winrt::impl::hash_base {}; +template<> struct hash : winrt::impl::hash_base {}; +template<> struct hash : winrt::impl::hash_base {}; +template<> struct hash : winrt::impl::hash_base {}; +template<> struct hash : winrt::impl::hash_base {}; template<> struct hash : winrt::impl::hash_base {}; +template<> struct hash : winrt::impl::hash_base {}; +template<> struct hash : winrt::impl::hash_base {}; +template<> struct hash : winrt::impl::hash_base {}; } diff --git a/vnext/ReactUWP/Views/module.g.cpp b/vnext/ReactUWP/Views/module.g.cpp new file mode 100644 index 00000000000..48763d1a1c5 --- /dev/null +++ b/vnext/ReactUWP/Views/module.g.cpp @@ -0,0 +1,72 @@ +// WARNING: Please don't edit this file. It was generated by C++/WinRT v1.0.190111.3 + +#include "pch.h" +#include "DynamicAutomationPeer.h" +#include "DynamicAutomationProperties.h" +#include "ViewControl.h" +#include "ViewPanel.h" + +int32_t WINRT_CALL WINRT_CanUnloadNow() noexcept +{ +#ifdef _WRL_MODULE_H_ + if (!::Microsoft::WRL::Module<::Microsoft::WRL::InProc>::GetModule().Terminate()) + { + return 1; // S_FALSE + } +#endif + + if (winrt::get_module_lock()) + { + return 1; // S_FALSE + } + + winrt::clear_factory_cache(); + return 0; // S_OK +} + +int32_t WINRT_CALL WINRT_GetActivationFactory(void* classId, void** factory) noexcept +{ + try + { + *factory = nullptr; + uint32_t length{}; + wchar_t const* const buffer = WINRT_WindowsGetStringRawBuffer(classId, &length); + std::wstring_view const name{ buffer, length }; + + auto requal = [](std::wstring_view const& left, std::wstring_view const& right) noexcept + { + return std::equal(left.rbegin(), left.rend(), right.rbegin(), right.rend()); + }; + + if (requal(name, L"react.uwp.DynamicAutomationPeer")) + { + *factory = winrt::detach_abi(winrt::make()); + return 0; + } + + if (requal(name, L"react.uwp.DynamicAutomationProperties")) + { + *factory = winrt::detach_abi(winrt::make()); + return 0; + } + + if (requal(name, L"react.uwp.ViewControl")) + { + *factory = winrt::detach_abi(winrt::make()); + return 0; + } + + if (requal(name, L"react.uwp.ViewPanel")) + { + *factory = winrt::detach_abi(winrt::make()); + return 0; + } + +#ifdef _WRL_MODULE_H_ + return ::Microsoft::WRL::Module<::Microsoft::WRL::InProc>::GetModule().GetActivationFactory(static_cast(classId), reinterpret_cast<::IActivationFactory**>(factory)); +#else + return winrt::hresult_class_not_available(name).to_abi(); +#endif + } + catch (...) { return winrt::to_hresult(); } +} diff --git a/vnext/ReactUWP/XamlDirectInstance.cpp b/vnext/ReactUWP/XamlDirectInstance.cpp new file mode 100644 index 00000000000..f52880f8730 --- /dev/null +++ b/vnext/ReactUWP/XamlDirectInstance.cpp @@ -0,0 +1,17 @@ +#include "pch.h" +#include + +namespace XD { + using namespace winrt::Windows::UI::Xaml::Core::Direct; +} + +XD::IXamlDirect XamlDirectInstance::m_xamlDirectInstance = NULL; + +XD::IXamlDirect XamlDirectInstance::GetXamlDirect() +{ + if (m_xamlDirectInstance == NULL) + { + m_xamlDirectInstance = XD::XamlDirect::GetDefault(); + } + return m_xamlDirectInstance; +} diff --git a/vnext/ReactUWP/XamlDirectInstance.h b/vnext/ReactUWP/XamlDirectInstance.h new file mode 100644 index 00000000000..2089fbf05a4 --- /dev/null +++ b/vnext/ReactUWP/XamlDirectInstance.h @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include + +namespace XD { + using namespace winrt::Windows::UI::Xaml::Core::Direct; +} + +class XamlDirectInstance +{ +public: + static XD::IXamlDirect GetXamlDirect(); + +private: + static XD::IXamlDirect m_xamlDirectInstance; + XamlDirectInstance(); +}; diff --git a/vnext/ReactUWP/packages.config b/vnext/ReactUWP/packages.config index 9dd760e38e9..f5ca708cefc 100644 --- a/vnext/ReactUWP/packages.config +++ b/vnext/ReactUWP/packages.config @@ -2,5 +2,4 @@ - \ No newline at end of file diff --git a/vnext/ReactUwp.nuspec b/vnext/ReactUwp.nuspec index e3aa48465e5..58c8eb21a22 100644 --- a/vnext/ReactUwp.nuspec +++ b/vnext/ReactUwp.nuspec @@ -2,11 +2,14 @@ OfficeReact.Uwp - __BuildBuildNumber__ + $npmVersion$ Contains Windows Implementation of React-Native Microsoft https://office.visualstudio.com/ISS/_git/sdx-platform false + diff --git a/vnext/ReactWin32.nuspec b/vnext/ReactWin32.nuspec index 30acf1d5007..7e3a91ca12e 100644 --- a/vnext/ReactWin32.nuspec +++ b/vnext/ReactWin32.nuspec @@ -2,11 +2,14 @@ OfficeReact.Win32 - __BuildBuildNumber__ + $npmVersion$ Contains Windows Implementation of React-Native Microsoft https://office.visualstudio.com/ISS/_git/sdx-platform false + diff --git a/vnext/ReactWindows.sln b/vnext/ReactWindows.sln index 2459644e957..8afc153534f 100644 --- a/vnext/ReactWindows.sln +++ b/vnext/ReactWindows.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27310.2036 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29009.5 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "React.Windows.Universal.SampleApp", "Universal.SampleApp\React.Windows.Universal.SampleApp.vcxproj", "{8B88FFAE-4DBC-49A2-AFA5-D2477D4AD189}" ProjectSection(ProjectDependencies) = postProject @@ -45,9 +45,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig Directory.Build.props = Directory.Build.props + Directory.Build.targets = Directory.Build.targets NuGet.Config = NuGet.Config - ReactWin32.nuspec = ReactWin32.nuspec ReactUwp.nuspec = ReactUwp.nuspec + ReactWin32.nuspec = ReactWin32.nuspec README.md = README.md EndProjectSection EndProject diff --git a/vnext/ReactWindowsCore/DevSettings.h b/vnext/ReactWindowsCore/DevSettings.h index 874b82e1519..74f8f32ec4a 100644 --- a/vnext/ReactWindowsCore/DevSettings.h +++ b/vnext/ReactWindowsCore/DevSettings.h @@ -45,6 +45,9 @@ struct DevSettings NativeLoggingHook loggingCallback; std::function jsExceptionCallback; + /// Enables the user to set a custom root path for bundle resolution + std::string bundleRootPath; + /// Enables debugging directly in the JavaScript engine. bool useDirectDebugger{ false }; diff --git a/vnext/ReactWindowsCore/IWebSocket.h b/vnext/ReactWindowsCore/IWebSocket.h index 1aa8e4251e3..3b175a6ddbe 100644 --- a/vnext/ReactWindowsCore/IWebSocket.h +++ b/vnext/ReactWindowsCore/IWebSocket.h @@ -7,9 +7,11 @@ #include #include -namespace Microsoft { -namespace React { +namespace Microsoft::React { +/// +/// Defines the core functionality for a native WebSocket client resource. +/// struct IWebSocket { #pragma region Aliases @@ -17,52 +19,59 @@ struct IWebSocket using Protocols = std::vector; using Options = std::map; - #pragma endregion // Aliases + #pragma endregion Aliases #pragma region Inner types + /// + /// As defined in RFC6455. + /// enum class ReadyState : std::uint16_t { Connecting = 0, // Handle initialized - Open = 1, // Ready to send - Closing = 2, // Currently closing - Closed = 3, // Closed or failed to open - Size = 4 + Open = 1, // Ready to send + Closing = 2, // Currently closing + Closed = 3, // Closed or failed to open + Size = 4 // Metavalue representing the number of entries in this enum. }; enum class ErrorType : size_t { - None = 0, + None = 0, Resolution = 1, Connection = 2, - Handshake = 3, - Ping = 4, - Send = 5, - Receive = 6, - Close = 7, - Size = 8 + Handshake = 3, + Ping = 4, + Send = 5, + Receive = 6, + Close = 7, + Size = 8 // Metavalue representing the number of entries in this enum. }; + /// + /// As defined in https://tools.ietf.org/html/rfc6455#section-7.4 + /// enum class CloseCode : std::uint16_t { // Keep in sync with RFC 6455 specification - None = 0, - Normal = 1000, - GoingAway = 1001, - ProtocolError = 1002, - UnknownData = 1003, - Reserved1 = 1004, - NoStatus = 1005, - Abnormal = 1006, - BadPayload = 1007, - PolicyError = 1008, - TooBig = 1009, + None = 0, + Normal = 1000, + GoingAway = 1001, + ProtocolError = 1002, + UnknownData = 1003, + Reserved1 = 1004, + NoStatus = 1005, + Abnormal = 1006, + BadPayload = 1007, + PolicyError = 1008, + TooBig = 1009, NeedsExtension = 1010, - InternalError = 1011, + InternalError = 1011, ServiceRestart = 1012, - TryAgainLater = 1013, - Reserved2 = 1014, - Reserved3 = 1015, + TryAgainLater = 1013, + Reserved2 = 1014, + Reserved3 = 1015, + Size = 17 // Metavalue representing the number of entries in this enum. }; struct Error @@ -71,8 +80,15 @@ struct IWebSocket const ErrorType Type; }; - #pragma endregion // Inner types + #pragma endregion Inner types + /// + /// Creates an IWebSocket instance. + /// + /// + /// WebSocket URL address the instance will connect to. + /// The address's scheme can be either ws:// or wss://. + /// static std::unique_ptr Make(const std::string& url); // Only use if a legacy implementation is required as fallback. @@ -80,34 +96,101 @@ struct IWebSocket virtual ~IWebSocket() {} - /// - // Parameters: - // - // protocols - vector of protocols - // options - map of headers - /// + /// + /// Establishes a continuous connection with the remote endpoint. + /// + /// + /// Currently unused + /// + /// + /// HTTP header fields passed by the remote endpoint, to be used in the handshake process. + /// virtual void Connect(const Protocols& protocols = {}, const Options& options = {}) = 0; + + /// + /// Sends a ping frame to the remote endpoint. + /// virtual void Ping() = 0; + + /// + /// Sends a text message to the remote endpoint. + /// + /// + /// UTF8-encoded string of arbitrary length. + /// virtual void Send(const std::string& message) = 0; + + /// + /// Sends a non-plain-text message to the remote endpoint. + /// + /// + /// Binary message encoded in Base64 format. + /// virtual void SendBinary(const std::string& base64String) = 0; + + /// + /// Terminates this resource's connection to the remote endpoint. + /// This instance can't be restarted or re-connected afterwards. + /// + /// + /// + /// + /// virtual void Close(CloseCode code, const std::string& reason) = 0; + /// + /// Current public state as defined in the ReadyState enum. + /// virtual ReadyState GetReadyState() const = 0; + /// + /// Sets the optional custom behavior on a successful connection. + /// + /// + /// virtual void SetOnConnect(std::function&& handler) = 0; + + /// + /// Sets the optional custom behavior on a successful ping to the remote endpoint. + /// + /// + /// virtual void SetOnPing(std::function&& handler) = 0; + + /// + /// Sets the optional custom behavior on a message sending. + /// + /// + /// virtual void SetOnSend(std::function&& handler) = 0; + + /// + /// Sets the optional custom behavior to run when there is an incoming message. + /// + /// + /// virtual void SetOnMessage(std::function&& handler) = 0; + + /// + /// Sets the optional custom behavior to run when this instance is closed. + /// + /// + /// virtual void SetOnClose(std::function&& handler) = 0; + + /// + /// Sets the optional custom behavior on an error condition. + /// + /// + /// virtual void SetOnError(std::function&& handler) = 0; }; -} } // namespace facebook::react +} // namespace Microsoft::React // Deprecated. Keeping for compatibility with dependent code. -namespace facebook { -namespace react { +namespace facebook::react { using IWebSocket = Microsoft::React::IWebSocket; -} } // namespace facebook::react +} // namespace facebook::react diff --git a/vnext/ReactWindowsCore/Modules/AppThemeModule.cpp b/vnext/ReactWindowsCore/Modules/AppThemeModule.cpp new file mode 100644 index 00000000000..213a9b093db --- /dev/null +++ b/vnext/ReactWindowsCore/Modules/AppThemeModule.cpp @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "AppThemeModule.h" + +namespace react { namespace windows { + +// +// AppTheme +// + +AppTheme::AppTheme() = default; +AppTheme::~AppTheme() = default; + +const std::string AppTheme::getCurrentTheme() +{ + return AppTheme::light; +} + +bool AppTheme::getIsHighContrast() +{ + return false; +} + +folly::dynamic AppTheme::getHighContrastColors() +{ + return {}; +} + +// +// AppThemeModule +// + +AppThemeModule::AppThemeModule(std::shared_ptr&& appTheme) + : m_appTheme(std::move(appTheme)) +{ +} + +auto AppThemeModule::getConstants() -> std::map +{ + return { + { "initialAppTheme", folly::dynamic { m_appTheme->getCurrentTheme() } }, + { "initialHighContrast", folly::dynamic { m_appTheme->getIsHighContrast() }}, + { "initialHighContrastColors", folly::dynamic {m_appTheme->getHighContrastColors()}} + }; +} + +auto AppThemeModule::getMethods() -> std::vector +{ + return { }; +} + +} } // namespace react::windows diff --git a/vnext/ReactWindowsCore/Modules/AppThemeModule.h b/vnext/ReactWindowsCore/Modules/AppThemeModule.h new file mode 100644 index 00000000000..da1a693457f --- /dev/null +++ b/vnext/ReactWindowsCore/Modules/AppThemeModule.h @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include + +namespace react { namespace windows { + +class AppTheme +{ +public: + static inline const std::string dark = "dark"; + static inline const std::string light = "light"; + + AppTheme(); + virtual ~AppTheme(); + + virtual const std::string getCurrentTheme(); + virtual bool getIsHighContrast(); + virtual folly::dynamic getHighContrastColors(); +}; + +class AppThemeModule : public facebook::xplat::module::CxxModule +{ +public: + static inline const std::string name = "RTCAppTheme"; + + AppThemeModule(std::shared_ptr && appTheme); + + // CxxModule + std::string getName() override { return name; }; + auto getConstants() -> std::map override; + auto getMethods() -> std::vector override; + +private: + std::shared_ptr m_appTheme; +}; + +} } // namespace react::windows diff --git a/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj b/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj index 7ec810dc6f0..57653e71e36 100644 --- a/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj +++ b/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj @@ -5,10 +5,6 @@ Debug ARM - - Debug - x86 - Debug x64 @@ -17,15 +13,10 @@ Release ARM - - Release - x86 - Release x64 - Debug Win32 @@ -67,10 +58,10 @@ NotUsing false true - - REACTWINDOWS_BUILD;NOMINMAX;FOLLY_NO_CONFIG;WIN32_LEAN_AND_MEAN;WIN32=0;RN_EXPORT=;CHAKRACORE;NOJSC;%(PreprocessorDefinitions) + REACTWINDOWS_BUILD;NOMINMAX;FOLLY_NO_CONFIG;WIN32=0;RN_EXPORT=;CHAKRACORE;%(PreprocessorDefinitions) $(ReactNativeWindowsDir);$(ReactNativeWindowsDir)include;$(ReactNativeWindowsDir)include\ReactWindowsCore;$(ReactNativeDir)\ReactCommon;$(ReactNativeWindowsDir)stubs;$(FollyDir);$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) false @@ -118,6 +109,7 @@ + @@ -139,6 +131,7 @@ + @@ -163,12 +156,12 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + \ No newline at end of file diff --git a/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj.filters b/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj.filters index 85df48167eb..0db328a68c8 100644 --- a/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj.filters +++ b/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj.filters @@ -41,6 +41,9 @@ Modules + + Modules + @@ -131,6 +134,9 @@ Modules + + Modules + diff --git a/vnext/ReactWindowsCore/Utils.cpp b/vnext/ReactWindowsCore/Utils.cpp index da629c6cc6f..1eaa2653f2e 100644 --- a/vnext/ReactWindowsCore/Utils.cpp +++ b/vnext/ReactWindowsCore/Utils.cpp @@ -6,8 +6,7 @@ using namespace std; -namespace Microsoft { -namespace React { +namespace Microsoft::React { Url::Url(const string& source) { @@ -51,13 +50,12 @@ string Url::Target() return path.append("?").append(queryString); } -} } // namespace Microsoft::React +} // namespace Microsoft::React // Folly/folly/SafeAssert.cpp brings in a bunch of file APIs that we otherwise dont need // And we probably want to look at some other functionality for reporting errors at // some point anyway. For now, just stub them out. -namespace folly { -namespace detail { +namespace folly::detail { namespace { void writeStderr(const char* s, size_t len) { @@ -80,6 +78,5 @@ void assertionFailure( std::terminate(); } -} // namespace detail -} // namespace folly +} // namespace folly::detail diff --git a/vnext/ReactWindowsCore/Utils.h b/vnext/ReactWindowsCore/Utils.h index a79bdfc3951..ebeafaa4317 100644 --- a/vnext/ReactWindowsCore/Utils.h +++ b/vnext/ReactWindowsCore/Utils.h @@ -5,8 +5,7 @@ #include -namespace Microsoft { -namespace React { +namespace Microsoft::React { struct Url { @@ -21,12 +20,11 @@ struct Url std::string Target(); }; -} } // namespace Microsoft::React +} // namespace Microsoft::React // Deprecated. Keeping for compatibility. -namespace facebook { -namespace react { +namespace facebook::react { using Url = Microsoft::React::Url; -} } // namespace facebook::react +} // namespace facebook::react diff --git a/vnext/ReactWindowsCore/WebSocketModule.h b/vnext/ReactWindowsCore/WebSocketModule.h index 4f0bfd270d2..d7bfadec70e 100644 --- a/vnext/ReactWindowsCore/WebSocketModule.h +++ b/vnext/ReactWindowsCore/WebSocketModule.h @@ -6,9 +6,12 @@ #include #include "IWebSocket.h" -namespace Microsoft { -namespace React { +namespace Microsoft::React { +/// +/// Realizes NativeModules projection. +/// See react-native/Libraries/WebSocket/WebSocket.js +/// class WebSocketModule : public facebook::xplat::module::CxxModule { public: @@ -23,23 +26,46 @@ class WebSocketModule : public facebook::xplat::module::CxxModule }; WebSocketModule(); + + /// + /// + /// std::string getName(); + + /// + /// + /// virtual std::map getConstants(); + + /// + /// + /// + /// See See react-native/Libraries/WebSocket/WebSocket.js virtual std::vector getMethods(); private: + /// + /// Notifies an event to the current React Instance. + /// void SendEvent(std::string&& eventName, folly::dynamic&& parameters); - IWebSocket* GetWebSocket(int64_t id, std::string&& url = std::string()); + /// + /// Creates or retrieves a raw IWebSocket pointer. + /// + IWebSocket* GetOrCreateWebSocket(int64_t id, std::string&& url = std::string()); + + /// + /// Keeps IWebSocket instances identified by id. + /// As defined in WebSocket.js. + /// std::map> m_webSockets; }; -} } // Microsoft::React +} // Microsoft::React // Deprecated. Keeping for compatibility. -namespace facebook { -namespace react { +namespace facebook::react { using WebSocketModule = Microsoft::React::WebSocketModule; -} } // namespace facebook::react +} // namespace facebook::react diff --git a/vnext/Scripts/OpenSSL.nuspec b/vnext/Scripts/OpenSSL.nuspec new file mode 100644 index 00000000000..a79adfe2c41 --- /dev/null +++ b/vnext/Scripts/OpenSSL.nuspec @@ -0,0 +1,26 @@ + + + + $id$ + $version$ + OpenSSL for Windows Desktop - Static Library. + Microsoft + https://www.openssl.org + false + + + + + + + + + + + + + + + + + diff --git a/vnext/Scripts/OpenSSL.targets b/vnext/Scripts/OpenSSL.targets new file mode 100644 index 00000000000..d29ffac2f64 --- /dev/null +++ b/vnext/Scripts/OpenSSL.targets @@ -0,0 +1,30 @@ + + + + + + $(MSBuildThisFileDirectory)..\..\include\$(Platform); + %(AdditionalIncludeDirectories) + + + $(MSBuildThisFileDirectory)..\..\include\x86; + %(AdditionalIncludeDirectories) + + + + + $(MSBuildThisFileDirectory)..\..\lib\$(Platform)\$(Configuration); + %(AdditionalLibraryDirectories) + + + $(MSBuildThisFileDirectory)..\..\lib\x86\$(Configuration); + %(AdditionalLibraryDirectories) + + + libeay32.lib; + ssleay32.lib; + %(AdditionalDependencies) + + + + \ No newline at end of file diff --git a/vnext/Scripts/Scripts.pssproj b/vnext/Scripts/Scripts.pssproj deleted file mode 100644 index 2ca44cd0d0b..00000000000 --- a/vnext/Scripts/Scripts.pssproj +++ /dev/null @@ -1,39 +0,0 @@ - - - Debug - 2.0 - 6CAFC0C6-A428-4d30-A9F9-700E829FEA51 - Exe - ReactNative - ReactNative - Scripts - $(ReactNativeWindowsDir)target\$(Platform)\$(Configuration)\$(MSBuildProjectName)\ - TRACE - prompt - 4 - - - true - full - false - DEBUG;$(DefineConstants) - - - pdbonly - true - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vnext/Shared/Logging.cpp b/vnext/Shared/Logging.cpp index ba0fd13a575..dedf7a183a5 100644 --- a/vnext/Shared/Logging.cpp +++ b/vnext/Shared/Logging.cpp @@ -11,10 +11,6 @@ #include #endif -#if !defined(NOJSC) -#include -#endif - namespace facebook { namespace react { namespace { @@ -34,31 +30,6 @@ static double nativePerformanceNow() { void logMarker(const ReactMarker::ReactMarkerId /*id*/, const char* /*tag*/) { } #endif - -#if !defined(NOJSC) - -JSValueRef nativePerformanceNowJSC( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], JSValueRef *exception) { - // TODO - return Value::makeNumber(ctx, 0); -} - -JSValueRef nativeLoggingHookJSC( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], JSValueRef *exception) { - // TODO - return Value::makeUndefined(ctx); -} - -#endif // !defined(NOJSC) - } // end anonymous namespace void InitializeLogging(NativeLoggingHook&& hook) { @@ -67,12 +38,6 @@ void InitializeLogging(NativeLoggingHook&& hook) { JSNativeHooks::loggingHook = LogHook; JSNativeHooks::nowHook = nativePerformanceNow; -#if !defined(NOJSC) - JSCNativeHooks::loggingHook = nativeLoggingHookJSC; - JSCNativeHooks::nowHook = nativePerformanceNowJSC; - // JSCNativeHooks::installPerfHooks = addNativePerfLoggingHooksJSC; -#endif - #if !defined(OSS_RN) ReactMarker::logTaggedMarker = logMarker; #endif diff --git a/vnext/Shared/OInstance.cpp b/vnext/Shared/OInstance.cpp index 677d655d7d2..98496d2e5c3 100644 --- a/vnext/Shared/OInstance.cpp +++ b/vnext/Shared/OInstance.cpp @@ -576,7 +576,9 @@ void InstanceImpl::loadBundleInternal(std::string&& jsBundleRelativePath, bool s } #else - auto bundleString = std::make_unique<::react::uwp::StorageFileBigString>("ms-appx:///Bundle/" + jsBundleRelativePath + ".bundle"); + std::string bundlePath = m_devSettings->bundleRootPath + jsBundleRelativePath + ".bundle"; + + auto bundleString = std::make_unique<::react::uwp::StorageFileBigString>(bundlePath); m_innerInstance->loadScriptFromString(std::move(bundleString), #if !defined(OSS_RN) 0 /*bundleVersion*/, diff --git a/vnext/Shared/Shared.vcxitems b/vnext/Shared/Shared.vcxitems index d101774fadf..0bab515b8ad 100644 --- a/vnext/Shared/Shared.vcxitems +++ b/vnext/Shared/Shared.vcxitems @@ -20,9 +20,15 @@ - + + + NOJSC;%(PreprocessorDefinitions) + - + + + NOJSC;%(PreprocessorDefinitions) + diff --git a/vnext/Universal.IntegrationTests/RNTesterIntegrationTests.cpp b/vnext/Universal.IntegrationTests/RNTesterIntegrationTests.cpp index c9426a1881f..d5a03883765 100644 --- a/vnext/Universal.IntegrationTests/RNTesterIntegrationTests.cpp +++ b/vnext/Universal.IntegrationTests/RNTesterIntegrationTests.cpp @@ -8,9 +8,7 @@ using namespace facebook::react::test; using namespace Microsoft::VisualStudio::CppUnitTestFramework; -namespace Microsoft { -namespace VisualStudio { -namespace CppUnitTestFramework { +namespace Microsoft::VisualStudio::CppUnitTestFramework { template <> std::wstring ToString(const facebook::react::test::TestStatus& status) @@ -18,7 +16,7 @@ std::wstring ToString(const facebook::react:: return ToString(static_cast(status)); } -} } } // namespace Microsoft::VisualStudio::CppUnitTestFramework +} // namespace Microsoft::VisualStudio::CppUnitTestFramework TEST_CLASS(RNTesterIntegrationTests) { diff --git a/vnext/Universal.IntegrationTests/React.Windows.Universal.IntegrationTests.vcxproj b/vnext/Universal.IntegrationTests/React.Windows.Universal.IntegrationTests.vcxproj index 398ab919a80..1098be2450a 100644 --- a/vnext/Universal.IntegrationTests/React.Windows.Universal.IntegrationTests.vcxproj +++ b/vnext/Universal.IntegrationTests/React.Windows.Universal.IntegrationTests.vcxproj @@ -13,23 +13,14 @@ - - Debug - x86 - Debug x64 - - Release - x86 - Release x64 - Debug Win32 @@ -58,11 +49,11 @@ ;$(ReactNativeWindowsDir)IntegrationTests;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories) 4453;28204;4068;4146;%(DisableSpecificWarnings) - _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN;NOMINMAX;FOLLY_NO_CONFIG;RN_EXPORT=;WIN32=0;NOJSC;_HAS_AUTO_PTR_ETC;%(PreprocessorDefinitions) + _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;NOMINMAX;FOLLY_NO_CONFIG;RN_EXPORT=;WIN32=0;NOJSC;_HAS_AUTO_PTR_ETC;%(PreprocessorDefinitions) /bigobj %(AdditionalOptions) - $(ReactNativeWindowsDir)target\$(Platform)\$(Configuration)\ReactUWP\React.uwp.lib;%(AdditionalDependencies) + $(ReactNativeWindowsDir)target\$(PlatformTarget)\$(Configuration)\ReactUWP\React.uwp.lib;%(AdditionalDependencies) @@ -105,7 +96,10 @@ MainPage.xaml - + + + NOJSC;%(PreprocessorDefinitions) + App.xaml @@ -137,14 +131,12 @@ - - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + \ No newline at end of file diff --git a/vnext/Universal.IntegrationTests/UniversalTestInstance.h b/vnext/Universal.IntegrationTests/UniversalTestInstance.h index daf56aeaf73..f455ab7aa96 100644 --- a/vnext/Universal.IntegrationTests/UniversalTestInstance.h +++ b/vnext/Universal.IntegrationTests/UniversalTestInstance.h @@ -24,7 +24,7 @@ class UniversalTestInstance : public ITestInstance void DetachRootView() noexcept; std::shared_ptr GetInnerInstance() const noexcept override; - #pragma endregion // ITestInstance members + #pragma endregion ITestInstance members private: ::react::uwp::ReactInstanceCreator m_instanceCreator; }; diff --git a/vnext/Universal.IntegrationTests/packages.config b/vnext/Universal.IntegrationTests/packages.config index 025755b87c9..cdb7bb377d4 100644 --- a/vnext/Universal.IntegrationTests/packages.config +++ b/vnext/Universal.IntegrationTests/packages.config @@ -1,5 +1,4 @@  - \ No newline at end of file diff --git a/vnext/Universal.SampleApp/App.xaml b/vnext/Universal.SampleApp/App.xaml index 10bb2a7542b..75b7e794414 100644 --- a/vnext/Universal.SampleApp/App.xaml +++ b/vnext/Universal.SampleApp/App.xaml @@ -1,8 +1,7 @@ - + xmlns:local="using:WindowsSampleApp"> diff --git a/vnext/Universal.SampleApp/React.Windows.Universal.SampleApp.vcxproj b/vnext/Universal.SampleApp/React.Windows.Universal.SampleApp.vcxproj index aac0b19c6e1..6312cb406fc 100644 --- a/vnext/Universal.SampleApp/React.Windows.Universal.SampleApp.vcxproj +++ b/vnext/Universal.SampleApp/React.Windows.Universal.SampleApp.vcxproj @@ -14,10 +14,6 @@ Debug ARM - - Debug - x86 - Debug x64 @@ -26,15 +22,10 @@ Release ARM - - Release - x86 - Release x64 - Debug Win32 @@ -67,7 +58,7 @@ /await /bigobj /Zc:twoPhase- %(AdditionalOptions) 4453;4800;28204;4146;%(DisableSpecificWarnings) $(FollyDir);$(ReactNativeDir)\ReactCommon;$(ReactNativeWindowsDir)stubs;$(ReactNativeWindowsDir)include;$(ReactNativeWindowsDir)ReactWindowsCore;$(ReactNativeWindowsDir)include\ReactWindowsCore;$(ReactNativeWindowsDir)include\ReactUWP;$(YogaDir);%(AdditionalIncludeDirectories) - _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;FOLLY_NO_CONFIG;NOMINMAX;NOJSC;_HAS_AUTO_PTR_ETC;RN_EXPORT=;%(PreprocessorDefinitions) + FOLLY_NO_CONFIG;NOMINMAX;NOJSC;_HAS_AUTO_PTR_ETC;RN_EXPORT=;%(PreprocessorDefinitions) true Use @@ -116,6 +107,7 @@ true + @@ -161,12 +153,12 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + \ No newline at end of file diff --git a/vnext/Universal.SampleApp/React.Windows.Universal.SampleApp.vcxproj.filters b/vnext/Universal.SampleApp/React.Windows.Universal.SampleApp.vcxproj.filters index 1ff6aeb29dd..fc241e60a1a 100644 --- a/vnext/Universal.SampleApp/React.Windows.Universal.SampleApp.vcxproj.filters +++ b/vnext/Universal.SampleApp/React.Windows.Universal.SampleApp.vcxproj.filters @@ -78,6 +78,7 @@ Bundle\Universal.SampleApp + diff --git a/vnext/Universal.SampleApp/image.uwp.js b/vnext/Universal.SampleApp/image.uwp.js new file mode 100644 index 00000000000..14a0ea63b76 --- /dev/null +++ b/vnext/Universal.SampleApp/image.uwp.js @@ -0,0 +1,94 @@ +/** + * Sample React Native App + * https://github.com/facebook/react-native + * @flow + */ + +import React, { Component } from 'react'; +import { Picker } from 'react-native-windows'; +import { + AppRegistry, + Image, + View, + Text, + Switch, + StyleSheet +} from 'react-native'; + +const largeImageUri = 'https://cdn.freebiesupply.com/logos/large/2x/react-logo-png-transparent.png'; +const smallImageUri = 'http://facebook.github.io/react-native/img/header_logo.png'; + +export default class Bootstrap extends Component { + state = { + selectedResizeMode: 'center', + useLargeImage: false, + imageUrl: 'http://facebook.github.io/react-native/img/header_logo.png' + }; + + switchImageUrl = () => { + const useLargeImage = !this.state.useLargeImage; + this.setState({ useLargeImage }); + + const imageUrl = useLargeImage ? largeImageUri : smallImageUri; + this.setState({ imageUrl }); + } + + render() { + return ( + + + + ResizeMode + this.setState({ selectedResizeMode: value })}> + + + + + + + + + Image Size + Small + + Large + + + + + + + + ); + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + marginBottom: 5 + }, + rowContainer: { + flexDirection: 'row', + alignItems: 'center' + }, + imageContainer: { + marginTop: 5, + backgroundColor: 'orange', + height: '50%', + width: '75%' + }, + image: { + height: '100%', + width: '100%' + }, + title: { + fontWeight: 'bold', + margin: 5, + width: 80 + } +}); + +AppRegistry.registerComponent('Bootstrap', () => Bootstrap); diff --git a/vnext/Universal.SampleApp/index.uwp.js b/vnext/Universal.SampleApp/index.uwp.js index 9676460384a..04596d9bcd9 100644 --- a/vnext/Universal.SampleApp/index.uwp.js +++ b/vnext/Universal.SampleApp/index.uwp.js @@ -262,6 +262,15 @@ export default class Bootstrap extends Component { onError={() => { console.log('image onError!'); }} /> + + + this.setState({ checkBoxIsOn: value })} diff --git a/vnext/Universal.UnitTests/React.Windows.Universal.UnitTests.vcxproj b/vnext/Universal.UnitTests/React.Windows.Universal.UnitTests.vcxproj index d5cc54d545c..1576415dd23 100644 --- a/vnext/Universal.UnitTests/React.Windows.Universal.UnitTests.vcxproj +++ b/vnext/Universal.UnitTests/React.Windows.Universal.UnitTests.vcxproj @@ -20,15 +20,6 @@ Release x64 - - Debug - x86 - - - Release - x86 - - Debug Win32 @@ -62,12 +53,12 @@ /await /bigobj %(AdditionalOptions) $(ReactNativeWindowsDir)include\ReactWindowsCore;$(ReactNativeWindowsDir)include\ReactUWP;$(ReactNativeWindowsDir)ReactWindowsCore;$(ReactNativeWindowsDir)ReactUWP;$(ReactNativeWindowsDir)include;$(ReactNativeWindowsDir)stubs;$(ReactNativeWindowsDir)Shared;$(FollyDir);$(ReactNativeDir)\ReactCommon;$(YogaDir);%(AdditionalIncludeDirectories) - RN_PLATFORM=uwp;USE_EDGEMODE_JSRT;GTEST_LANG_CXX11=1;WIN32_LEAN_AND_MEAN;NOMINMAX;FOLLY_NO_CONFIG;RN_EXPORT=;WIN32=0;WINRT=1;NOJSC;_HAS_AUTO_PTR_ETC;BOOST_ASIO_WINDOWS_APP;BOOST_BEAST_USE_WIN32_FILE=0;%(PreprocessorDefinitions) + RN_PLATFORM=uwp;USE_EDGEMODE_JSRT;GTEST_LANG_CXX11=1;NOMINMAX;FOLLY_NO_CONFIG;RN_EXPORT=;WIN32=0;WINRT=1;NOJSC;_HAS_AUTO_PTR_ETC;BOOST_ASIO_WINDOWS_APP;BOOST_BEAST_USE_WIN32_FILE=0;%(PreprocessorDefinitions) true Use - $(ReactNativeWindowsDir)target\$(Platform)\$(Configuration)\ReactUWP\React.uwp.lib;Kernel32.lib;WindowsApp.lib;%(AdditionalDependencies) + $(ReactNativeWindowsDir)target\$(PlatformTarget)\$(Configuration)\ReactUWP\React.uwp.lib;Kernel32.lib;WindowsApp.lib;%(AdditionalDependencies) false false @@ -141,14 +132,12 @@ - - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + \ No newline at end of file diff --git a/vnext/Universal.UnitTests/packages.config b/vnext/Universal.UnitTests/packages.config index 025755b87c9..cdb7bb377d4 100644 --- a/vnext/Universal.UnitTests/packages.config +++ b/vnext/Universal.UnitTests/packages.config @@ -1,5 +1,4 @@  - \ No newline at end of file diff --git a/vnext/docs/GettingStarted.md b/vnext/docs/GettingStarted.md index c031a5bc6c3..cfc9b6d3bca 100644 --- a/vnext/docs/GettingStarted.md +++ b/vnext/docs/GettingStarted.md @@ -4,7 +4,7 @@ This is a summary of setup steps needed to install and work with React Native fo ## System requirements * You can run React-Native for Windows10 apps only on Windows 10 devices and Windows version: 10.0.15063.0 or higher. -* [Visual Studio 2017](https://www.visualstudio.com/downloads) with the following options: +* [Visual Studio 2019](https://www.visualstudio.com/downloads) with the following options: * Workloads * Universal Windows Platform development * Enable the optional 'C++ Universal Windows Platform tools' @@ -13,7 +13,6 @@ This is a summary of setup steps needed to install and work with React Native fo * Development activities * Node.js development support * SDKs, libraries, and frameworks per your versioning needs - * Windows 10 SDK (10.0.15063.0) * Windows 10 SDK (10.0.18362.0) ## Dependencies @@ -89,77 +88,78 @@ A new Command Prompt window will open with the React packager as well as a `reac - Make sure you have installed [dependencies](#dependencies) - Install [Git](https://git-scm.com/download/win) if you don't have it installed in your development machine -#### Build Steps -* Clone the repo - ```cmd - git clone https://github.com/microsoft/react-native-windows.git - cd react-native-windows - ``` +#### Build Steps +* Clone the repo + ```cmd + git clone https://github.com/microsoft/react-native-windows.git + cd react-native-windows + ``` -* Install dependencies. This step may take a while on the first run due to dependency download. - ```cmd - cd vnext - npm install - ``` +* Install dependencies. This step may take a while on the first run due to dependency download. + ```cmd + cd vnext + npm install + nuget restore + ``` -* Run `npm run build` in the vnext folder. +* Run `npm run build` in the vnext folder. * Run `Scripts\launchPackager.bat`. This is needed to ensure the JS files can be packaged and bundled to the UWP app. * Make sure Chrome is running if you're not already running it #### Running the Playground app -* Nuget restore through the command line. There is an outstanding issue [#2312](https://github.com/microsoft/react-native-windows/issues/2312) that blocks restoring Nuget dependencies using VS. +* Nuget restore through the command line. There is an outstanding issue [#2312](https://github.com/microsoft/react-native-windows/issues/2312) that blocks restoring Nuget dependencies using VS. ```cmd cd Playground ..\react-native-windows\vnext\Playground>nuget restore Playground.sln -PackagesDirectory packages ``` * Build solution. - * Using MSBuild - ```cmd - MSBuild.exe [/p:Platform=$(TargetPlatform)] [/p:Configuration=$(TargetConfiguration)] - ``` - - * Using Visual Studio IDE - 1. Open `Playground.sln`. - 2. Set your `Platform` to `x86` or `x64` and `Configuration ` to `Debug`. + * Using MSBuild + ```cmd + MSBuild.exe [/p:Platform=$(TargetPlatform)] [/p:Configuration=$(TargetConfiguration)] + ``` + + * Using Visual Studio IDE + 1. Open `Playground.sln`. + 2. Set your `Platform` to `x86` or `x64` and `Configuration ` to `Debug`. 3. Select `Project / Build Solution (Ctrl+Shift+B)` -* In Visual Studio, set Playground as the StartUp Project. +* In Visual Studio, set Playground as the StartUp Project. -* Run project (`F5` or `Debug / Start Debugging`). +* Run project (`F5` or `Debug / Start Debugging`). You now see your new app and Chrome should have loaded `http://localhost:8081/debugger-ui/` in a new tab. Press `F12` or `Ctrl+Shift+I` in Chrome to open its Developer Tools. :tada: -#### Running the Sample Universal Windows App -* Build solution. - * Using MSBuild - ```cmd - MSBuild.exe [/p:Platform=$(TargetPlatform)] [/p:Configuration=$(TargetConfiguration)] - ``` +#### Running the Sample Universal Windows App +* Build solution. + * Using MSBuild + ```cmd + MSBuild.exe [/p:Platform=$(TargetPlatform)] [/p:Configuration=$(TargetConfiguration)] + ``` - * Using Visual Studio IDE - 1. Open `ReactWindows-UWP.sln`. - 2. Set your `Platform` to `x86` or `x64` and `Configuration ` to `Debug`. + * Using Visual Studio IDE + 1. Open `ReactWindows-UWP.sln`. + 2. Set your `Platform` to `x86` or `x64` and `Configuration ` to `Debug`. 3. Select `Project / Build Solution (Ctrl+Shift+B)` -* In Visual Studio, set React.Windows.Universal.SampleApp as the StartUp Project. +* In Visual Studio, set React.Windows.Universal.SampleApp as the StartUp Project. + +* If you didn't already, make sure to set your `Platform` to `x86` or `x64` and `Configuration ` to `Debug`. -* If you didn't already, make sure to set your `Platform` to `x86` or `x64` and `Configuration ` to `Debug`. +* Run project (`F5` or `Debug / Start Debugging`). -* Run project (`F5` or `Debug / Start Debugging`). +* Press the "Load" button on the left side of the Windows 10 application window that appears. -* Press the "Load" button on the left side of the Windows 10 application window that appears. + The selected React Native component (defaulted to `Bootstrap`) should get loaded in the bottom of the application window. Chrome should have loaded `http://localhost:8081/debugger-ui/` in a new tab. Press `F12` or `Ctrl+Shift+I` in Chrome to open its Developer Tools. :tada: - The selected React Native component (defaulted to `Bootstrap`) should get loaded in the bottom of the application window. Chrome should have loaded `http://localhost:8081/debugger-ui/` in a new tab. Press `F12` or `Ctrl+Shift+I` in Chrome to open its Developer Tools. :tada: + Try these samples by entering the JS file name and App names below into the textboxes at the top of the application window before pressing "Load": + - Sample: JavaScript file: `Universal.SampleApp\index.uwp` App Name: `Bootstrap` + - RNTester: JavaScript file: `lib\RNTester\RNTesterApp.uwp` App Name: `RNTesterApp` - Try these samples by entering the JS file name and App names below into the textboxes at the top of the application window before pressing "Load": - - Sample: JavaScript file: `Universal.SampleApp\index.uwp` App Name: `Bootstrap` - - RNTester: JavaScript file: `lib\RNTester\RNTesterApp.uwp` App Name: `RNTesterApp` - ## Troubleshooting * If after running the app the packager does not update (or) app does not show React Native content - close the packager command prompt window and the app, run `yarn start` and run the app again. Issue [#2311](https://github.com/microsoft/react-native-windows/issues/2311) is tracking a known issue on this. -* If you get a red error box in your UWP app window with the error message : `ERROR: Instance failed to start. A connection with the server cannot be established`, make sure you have the packager running using `yarn start` and run the app again. +* If you get a red error box in your UWP app window with the error message : `ERROR: Instance failed to start. A connection with the server cannot be established`, make sure you have the packager running using `yarn start` and run the app again. * If you are trying to run your `react-native` app on iOS/Android while using this `vnext` implementation for developing/running on Windows, you will encounter errors while running the app for other platforms. This will be fixed once we address Issues [#2264](https://github.com/microsoft/react-native-windows/issues/2264) and [#2535](https://github.com/microsoft/react-native-windows/issues/2535). Until this is fixed, please refer to [this comment](https://github.com/microsoft/react-native-windows/issues/2515#issuecomment-497375198) which describes the workaround for running on other platforms while developing for windows using `vnext`. diff --git a/vnext/docs/ProjectStructure.md b/vnext/docs/ProjectStructure.md new file mode 100644 index 00000000000..9219cd5c080 --- /dev/null +++ b/vnext/docs/ProjectStructure.md @@ -0,0 +1,100 @@ +# MSBuild Project Structure + +This is a description of each of the core projects, their purpose and output artifacts.
+Sample applications are not covered. + +## Alphabetical Index +- [Chakra\Chakra.vcxitems](#Chakra) +- [Desktop\React.Windows.Desktop.vcxproj](#React.Windows.Desktop) +- **[Desktop.DLL\React.Windows.Desktop.DLL.vcxproj](#React.Windows.Desktop.DLL)** +- [Desktop.IntegrationTests\React.Windows.Desktop.IntegrationTests.vcxproj](#React.Windows.Desktop.IntegrationTests) +- [Desktop.UnitTests\React.Windows.Desktop.UnitTests.vcxproj](#React.Windows.Desktop.UnitTests) +- [Folly\Folly.vcxproj](#Folly) +- [FollyWin32\FollyWin32.vcxproj](#FollyWin32) +- [IntegrationTestScripts\IntegrationTests.njsproj](#IntegrationTests-Node-Project) +- [IntegrationTests\React.Windows.IntegrationTests.vcxproj](#React.Windows.IntegrationTests) +- [ReactCommon\ReactCommon.vcxproj](#ReactCommon) +- **[ReactUWP\ReactUWP.vcxproj](#ReactUWP)** +- [ReactWindowsCore\ReactWindowsCore.vcxproj](#ReactWindowsCore) +- [Shared\Shared.vcxitems](#Shared) +- [Universal.IntegrationTests\React.Windows.Universal.IntegrationTests.vcxproj](#React.Windows.Universal.IntegrationTests) +- [Universal.UnitTests\React.Windows.Universal.UnitTests.vcxproj](#React.Windows.Universal.UnitTests) + +## Common Projects + +### ReactWindowsCore +*Static Library*
+Contains common functionality for both Desktop and Universal Windows variants. + +### Shared +*Shared Items (no build artifact)*
+Holds sources common to both Windows variants, that require different build configuration +(i.e. compiler flags, language standard). + +### ReactCommon +*Static Library*
+React Native core, cross-platform C++ types and interfaces.
+Sources provided as part of the `react-native` Node dependency. Not part of this repository.
+See https://github.com/facebook/react-native/tree/v0.59.9/ReactCommon. + +### Folly +*Static Library*
+Folly variant type system for JavaScript/C++ interoperability.
+Sources provided as part of the `react-native` Node dependency. Not part of this repository. + +### Chakra +*Shared Items (no build artifact)*
+ChakraCore bridging layer. May use different compiler flags between Windows variants. + +### React.Windows.IntegrationTests +*Static Library*
+Common framework for running out of process and/or full React instance testing. + +### IntegrationTests (Node Project) +*MSBuild Node project. For reading/editing purposes only (no build artifact)*
+Set of JavaScript component tests for [RNTester](https://github.com/facebook/react-native/tree/v0.59.9/RNTester). +Sources provided as part of the `react-native` Node dependency. Not part of this repository.
+See https://github.com/facebook/react-native/tree/v0.59.9/IntegrationTests. + +## Windows Desktop Projects + +### React.Windows.Desktop +*Static Library*
+Set of Native Modules, View Managers and Executors for Windows Desktop. + +### React.Windows.Desktop.DLL +*Dynamic Library*
+Shared library that exports the intended public API surface for [React.Windows.Desktop](#React.Windows.Desktop).
+**Main artifact to use in Windows Desktop applications.** + +### React.Windows.Desktop.UnitTests +*VSTest Dynamic Library* +Set of isolated (mocked) tests for types defined in [React.Windows.Desktop](#React.Windows.Desktop). + +### React.Windows.Desktop.IntegrationTests +*VSTest Dynamic Library* +Set of component tests that validate functionality against external runtime components +(i.e. networking servers, file system, React Native applications, external processes).
+Validates [React.Windows.Desktop.DLL](#React.Windows.Desktop.DLL). + +### FollyWin32 +*Static Library*
+Superset of Folly APIs only available and required by [React.Windows.Desktop](#React.Windows.Desktop).
+Sources provided as part of the `react-native` Node dependency. Not part of this repository. + +## Windows Universal Projects + +### ReactUWP +*Dynamic Library*
+Set of Native Modules, View Managers and Executors for Windows Universal.
+**Main artifact to use in Windows Universal applications.** + +### React.Windows.Universal.UnitTests +*VSTest Dynamic Library* +Set of isolated (mocked) tests for types defined in [ReactUWP](#ReactUWP). + +### React.Windows.Universal.IntegrationTests +*VSTest Dynamic Library* +Set of component tests that validate functionality against external runtime components +(i.e. networking servers, file system, React Native applications, external processes).
+Validates [ReactUWP](#ReactUWP). diff --git a/vnext/include/CppWinRTIncludes.h b/vnext/include/CppWinRTIncludes.h index 580a492757f..19b797a4bb5 100644 --- a/vnext/include/CppWinRTIncludes.h +++ b/vnext/include/CppWinRTIncludes.h @@ -4,8 +4,22 @@ #pragma once #include +#include +#include +#include +#include +#include +#include namespace winrt { + using namespace ::winrt::Windows::UI::Xaml; using namespace ::winrt::Windows::UI::Core; + using namespace Windows::Foundation; + using namespace Windows::Foundation::Collections; + using namespace Windows::UI::Xaml; + using namespace Windows::UI::Xaml::Controls; + using namespace Windows::UI::Xaml::Controls::Primitives; + using namespace Windows::UI::Composition; + using namespace Windows::UI::Xaml::Hosting; } diff --git a/vnext/include/ReactUWP/IReactInstance.h b/vnext/include/ReactUWP/IReactInstance.h index 0071a563cef..1f862d68476 100644 --- a/vnext/include/ReactUWP/IReactInstance.h +++ b/vnext/include/ReactUWP/IReactInstance.h @@ -31,8 +31,12 @@ struct ReactInstanceSettings bool UseDirectDebugger{ false }; bool UseJsi { true }; bool EnableJITCompilation { true }; + bool EnableByteCodeCacheing { false }; + + std::string ByteCodeFileUri; std::string DebugHost; std::string DebugBundlePath; + std::string BundleRootPath; facebook::react::NativeLoggingHook LoggingCallback; std::function JsExceptionCallback; }; @@ -76,6 +80,10 @@ struct IReactInstance virtual void loadBundle(std::string&& jsBundleRelativePath) = 0; + // Returns the root path of the JS bundle. This is needed for + // classes that do not have access to the settings object. + virtual std::string GetBundleRootPath() const noexcept = 0; + // Test Hooks virtual void SetXamlViewCreatedTestHook(std::function testHook) = 0; virtual void CallXamlViewCreatedTestHook(react::uwp::XamlView view) = 0; diff --git a/vnext/include/ReactUWP/Utils/AccessibilityUtils.h b/vnext/include/ReactUWP/Utils/AccessibilityUtils.h index fdf1f60d07b..767c46c58b6 100644 --- a/vnext/include/ReactUWP/Utils/AccessibilityUtils.h +++ b/vnext/include/ReactUWP/Utils/AccessibilityUtils.h @@ -11,6 +11,6 @@ namespace react { namespace uwp { -REACTWINDOWS_API_(void) AnnounceLiveRegionChangedIfNeeded(winrt::Windows::UI::Xaml::FrameworkElement element); +REACTWINDOWS_API_(void) AnnounceLiveRegionChangedIfNeeded(const winrt::Windows::UI::Xaml::FrameworkElement& element); } } diff --git a/vnext/include/ReactUWP/Views/FrameworkElementViewManager.h b/vnext/include/ReactUWP/Views/FrameworkElementViewManager.h index c7ed85d2543..2cc6d64eb54 100644 --- a/vnext/include/ReactUWP/Views/FrameworkElementViewManager.h +++ b/vnext/include/ReactUWP/Views/FrameworkElementViewManager.h @@ -8,6 +8,12 @@ namespace react { namespace uwp { +enum class FocusCommand +{ + SetFocus = 1, + Blur = 2 +}; + class REACTWINDOWS_EXPORT FrameworkElementViewManager : public ViewManagerBase { using Super = ViewManagerBase; @@ -21,6 +27,9 @@ class REACTWINDOWS_EXPORT FrameworkElementViewManager : public ViewManagerBase void RefreshTransformMatrix(ShadowNodeBase* shadowNode); void StartTransformAnimation(winrt::UIElement uielement, winrt::Windows::UI::Composition::CompositionPropertySet transformPS); + folly::dynamic GetCommands() const override; + void DispatchCommand(XamlView viewToUpdate, int64_t commandId, const folly::dynamic& commandArgs) override; + protected: virtual void TransferProperties(XamlView oldView, XamlView newView) override; void TransferProperty(XamlView oldView, XamlView newView, winrt::Windows::UI::Xaml::DependencyProperty dp); diff --git a/vnext/include/ReactUWP/Views/KeyboardEventHandler.h b/vnext/include/ReactUWP/Views/KeyboardEventHandler.h new file mode 100644 index 00000000000..7c79b3d4c6d --- /dev/null +++ b/vnext/include/ReactUWP/Views/KeyboardEventHandler.h @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include +#include +#include +#include +#include + +#include "XamlView.h" +#include + +namespace winrt { + using namespace Windows::UI; + using namespace Windows::UI::Xaml; + using namespace Windows::UI::Xaml::Controls; + using namespace Windows::UI::Xaml::Input; + using namespace Windows::Foundation; + using namespace Windows::UI::Xaml::Media; + using namespace Windows::System; + using namespace Windows::UI::Core; +} + +namespace react { namespace uwp { + enum class HandledEventPhase + { + Capturing = 1, // match the value with EventPhase in React. EventPhase includes None, Capturing, AtTarget, Bubbling + Bubbling = 3 + }; + + struct ModifiedKeyState + { + bool altKey{ false }; + bool ctrlKey{ false }; + bool metaKey{ false }; + bool shiftKey{ false }; + bool capLocked{ false }; + }; + + struct ReactKeyboardEvent: ModifiedKeyState + { + int64_t target{ 0 }; + std::string key{}; + }; + + struct HandledKeyboardEvent: ModifiedKeyState + { + HandledEventPhase handledEventPhase{ HandledEventPhase::Bubbling }; + std::string key{}; + }; + + typedef std::function KeyboardEventCallback; + + class KeyboardEventBaseHandler { + public: + KeyboardEventBaseHandler(KeyboardEventCallback&& keyDown, KeyboardEventCallback&& keyUp); + virtual ~KeyboardEventBaseHandler() {}; + + virtual void hook(XamlView xamlView) = 0; + virtual void unhook() = 0; + + protected: + KeyboardEventCallback m_keyDownCallback; + KeyboardEventCallback m_keyUpCallback; + }; + + class PreviewKeyboardEventHandler: public KeyboardEventBaseHandler + { + public: + PreviewKeyboardEventHandler(KeyboardEventCallback&& keyDown, KeyboardEventCallback&& keyUp); + + void hook(XamlView xamlView); + void unhook(); + + private: + winrt::UIElement::PreviewKeyDown_revoker m_previewKeyDownRevoker{}; + winrt::UIElement::PreviewKeyUp_revoker m_previewKeyUpRevoker{}; + }; + + class KeyboardEventHandler : public KeyboardEventBaseHandler + { + public: + KeyboardEventHandler(KeyboardEventCallback&& keyDown, KeyboardEventCallback&& keyUp); + + void hook(XamlView xamlView); + void unhook(); + + private: + winrt::UIElement::KeyDown_revoker m_keyDownRevoker{}; + winrt::UIElement::KeyUp_revoker m_keyUpRevoker{}; + }; + + class PreviewKeyboardEventHandlerOnRoot: public PreviewKeyboardEventHandler + { + public: + PreviewKeyboardEventHandlerOnRoot(const std::weak_ptr& reactInstance); + + private: + void OnPreKeyDown(winrt::IInspectable const& sender, winrt::KeyRoutedEventArgs const& args); + void OnPreKeyUp(winrt::IInspectable const& sender, winrt::KeyRoutedEventArgs const& args); + + void DispatchEventToJs(std::string const& name, winrt::KeyRoutedEventArgs const& args); + std::weak_ptr m_wkReactInstance; + }; + + class HandledKeyboardEventHandler + { + public: + enum class KeyboardEventPhase + { + PreviewKeyUp, + PreviewKeyDown, + KeyUp, + KeyDown + }; + + HandledKeyboardEventHandler(); + + void hook(XamlView xamlView); + void unhook(); + + public: + void UpdateHandledKeyboardEvents(std::string const& propertyName, folly::dynamic const& value); + + private: + void EnsureKeyboardEventHandler(); + + void KeyboardEventHandledHandler(KeyboardEventPhase phase, winrt::IInspectable const& sender, winrt::KeyRoutedEventArgs const& args); + bool ShouldMarkKeyboardHandled(std::vector const& handledEvents, HandledKeyboardEvent currentEvent); + + std::vector m_handledKeyUpKeyboardEvents; + std::vector m_handledKeyDownKeyboardEvents; + + std::unique_ptr m_previewKeyboardEventHandler; + std::unique_ptr m_keyboardEventHandler; + }; + + struct KeyboardHelper + { + static std::vector FromJS(folly::dynamic const& obj); + static HandledKeyboardEvent CreateKeyboardEvent(HandledEventPhase phase, winrt::KeyRoutedEventArgs const& args); + static std::string FromVirtualKey(winrt::VirtualKey key, bool shiftDown, bool capLocked); + }; +}} diff --git a/vnext/include/ReactUWP/Views/ShadowNodeBase.h b/vnext/include/ReactUWP/Views/ShadowNodeBase.h index b455c27b59d..4a5cf97c6e1 100644 --- a/vnext/include/ReactUWP/Views/ShadowNodeBase.h +++ b/vnext/include/ReactUWP/Views/ShadowNodeBase.h @@ -10,6 +10,7 @@ #include #include +#include "KeyboardEventHandler.h" namespace react { namespace uwp { @@ -43,30 +44,6 @@ enum ShadowCorners : uint8_t CountCorners }; -enum AccessibilityRoles : uint8_t -{ - None = 0, - Button, - Link, - Search, - Image, - KeyboardKey, - Text, - Adjustable, - ImageButton, - Header, - Summary, - Unknown, - CountRoles -}; - -enum AccessibilityStates : uint8_t -{ - Selected = 0, - Disabled, - CountStates -}; - extern const DECLSPEC_SELECTANY double c_UndefinedEdge = -1; #define INIT_UNDEFINED_EDGES { c_UndefinedEdge, c_UndefinedEdge, c_UndefinedEdge, c_UndefinedEdge, c_UndefinedEdge, c_UndefinedEdge, c_UndefinedEdge, c_UndefinedEdge, c_UndefinedEdge } #define INIT_UNDEFINED_CORNERS { c_UndefinedEdge, c_UndefinedEdge, c_UndefinedEdge, c_UndefinedEdge, c_UndefinedEdge, c_UndefinedEdge, c_UndefinedEdge, c_UndefinedEdge, c_UndefinedEdge } @@ -122,6 +99,14 @@ struct REACTWINDOWS_EXPORT ShadowNodeBase : public facebook::react::ShadowNode bool m_onMouseEnter = false; bool m_onMouseLeave = false; bool m_onMouseMove = false; + + // Support Keyboard +public: + void UpdateHandledKeyboardEvents(std::string const& propertyName, folly::dynamic const& value); + +private: + void EnsureHandledKeyboardEventHandler(); + std::unique_ptr m_handledKeyboardEventHandler; }; #pragma warning(pop) diff --git a/vnext/include/ReactUWP/Views/ViewManagerBase.h b/vnext/include/ReactUWP/Views/ViewManagerBase.h index 262e14f235b..dea230823d4 100644 --- a/vnext/include/ReactUWP/Views/ViewManagerBase.h +++ b/vnext/include/ReactUWP/Views/ViewManagerBase.h @@ -4,12 +4,9 @@ #pragma once #include - #include - #include #include - #include namespace facebook { namespace react { diff --git a/vnext/include/ReactUWP/XamlView.h b/vnext/include/ReactUWP/XamlView.h index 9b43da0b41b..e292ffabd2e 100644 --- a/vnext/include/ReactUWP/XamlView.h +++ b/vnext/include/ReactUWP/XamlView.h @@ -8,6 +8,7 @@ namespace winrt { using namespace Windows::UI::Xaml; + using namespace Windows::UI::Xaml::Input; using namespace Windows::Foundation; } @@ -30,4 +31,22 @@ inline void SetTag(XamlView view, winrt::IInspectable tag) SetTag(view, tag.as().GetInt64()); } +inline bool IsValidTag(winrt::IPropertyValue value) +{ + assert(value); + return (value.Type() == winrt::PropertyType::Int64); +} + +inline int64_t GetTag(winrt::IPropertyValue value) +{ + assert(value); + return value.GetInt64(); +} + +inline winrt::IPropertyValue GetTagAsPropertyValue(winrt::FrameworkElement fe) +{ + assert(fe); + return fe.GetValue(winrt::FrameworkElement::TagProperty()).try_as(); +} + } } diff --git a/vnext/local-cli/generator-windows/index.js b/vnext/local-cli/generator-windows/index.js index 0085dfa31ad..b0bdc9bf056 100644 --- a/vnext/local-cli/generator-windows/index.js +++ b/vnext/local-cli/generator-windows/index.js @@ -113,7 +113,7 @@ function installDependencies(options) { const depDelim = ' || '; const delimIndex = reactNativeVersion.indexOf(depDelim); if (delimIndex !== -1) { - reactNativeVersion = reactNativeVersion.substring(delimIndex + depDelim.length); + reactNativeVersion = reactNativeVersion.slice(0, delimIndex); } console.log(chalk.green('Updating to compatible version of react-native:')); diff --git a/vnext/makewinrt.inc b/vnext/makewinrt.inc index de68c87d337..e8d63576bf2 100644 --- a/vnext/makewinrt.inc +++ b/vnext/makewinrt.inc @@ -8,8 +8,6 @@ LIBLET_WINRT = 1 LIBLET_NO_PRECOMP = 1 -NOJSC = 1; - !include $(WAREHOUSEIMPORTDIR)\libletmake\x-none\nmake\make.inc INCLUDES = $(INCLUDES); \ @@ -49,7 +47,6 @@ C_DEFINES = $(C_DEFINES) -D RN_EXPORT= C_DEFINES = $(C_DEFINES) -D JSI_EXPORT= C_DEFINES = $(C_DEFINES) -D WIN32=0 C_DEFINES = $(C_DEFINES) -D WINRT=1 -C_DEFINES = $(C_DEFINES) -D NOJSC C_DEFINES = $(C_DEFINES) -D _HAS_AUTO_PTR_ETC diff --git a/vnext/package.json b/vnext/package.json index bc3033bd373..85901909aed 100644 --- a/vnext/package.json +++ b/vnext/package.json @@ -1,6 +1,6 @@ { "name": "react-native-windows", - "version": "0.59.0-vnext.11", + "version": "0.59.0-vnext.51", "license": "MIT", "repository": { "type": "git", @@ -13,9 +13,9 @@ "preinstall": "node Scripts/preInstall.js", "postinstall": "node Scripts/postInstall.js", "build": "just-scripts build", - "clean": "node Scripts/just.js clean", + "clean": "just-scripts clean", "start": "node Scripts/cli.js start", - "watch": "node node_modules/@office-iss/sdx-build-tools/watch.js" + "watch": "tsc -w" }, "disabledTasks": [ "api-doc", @@ -47,11 +47,11 @@ "create-react-class": "^15.6.3", "fbjs": "^1.0.0", "prop-types": "^15.5.8", - "react-timer-mixin": "^0.13.2", "react-native-local-cli": "^1.0.0-alpha.5", + "react-timer-mixin": "^0.13.2", "regenerator-runtime": "^0.13.2", - "username": "^3.0.0", "shelljs": "^0.7.8", + "username": "^3.0.0", "uuid": "^2.0.1", "xml-parser": "^1.2.1" }, @@ -66,10 +66,10 @@ "tslint-microsoft-contrib": "^5.0.1", "tslint-react": "^4", "typescript": "3.5.1", - "react-native": "0.59.0-microsoft.4" + "react-native": "0.59.0-microsoft.8" }, "peerDependencies": { "react": "16.8.3", - "react-native": "^0.59.0 || 0.59.0-microsoft.4 || https://github.com/microsoft/react-native/archive/v0.59.0-microsoft.4.tar.gz" + "react-native": "^0.59.0 || 0.59.0-microsoft.8 || https://github.com/microsoft/react-native/archive/v0.59.0-microsoft.8.tar.gz" } -} \ No newline at end of file +} diff --git a/vnext/src/Libraries/AppTheme/AppTheme.ts b/vnext/src/Libraries/AppTheme/AppTheme.ts new file mode 100644 index 00000000000..c82142922a2 --- /dev/null +++ b/vnext/src/Libraries/AppTheme/AppTheme.ts @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +'use strict'; + +import { NativeEventEmitter } from 'react-native'; +import { IHighContrastColors } from './AppThemeTypes'; + +class AppThemeModule extends NativeEventEmitter { + get currentTheme(): string { + return ''; + } + + get isHighContrast(): boolean { + return false; + } + + get currentHighContrastColorValues(): IHighContrastColors { + return { } as IHighContrastColors; + } +} + +export const AppTheme = new AppThemeModule(); +export default AppTheme; \ No newline at end of file diff --git a/vnext/src/Libraries/AppTheme/AppTheme.uwp.ts b/vnext/src/Libraries/AppTheme/AppTheme.uwp.ts new file mode 100644 index 00000000000..a66a1d48835 --- /dev/null +++ b/vnext/src/Libraries/AppTheme/AppTheme.uwp.ts @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +'use strict'; + +import { NativeEventEmitter, NativeModules } from 'react-native'; +const MissingNativeEventEmitterShim = require('MissingNativeEventEmitterShim'); +import { IHighContrastColors, IHighContrastChangedEvent } from './AppThemeTypes'; + +const NativeAppTheme = NativeModules.RTCAppTheme; + +class AppThemeModule extends NativeEventEmitter { + public isAvailable: boolean; + private _isHighContrast: boolean; + private _currentTheme: string; + private _highContrastColors: IHighContrastColors; + + constructor() { + super(NativeAppTheme); + this.isAvailable = true; + + this._highContrastColors = NativeAppTheme.initialHighContrastColors; + this._isHighContrast = NativeAppTheme.initialHighContrast; + this.addListener('highContrastChanged', (nativeEvent: IHighContrastChangedEvent) => { + this._isHighContrast = nativeEvent.isHighContrast; + this._highContrastColors = nativeEvent.highContrastColors; + }); + + this._currentTheme = NativeAppTheme.initialAppTheme; + this.addListener('appThemeChanged', ({currentTheme}:{currentTheme: string}) => { + this._currentTheme = currentTheme; + }); + } + + get currentTheme(): string { + return this._currentTheme; + } + + get isHighContrast(): boolean { + return this._isHighContrast; + } + + get currentHighContrastColors(): IHighContrastColors { + return this._highContrastColors; + } +} + +// This module depends on the native `RCTAppTheme` module. If you don't include it, +// `AppTheme.isAvailable` will return `false`, and any method calls will throw. +class MissingNativeAppThemeShim extends MissingNativeEventEmitterShim { + public isAvailable = false; + public currentTheme = ''; + public isHighContrast = false; + public currentHighContrastColors = {} as IHighContrastColors; +} + +export const AppTheme = (NativeAppTheme ? new AppThemeModule() : new MissingNativeAppThemeShim()); +export default AppTheme; \ No newline at end of file diff --git a/vnext/src/Libraries/AppTheme/AppThemeTypes.ts b/vnext/src/Libraries/AppTheme/AppThemeTypes.ts new file mode 100644 index 00000000000..fd96afdb9e6 --- /dev/null +++ b/vnext/src/Libraries/AppTheme/AppThemeTypes.ts @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +export interface IHighContrastColors { + ButtonFaceColor: string; + ButtonTextColor: string; + GrayTextColor: string; + HighlightColor: string; + HighlightTextColor: string; + HotlightColor: string; + WindowColor: string; + WindowTextColor: string; +} + +export interface IAppThemeChangedEvent { + currentTheme: string; +} + +export interface IHighContrastChangedEvent { + isHighContrast: boolean; + highContrastColors: IHighContrastColors; +} \ No newline at end of file diff --git a/vnext/src/Libraries/Components/Keyboard/KeyboardExt.tsx b/vnext/src/Libraries/Components/Keyboard/KeyboardExt.tsx new file mode 100644 index 00000000000..2dfd6fa80e0 --- /dev/null +++ b/vnext/src/Libraries/Components/Keyboard/KeyboardExt.tsx @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +'use strict'; + +import * as React from 'react'; +import { IKeyboardProps } from './KeyboardExtProps'; + +export const supportKeyboard =

(Component: React.ComponentType

) => +class SupportKeyboard extends React.Component

{ + public render(): JSX.Element | null { + return null; + } +}; diff --git a/vnext/src/Libraries/Components/Keyboard/KeyboardExt.uwp.tsx b/vnext/src/Libraries/Components/Keyboard/KeyboardExt.uwp.tsx new file mode 100644 index 00000000000..349f65b8259 --- /dev/null +++ b/vnext/src/Libraries/Components/Keyboard/KeyboardExt.uwp.tsx @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +'use strict'; + +import * as React from 'react'; +import { IKeyboardProps } from './KeyboardExtProps'; + +export const supportKeyboard =

(WrappedComponent: React.ComponentType

) => { + interface IForwardRefProps { + // tslint:disable-next-line:no-any + forwardedRef?: React.Ref; + } + + // children is used to avoid error: Property 'children' does not exist on type 'IntrinsicAttributes & ViewProps & + // IKeyboardProps & RefAttributes + // tslint:disable-next-line:no-any + type PropsWithoutForwardedRef = P & IKeyboardProps & {children?: any}; + type PropsWithForwardedRef = PropsWithoutForwardedRef & IForwardRefProps; + + class SupportKeyboard extends React.Component { + public render(): JSX.Element { + const { forwardedRef, ...rest } = this.props; + return ; + } + } + + // tslint:disable-next-line:no-any + return React.forwardRef((props: PropsWithoutForwardedRef, ref: React.Ref) => { + return ; + }); +}; \ No newline at end of file diff --git a/vnext/src/Libraries/Components/Keyboard/KeyboardExtProps.ts b/vnext/src/Libraries/Components/Keyboard/KeyboardExtProps.ts new file mode 100644 index 00000000000..0f6ccb656ed --- /dev/null +++ b/vnext/src/Libraries/Components/Keyboard/KeyboardExtProps.ts @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +'use strict'; + +import * as RN from 'react-native'; + +export enum EventPhase { + None = 0, + Capturing, + AtTarget, + Bubbling +} + +export enum HandledEventPhase { + Capturing = EventPhase.Capturing, + Bubbling = EventPhase.Bubbling +} + +export interface INativeKeyboardEvent { + altKey: boolean; + ctrlKey: boolean; + metaKey: boolean; + shiftKey: boolean; + key: string; + eventPhase: EventPhase; +} + +export interface IHandledKeyboardEvent { + altKey?: boolean; + ctrlKey?: boolean; + metaKey?: boolean; + shiftKey?: boolean; + key: string; + handledEventPhase?: HandledEventPhase; +} + +export type IKeyboardEvent = RN.NativeSyntheticEvent; + +export interface IKeyboardProps { + onKeyDown?: (args: IKeyboardEvent) => void; + onKeyDownCapture?: (args: IKeyboardEvent) => void; + onKeyUp?: (args: IKeyboardEvent) => void; + onKeyUpCapture?: (args: IKeyboardEvent) => void; + + keyDownEvents?: IHandledKeyboardEvent[]; + keyUpEvents?: IHandledKeyboardEvent[]; +} diff --git a/vnext/src/Libraries/Components/View/ViewWindows.tsx b/vnext/src/Libraries/Components/View/ViewWindows.tsx new file mode 100644 index 00000000000..f05bf183b56 --- /dev/null +++ b/vnext/src/Libraries/Components/View/ViewWindows.tsx @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { IViewWindowsProps } from './ViewWindowsProps'; +import React = require('react'); + +export class ViewWindows extends React.Component { + + public render(): JSX.Element | null { + return null; + } +} + +export default ViewWindows; diff --git a/vnext/src/Libraries/Components/View/ViewWindows.uwp.tsx b/vnext/src/Libraries/Components/View/ViewWindows.uwp.tsx new file mode 100644 index 00000000000..003d95dd803 --- /dev/null +++ b/vnext/src/Libraries/Components/View/ViewWindows.uwp.tsx @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { IViewWindowsProps } from './ViewWindowsProps'; +import * as React from 'react'; +import { View } from 'react-native'; + +// tslint:disable-next-line:no-any +export const ViewWindows = React.forwardRef((props: IViewWindowsProps, ref: React.Ref) => ( + +)); + +export default ViewWindows; diff --git a/vnext/src/Libraries/Components/View/ViewWindowsProps.ts b/vnext/src/Libraries/Components/View/ViewWindowsProps.ts new file mode 100644 index 00000000000..402bee6f8d4 --- /dev/null +++ b/vnext/src/Libraries/Components/View/ViewWindowsProps.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { IKeyboardProps } from '../Keyboard/KeyboardExtProps'; +import { ViewProps } from 'react-native'; + +export interface IViewWindowsProps extends IKeyboardProps, ViewProps { + acceptsKeyboardFocus?: boolean; + // tslint:disable-next-line:no-any + children?: any; +} \ No newline at end of file diff --git a/vnext/src/RNTester/AccessibilityExample.tsx b/vnext/src/RNTester/AccessibilityExample.tsx index a176f20c568..847c34ea4ff 100644 --- a/vnext/src/RNTester/AccessibilityExample.tsx +++ b/vnext/src/RNTester/AccessibilityExample.tsx @@ -4,7 +4,9 @@ /* tslint:disable */ import React = require('react'); -import { Text, TouchableHighlight, View } from 'react-native'; +import { FlatList, Text, TouchableHighlight, View, StyleSheet } from 'react-native'; +import { AppTheme } from '../../src/index.uwp'; +import { IAppThemeChangedEvent } from 'src/Libraries/AppTheme/AppThemeTypes'; class AccessibilityBaseExample extends React.Component { public render() { @@ -27,6 +29,81 @@ class AccessibilityBaseExample extends React.Component { } } +class HighContrastExample extends React.Component { + state = { + isHighContrast: AppTheme.isHighContrast, + highContrastColorValues: AppTheme.currentHighContrastColors, + currentTheme: AppTheme.currentTheme + }; + + componentDidMount() { + AppTheme.addListener('highContrastChanged', this.onHighContrastChanged); + AppTheme.addListener('appThemeChanged', this.onAppThemeChanged); + } + + componenetWillUnmount() { + AppTheme.removeListener('highContrastChanged', this.onHighContrastChanged); + AppTheme.removeListener('appThemeChanged', this.onAppThemeChanged); + } + + // TODO: Make args props + onHighContrastChanged = (event: IAppThemeChangedEvent) => { + this.setState({isHighContrast : AppTheme.isHighContrast, + highContrastColorValues : AppTheme.currentHighContrastColors}); + }; + + onAppThemeChanged = (event: any) => { + this.setState({currentTheme : AppTheme.currentTheme}); + } + + public render() { + return ( + + The following has HighContrast Event awareness: + + isHighContrast: {this.state.isHighContrast ? 'True' : 'False'} + + + ButtonFace High Contrast Hex Value: {this.state.highContrastColorValues.ButtonFaceColor} + + + ButtonText High Contrast Color Hex Value: {this.state.highContrastColorValues.ButtonTextColor} + + + GrayText High Contrast Color Hex Value: {this.state.highContrastColorValues.GrayTextColor} + + + Highlight High Contrast Color Hex Value: {this.state.highContrastColorValues.HighlightColor} + + + HighlightText High Contrast Color Hex Value: {this.state.highContrastColorValues.HighlightTextColor} + + + Hotlight High Contrast Color Hex Value: {this.state.highContrastColorValues.HotlightColor} + + + Window High Contrast Color Hex Value: {this.state.highContrastColorValues.WindowColor} + + + WindowText High Contrast Color Hex Value: {this.state.highContrastColorValues.WindowTextColor} + + + ); + } + + styles = StyleSheet.create ({ + enabled: { + width: 250, + height: 50 + }, + disabled: { + width: 250, + height: 50, + backgroundColor: '#808080' + } + }); +} + class TouchableExamples extends React.Component<{}, any> { public state = { pressedCount: 0, @@ -56,6 +133,61 @@ class TouchableExamples extends React.Component<{}, any> { } } +class AccessibilityStateExamples extends React.Component { + public state = { + viewDisabled: false, + itemsSelected: [false, false, false], + } + + public render() { + var selectableItems = [{}, {}, {}] + return ( + + The following TouchableHighlight toggles accessibilityState.disabled for the View under it: + + Toggle + + + This View should be {this.state.viewDisabled ? "disabled" : "enabled"} according to UIA + + The following list of TouchableHighlights toggles accessibilityState.selected when touched: + + + this.selectPress(item.index)} + > + {this.state.itemsSelected[item.index] ? "Selected" : "Unselected"} + + } + keyExtractor={(item, index) => index.toString()} + /> + + + ); + } + + private disablePress = () => { + this.setState({viewDisabled: !this.state.viewDisabled}); +} + + private selectPress = (index: number) => { + let tmp = this.state.itemsSelected; + tmp[index] = !tmp[index]; + this.setState({itemsSelected: tmp}); + } +} export const displayName = (_undefined?: string) => {}; export const title = 'Accessibility'; @@ -72,5 +204,17 @@ export const examples = [ render: function(): JSX.Element { return ; }, + }, + { + title: 'HighContrast', + render: function(): JSX.Element { + return ; + }, + }, + { + title: 'States', + render: function(): JSX.Element { + return ; + }, } -]; +]; \ No newline at end of file diff --git a/vnext/src/RNTester/KeyboardExtensionExample.uwp.tsx b/vnext/src/RNTester/KeyboardExtensionExample.uwp.tsx new file mode 100644 index 00000000000..0db201fdc9d --- /dev/null +++ b/vnext/src/RNTester/KeyboardExtensionExample.uwp.tsx @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/* tslint:disable */ + +import * as React from 'react'; +import { View, StyleSheet, Text, TextInput } from 'react-native'; +import { supportKeyboard, IHandledKeyboardEvent, IKeyboardEvent, HandledEventPhase } from '../../src/index.uwp'; + +const ViewWindows = supportKeyboard(View) + +const styles = StyleSheet.create({ + border: { + borderStyle: 'dotted', + borderColor: 'black' + }, + keyComponentRoot: { + borderWidth: 2, + flexDirection: 'row', + marginVertical: 5, + backgroundColor: 'whitesmoke', + justifyContent: 'space-around' + }, + keyEnterVisualizer: { + margin: 5, + alignItems: 'center', + minWidth: 100, + minHeight: 30 + }, + textInput: { + height: 32, + width: 100 + }, + blackbox: { height: 30, width: 30, borderColor: 'black', borderWidth: 3 } +}); + +interface IKeyboardableComponentState { + lastKeyDown: string | null; + lastKeyUp: string | null; + lastKeyDownCapture: string | null; + lastKeyUpCapture: string | null; +} + +const handledNativeKeyboardEvents: IHandledKeyboardEvent[] = [ + { key: 'a', handledEventPhase: HandledEventPhase.Capturing }, + { key: 'b' }, + { key: 'c', handledEventPhase: HandledEventPhase.Bubbling }, + { key: 'Tab', handledEventPhase: HandledEventPhase.Capturing } +]; + +class ViewWindowsKeyboardExample extends React.Component<{}, IKeyboardableComponentState> { + public constructor(props: {}) { + super(props); + this.state = { + lastKeyDown: null, + lastKeyUp: null, + lastKeyDownCapture: null, + lastKeyUpCapture: null, + }; + } + + public render(): JSX.Element { + return ( + + + + OnKeyDown + {this.state.lastKeyDown !== null ? this.state.lastKeyDown : ' '} + OnKeyDownCapture + {this.state.lastKeyDownCapture !== null ? this.state.lastKeyDownCapture : ' '} + + + OnKeyUp + {this.state.lastKeyUp !== null ? this.state.lastKeyUp : ' '} + OnKeyUpCapture + {this.state.lastKeyUpCapture !== null ? this.state.lastKeyUpCapture : ' '} + + + + + + + ); + } + + private _onKeyUp = (ev: IKeyboardEvent) => { + this.setState({ lastKeyUp: ev.nativeEvent.key, lastKeyDown: null }); + }; + + private _onKeyDown = (ev: IKeyboardEvent) => { + this.setState({ lastKeyDown: ev.nativeEvent.key, lastKeyUp: null }); + }; + private _onKeyUpCapture = (ev: IKeyboardEvent) => { + this.setState({ lastKeyUpCapture: ev.nativeEvent.key, lastKeyDownCapture: null }); + }; + + private _onKeyDownCapture = (ev: IKeyboardEvent) => { + this.setState({ lastKeyDownCapture: ev.nativeEvent.key, lastKeyUpCapture: null }); + }; +} +export const displayName = (_undefined?: string) => { }; +export const title = 'Keyboard extension Example'; +export const description = 'Demo of keyboard properties.'; +export const examples = [ + { + title: 'Keyboard extension example', + render(): JSX.Element { + return ; + }, + } +]; \ No newline at end of file diff --git a/vnext/src/RNTester/KeyboardFocusExample.uwp.tsx b/vnext/src/RNTester/KeyboardFocusExample.uwp.tsx new file mode 100644 index 00000000000..610104f225c --- /dev/null +++ b/vnext/src/RNTester/KeyboardFocusExample.uwp.tsx @@ -0,0 +1,140 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/* tslint:disable */ + +import * as React from 'react'; +import { View, StyleSheet, Text, TextInput } from 'react-native'; +import { supportKeyboard, IKeyboardEvent, CheckBox, ViewWindows, Picker } from '../../src/index.uwp'; + +// TextInput2 is used to verify supportKeyboard + focus +const TextInput2 = supportKeyboard(TextInput) + +const styles = StyleSheet.create({ + border: { + borderStyle: 'dotted', + borderColor: 'black' + }, + keyComponentRoot: { + borderWidth: 2, + flexDirection: 'column', + marginVertical: 5, + backgroundColor: 'whitesmoke', + justifyContent: 'space-around' + }, + keyEnterVisualizer: { + margin: 5, + alignItems: 'center', + minWidth: 100, + minHeight: 30 + }, + textInput: { + height: 32, + width: 100 + }, + blackbox: { height: 30, width: 30, borderColor: 'black', borderWidth: 3 } +}); + +interface IKeyboardFocusComponentState { + selected: string; + keyOnKeyDown: string; +} + +// tslint:disable-next-line +const pickerRef = React.createRef(); +const viewWindowsRef = React.createRef(); +const textInputRef = React.createRef(); +const textInputRef2 = React.createRef(); + +// tslint:disable-next-line +const checkBoxRef = React.createRef(); + +class KeyboardFocusExample extends React.Component<{}, IKeyboardFocusComponentState> { + public constructor(props: {}) { + super(props); + this.state = { + selected: '', + keyOnKeyDown: 'unknown' + }; + } + + public render(): JSX.Element { + const pickerItems = ['View', 'Picker', 'TextInput', 'TextInput2', "CheckBox"]; + + return ( + + + Please select a item to set focus + + + {pickerItems.map(item => ())} + + + + View accept focus + + + + + + + + + Test Purpose: focus on TextInput, then timeout and blur on TextInput2, TextInput still keep focus + + + + Test Purpose: focus on TextInput2, then timeout and blur on TextInput2, TextInput2 lose focus + + Key {this.state.keyOnKeyDown} + + + + Checkbox accept focus + + + ); + } + + private _textInputKeyDown = (ev: IKeyboardEvent) => { + this.setState({ keyOnKeyDown: ev.nativeEvent.key }); + }; + + private _selectionChanged = (selected: string) => { + switch (selected) { + case 'View': + viewWindowsRef.current && viewWindowsRef.current.focus(); + break; + case 'Picker': + pickerRef.current && pickerRef.current.focus(); + break; + case 'TextInput': + textInputRef.current && textInputRef.current.focus(); + if (textInputRef.current) { + textInputRef.current.focus(); + setTimeout(() => { textInputRef2.current && textInputRef2.current.blur(); }, 10000); + } + break; + case 'TextInput2': + if (textInputRef2.current) { + textInputRef2.current.focus(); + setTimeout(() => { textInputRef2.current && textInputRef2.current.blur(); }, 10000); + } + break; + case 'CheckBox': + checkBoxRef.current && checkBoxRef.current.focus(); + break; + } + } +} +export const displayName = (_undefined?: string) => { }; +export const title = 'Keyboard Focus Example'; +export const description = 'Demo of keyboard focus.'; +export const examples = [ + { + title: 'Keyboard Focus example', + render(): JSX.Element { + return ; + }, + } +]; \ No newline at end of file diff --git a/vnext/src/RNTester/RNTesterList.uwp.ts b/vnext/src/RNTester/RNTesterList.uwp.ts index 8ca53e27a22..fb436f6e3bc 100644 --- a/vnext/src/RNTester/RNTesterList.uwp.ts +++ b/vnext/src/RNTester/RNTesterList.uwp.ts @@ -68,6 +68,10 @@ const ComponentExamples: Array = [ key: 'PopupExample', module: require('./PopupExample.uwp'), }, + { + key: 'KeyboardExtensionExample', + module: require('./KeyboardExtensionExample.uwp'), + }, { key: 'ScrollViewSimpleExample', module: require('react-native/RNTester/js/ScrollViewSimpleExample') @@ -110,6 +114,10 @@ const ComponentExamples: Array = [ ]; const APIExamples: Array = [ + { + key: 'KeyboardFocusExample', + module: require('./KeyboardFocusExample.uwp'), + }, { key: 'AccessibilityExample', module: require('./AccessibilityExample') @@ -118,6 +126,10 @@ const APIExamples: Array = [ key: 'AppStateExample', module: require('react-native/RNTester/js/AppStateExample') }, + { + key: 'ThemingExample', + module: require('./ThemingExample'), + }, { key: 'BorderExample', module: require('react-native/RNTester/js/BorderExample'), @@ -140,7 +152,7 @@ const APIExamples: Array = [ }, { key: 'KeyboardExample', - module: require('./KeyboardExample') + module: require('./KeyboardExample'), }, { key: 'LayoutExample', diff --git a/vnext/src/RNTester/ThemingExample.uwp.tsx b/vnext/src/RNTester/ThemingExample.uwp.tsx new file mode 100644 index 00000000000..5dd261cf3e2 --- /dev/null +++ b/vnext/src/RNTester/ThemingExample.uwp.tsx @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/* tslint:disable */ + +import React = require('react'); +import { Text, View, Button } from 'react-native'; +import { AppTheme } from '../../src/index.uwp'; + +class ThemeExample extends React.Component { + state = { + currentTheme: AppTheme.currentTheme + }; + + componentDidMount() { + AppTheme.addListener('appThemeChanged', this.onAppThemeChanged); + } + + componentWillUnmount() { + AppTheme.removeListener('appThemeChanged', this.onAppThemeChanged); + } + + onAppThemeChanged = (event: any) => { + const currentTheme = AppTheme.currentTheme; + this.setState({currentTheme}); + }; + + _onPress = () => { + } + + public render() { + return ( + + currentTheme: {this.state.currentTheme} + + + ); + } +} + +export const displayName = (_undefined?: string) => {}; +export const title = 'AppTheme'; +export const description = 'Usage of theme properties.'; +export const examples = [ + { + title: 'Theme Aware Control', + render: function(): JSX.Element { + return ; + }, + } +]; \ No newline at end of file diff --git a/vnext/src/index.ts b/vnext/src/index.ts index ee680b203b4..973aafc28f9 100644 --- a/vnext/src/index.ts +++ b/vnext/src/index.ts @@ -7,3 +7,9 @@ export * from './Libraries/Components/Flyout/Flyout'; export * from './Libraries/Components/Glyph/Glyph'; export * from './Libraries/Components/Picker/PickerUWP'; export * from './Libraries/Components/Popup/Popup'; +export * from './Libraries/Components/Keyboard/KeyboardExt'; +export * from './Libraries/Components/Keyboard/KeyboardExtProps'; +export * from './Libraries/Components/View/ViewWindowsProps'; +export * from './Libraries/Components/View/ViewWindows'; +export * from './Libraries/AppTheme/AppTheme'; +export * from './Libraries/AppTheme/AppThemeTypes'; diff --git a/vnext/src/index.uwp.ts b/vnext/src/index.uwp.ts index d007937f555..3c549d1d1e3 100644 --- a/vnext/src/index.uwp.ts +++ b/vnext/src/index.uwp.ts @@ -7,3 +7,9 @@ export * from './Libraries/Components/Flyout/Flyout.uwp'; export * from './Libraries/Components/Glyph/Glyph.uwp'; export * from './Libraries/Components/Picker/PickerUWP.uwp'; export * from './Libraries/Components/Popup/Popup.uwp'; +export * from './Libraries/Components/Keyboard/KeyboardExt.uwp'; +export * from './Libraries/Components/Keyboard/KeyboardExtProps'; +export * from './Libraries/Components/View/ViewWindowsProps'; +export * from './Libraries/Components/View/ViewWindows.uwp'; +export * from './Libraries/AppTheme/AppTheme.uwp'; +export * from './Libraries/AppTheme/AppThemeTypes'; \ No newline at end of file diff --git a/vnext/yarn.lock b/vnext/yarn.lock index 9be181d7e1c..a50152be6d6 100644 --- a/vnext/yarn.lock +++ b/vnext/yarn.lock @@ -4895,9 +4895,9 @@ react-native-local-cli@^1.0.0-alpha.5: xcode "^1.0.0" xmldoc "^0.4.0" -"react-native@https://github.com/Microsoft/react-native/archive/v0.59.0-microsoft.4.tar.gz": - version "0.59.0-microsoft.4" - resolved "https://github.com/Microsoft/react-native/archive/v0.59.0-microsoft.4.tar.gz#1776b512acd24257a3c1a64aaf7983ca30e37237" +"react-native@https://github.com/Microsoft/react-native/archive/v0.59.0-microsoft.8.tar.gz": + version "0.59.0-microsoft.8" + resolved "https://github.com/Microsoft/react-native/archive/v0.59.0-microsoft.8.tar.gz#fa26f69c22c3971619936f16d11cd09dae9b09f2" dependencies: "@babel/core" "^7.4.0" "@babel/generator" "^7.4.0"