Skip to content

Rework modal to be implemented entirely using public APIs #14256

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Jan 10, 2025

Conversation

acoates-ms
Copy link
Collaborator

@acoates-ms acoates-ms commented Jan 8, 2025

Description

The current implementation of Modal uses internal APIs which means it did not verify that it was possible to write such components using only public APIs. This PR reworks modal to use the public APIs.

  • Start generating codegen'd files for native components in RNW
  • Add methods to IReactCompositionViewComponentBuilder to allow custom RootComponentView's
  • Instead of implementing Modal by inheriting from the internal RootComponentView class, use the new builder, and the codegen'd types for modal.
  • Fixed some issues around focus, where focus would attempt to cross root views
  • Switched from using legacy win32 APIs to create the modal window to using the newer WinAppSDK AppWindow APIs.
Microsoft Reviewers: Open in CodeFlow

@acoates-ms acoates-ms requested review from a team as code owners January 8, 2025 18:32

// In the case of a sub rootview, we may have a non-zero origin. hitTest takes a pt in the parent coords, so we need
// to apply the current origin
ptScaled += RootComponentView().layoutMetrics().frame.origin;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment says the hitTest pt is taken in parent coordinates and we're incorporating the origin in the subrootview (separate window) for it hit test... for the other lines I was thinking "should this origin be incorporated inside hitTest instead of called before it, if it's the RootComponentView()'s layoutMetrics?" ... then saw the if(capturedPointers) { ... } that's more curious. When do we have m_capturedPointers vs not?

Is the underlying type of facebook::react::Point a float? Considering the implications of different DPI on different displays which can do curious things in some contexts

2);
int32_t yCor = static_cast<int32_t>((parentRC.top + parentRC.bottom - layoutMetrics.Frame.Height * layoutMetrics.PointScaleFactor) /
2);
int32_t xCor = static_cast<int32_t>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The overall change looks like formatting only, though I'm curious about the resizing logic relative to positioning logic.

Is the Modal position a controlled property, or pos+size not user-modifiable? I'm a little intrigued at the coordinate system / units for layoutMetrics.Frame being parent window client coordinates / Integer DIPs and our capacity for roundoff -- what scale factor is PointScaleFactor here?

On ~242 we create the AppWindow with the parentHwnd and then appear to clarify the new m_window is a top-level window. It looks reasonable for say a "modal is always centered over its parent" experience but do we have the winrt equivalent of InheritWindowMonitor to avoid separate DPI changes?

I'm a hair concerned about DPI wobbles if crossing a DPI boundary re-invokes layout before/after WM_DPICHANGED and its suggested rect for avoiding DPI wobbles gets processed

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The modal as it is right now is sized by its content only, never user modified or user modifiable. So I'm assuming that it will always have the same DPI as its parent? If InheritWindowMonitor is the API to ensure that, we can call it on this window until we get a more complete layout story.

Reworking the shadownode layout to allow more independent layout in the modal, from its parent is currently outside the scope of this change. But something we should think about.

I think of modal as something for quick MessageBox like dialogs. If you wanted something more long lived you are probably better off having a separate API in the JS that launches a window more like how logbox does it. Like a launchDialog('MyComponent', {initialProps}) API, rather than a component that you just render inline.

Copy link
Contributor

@PPatBoyd PPatBoyd Jan 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InheritWindowMonitor is the API to use here yeah, making the modal's top-level window DPI information be relative to a different top-level window (its owner window; technically not a parent window)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 I think about Modal the same way.

Even better IMO if it's backed by an in-tree UI component and doesn't require a separate top-level window, but it would make sense if there are competing priorities regarding the level of modality supported or allowing the modal to be bigger than its parent surface. An in-tree UI component would probably struggle to offer Code Modality in a brownfield app.

Copy link
Contributor

@TatianaKapos TatianaKapos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Just noticed two things that can be resolved in a later PR:

  1. Modal has extra white space with the width/height in rntester (this may just need a JavaScript change in rntester)
  2. With the UseExperimentalWinUI3 flag, you can only open/close the Modal once. After that any Modal won't open again.

@acoates-ms acoates-ms merged commit fb5c92b into microsoft:main Jan 10, 2025
59 checks passed
@acoates-ms acoates-ms deleted the modalpublicapi branch January 10, 2025 22:14
acoates-ms added a commit to acoates-ms/react-native-windows that referenced this pull request Jan 10, 2025
…14256)

* Rework modal implementation to use public APIs

* shutdown fix

* Change files

* format

* remove dead code

* format

* fixes

* fix

* UIA tree for root component should be kept distinct from main UIA tree

* input offset fix for sub rootviews

* Split modal into two componentview's so that we dont have multiple roots in our componentview tree

* format

* Ensure rootview removes itself from the island, before a new one adds itself on instance reload

* defork some modal test pages

* remove override
acoates-ms added a commit that referenced this pull request Jan 13, 2025
)

* Implement ISelectionProvider and ISelectionItemProvider (#14019)

Adds support for ISelectionProvider interface
Adds support for ISelectionItemProvider interface
Adds support for accessibilityState:selected
Adjusts AccessibilityState native type on Windows to be std::optional instead of bool
Adjusts AccessibilityState native type on Windows to include multiselectable and required fields of type std::optional
Adds multiselectable and required fields to AccessibilityState type in JS with type boolean | undefined
Adds support for aria-multiselectable and aria-required.
Adds support for the following accessibilityActions: addToSelection, removeFromSelection, select
Fixes crash in AccessibilityInsights.

* [Fabric] Implement IRangeValueProvider and Adjust IValueProvider Implementation (#14212)

* IRangeValue Provider

* Adjust ReadOnly to Use Prop Value

* Complete IRangeValueProvider Implementation

* Change files

* Update Snapshots

* Rework modal to be implemented entirely using public APIs (#14256)

* Rework modal implementation to use public APIs

* shutdown fix

* Change files

* format

* remove dead code

* format

* fixes

* fix

* UIA tree for root component should be kept distinct from main UIA tree

* input offset fix for sub rootviews

* Split modal into two componentview's so that we dont have multiple roots in our componentview tree

* format

* Ensure rootview removes itself from the island, before a new one adds itself on instance reload

* defork some modal test pages

* remove override

* fix

* fix

* snapshots

---------

Co-authored-by: Chiara Mooney <[email protected]>
acoates-ms added a commit to acoates-ms/react-native-windows that referenced this pull request Mar 11, 2025
…14256)

* Rework modal implementation to use public APIs

* shutdown fix

* Change files

* format

* remove dead code

* format

* fixes

* fix

* UIA tree for root component should be kept distinct from main UIA tree

* input offset fix for sub rootviews

* Split modal into two componentview's so that we dont have multiple roots in our componentview tree

* format

* Ensure rootview removes itself from the island, before a new one adds itself on instance reload

* defork some modal test pages

* remove override
acoates-ms added a commit that referenced this pull request Mar 12, 2025
* Update Guardrails on Provider Instantiation (#13961)

* Update Provider Guardrails

* Change files

* Format

* Update Snapshots

* Use WebSocket factory in PkgInspectorConnection (#14202)

* Use WebSocket resource factory for pkgr inspector

* Change files

* clang format

* Implement ISelectionProvider and ISelectionItemProvider (#14019)

Adds support for ISelectionProvider interface
Adds support for ISelectionItemProvider interface
Adds support for accessibilityState:selected
Adjusts AccessibilityState native type on Windows to be std::optional instead of bool
Adjusts AccessibilityState native type on Windows to include multiselectable and required fields of type std::optional
Adds multiselectable and required fields to AccessibilityState type in JS with type boolean | undefined
Adds support for aria-multiselectable and aria-required.
Adds support for the following accessibilityActions: addToSelection, removeFromSelection, select
Fixes crash in AccessibilityInsights.

* [Fabric] Implement IRangeValueProvider and Adjust IValueProvider Implementation (#14212)

* IRangeValue Provider

* Adjust ReadOnly to Use Prop Value

* Complete IRangeValueProvider Implementation

* Change files

* Update Snapshots

* std::aligned_storage is deprecated (#14253)

* std::aligned_storage is deprecated

* Change files

* format

---------

Co-authored-by: Andrew Coates <[email protected]>

* Update WinUI3ExperimentalVersion from 1.6.240701003-experimental2 to 1.7.250109001-experimental2 (#14270)

* Update WinUI3ExperimentalVersion from 1.6.240701003-experimental2 to 1.7.250109001-experimental2

* Change files

* Update some type and method names that have changed in WinAppSDK 1.7

---------

Co-authored-by: Jon Thysell <[email protected]>

* Rework modal to be implemented entirely using public APIs (#14256)

* Rework modal implementation to use public APIs

* shutdown fix

* Change files

* format

* remove dead code

* format

* fixes

* fix

* UIA tree for root component should be kept distinct from main UIA tree

* input offset fix for sub rootviews

* Split modal into two componentview's so that we dont have multiple roots in our componentview tree

* format

* Ensure rootview removes itself from the island, before a new one adds itself on instance reload

* defork some modal test pages

* remove override

* Enable basic XamlIsland in rntester within playground app when UseExperimentalWinUI3 is true (#14272)

* Enable basic XamlIsland in rntester within playground app when UseExperimentalWinUI3 is true

* Change files

* Fix build break due to unreferenced parameter

* lint

* Move the implementation of CalendarView to sample-custom-component, and use codegen

* Enable CalendarView only when UseExperimentalWinUI3 is true, and add CalendarView.g.h to git

* clang format

* Update snapshots and remove some unused variables

* Update snapshotPages.test.js.snap

* Remove new page from the visitAllPages test

* Remove Paper-only code from Fabric builds of Microsoft.ReactNative (#14289)

Removes most of the Paper-only code from Fabric builds of Microsoft.ReactNative. This is only a first pass - there may be more that needs to be removed (or stuff that needs to be put back in).

- Bug fix (non-breaking change which fixes an issue)
- Breaking change (fix or feature that would cause existing functionality to not work as expected)

Besides nearly doubling the size of the binary files, all of the Paper-only code is functionally useless in Fabric builds, which at worse is dead weight, and at best is confusing to developers.

Resolves #13405

Updated project files to not load/compile paper-only modules. Updated modules that are used by both to correctly only include the Paper or Fabric code they need.

None, but here are some preliminary binary size numbers for x64 release:

| File | Paper | Fabric (Before) | Fabric (After) |
|:-|:-:|:-:|:-:|
| Microsoft.ReactNative.dll | 4.02 MB | 8.32 MB | 6.47 MB (🔻1.85 MB / 22% ) |
| Microsoft.ReactNative.winmd | 64.0 KB | 121.0 KB | 92.0KB (🔻29 KB / 24%) |

Verified all existing tests still pass and fabric apps work.

Should this change be included in the release notes: _yes_

Remove Paper-only code from Fabric builds of Microsoft.ReactNative

* RNIsland UIA fragment root should report parents fragment root (#14302)

* Fix crash running on server 2016

* RNIsland UIA fragment root should report parents fragment root

* Change files

* fix

* use react tag for runtime id

* fix

* fix

* fix

* Fix crash when currently focused element gets marked as enableFocusRing=false (#14306)

* Fix crash when currently focused element gets marked as enableFocusRing=false

* Change files

* [Fabric] Add Functional Tests for Switch Component (#14297)

* Add Functional Tests for Switch

* Fix Tests

* Update Snapshots

* [Fabric] Use PopupWindowSiteBridge for Modal when USE_EXPERIMENTAL_WINUI3 is true (#14284)

* add modal implementation with PopupWindowSiteBridge

* Change files

* add conditional

* feedback

* Initial support for UIA and tab navigation for a child Island (#14305)

* Basic support for stitching the UIA tree for a ContentIslandComponentView's child

* Updated comment

* Change files

* Support shift+tab, and move Automation event handlers to ContentIslandComponentView

* Allow portals to have independent layout constraints and scale factor (#14315)

* Allow portals to have independent layout constraints and scale factor

* format

* change files

* fix

* Round Focus visuals by default, fix nudge rendering (#14312)

* Round Focus visuals by default, fix nudge rendering

* Change files

* Only build OfficeReact.Win32 with UseFabric enabled (#14319)

This PR changes our build system to only build the version of `OfficeReact.Win32` with Fabric enabled.

- Breaking change (fix or feature that would cause existing functionality to not work as expected)

We are building both versions of Desktop in our CI, but the `-Fabric` version is in fact a strict superset of functionality and the only one that Office uses now.

Changed the default so that Desktop always builds with `RnwNewArch` (and therefore `UseFabric`) enabled. Removed the matrix configurations for DesktopFabric from all CI. Fixed the affected nuspec file. Also fixed Desktop publish to include ARM64EC for Fabric and the an issue caused by #14311.

N/A.

Verified the build works.

Should this change be included in the release notes: _no_

* Fix react devtools hitting an assert on launch (#14320)

* ignore unsupported methods

* delete Super::DispatchCommand call

* Change files

* [Fabric] Fix PlatformColor (#14325)

* Fix platform color

* Change files

* Add missing theme colors

* snapshots

* TurboModule spec checking should accept hstring for string arguments (#14322)

* TurboModule spec checking should accept hstring for string arguments

* Change files

* example

* [Fabric] Add Support for ITextProvider, ITextProvider2, and ITextRangeProvider (#14332)

* Partial Implementation

* Add More Implementation

* More Implementation

* More Implementation

* Add Support for Bounding Rectangles

* Complete Initial Implementation

* Change files

* Code Cleanup

* Code Cleanup

* Update Snapshots + Code Cleanup

* Update Snapshots

* Address Feedback

* Address Feedback

* Update Snapshots

* Fix Tests

---------

Co-authored-by: Jon Thysell <[email protected]>

* [Fabric] Fix modal height (#14343)

* fix modal height

* Change files

* reverse change

* add override

* Fix stale focus rects left in UI when last focusable component is removed (#14359)

* Fix stale focus rects left in UI when last focusable component is removed

* Change files

---------

Co-authored-by: Tatiana Kapos <[email protected]>

* Fix issue when calling arrange on an RN Island during load (#14362)

* Fix issue when calling arrange on an RN Island during load

* Change files

---------

Co-authored-by: Tatiana Kapos <[email protected]>

* Fix tooltips in high dpi (#14397)

* Fix tooltips in high dpi

* Change files

* format

* tooltips dont respect textscalefactor

* Fix build issue building component codegen using clang (#14393)

* Fix build issue building component codegen using clang

* Change files

* Components do not lose hover state if pointer leaves window before it leaves the component (#14375)

* Components do not lost hover state if pointer leaves window before it leaves the component

* format

* Change files

---------

Co-authored-by: Tatiana Kapos <[email protected]>

* Property updates switching between PlatformColors would no-op (#14398)

* Property updates switching between PlatformColors would no-op

* Change files

* format

* [Fabric] Add Support for Role Prop (#14352)

* Add Support for Role Prop

* Change files

* Format

* Update Tests

---------

Co-authored-by: Tatiana Kapos <[email protected]>

* Fix bool operator on transparent colors returning false (#14413)

* Fix crash loading logbox

* Fix bool operator on transparent colors returning false

* Change files

* format

* change files

* codegen updates

* update overrides

* snapshots

---------

Co-authored-by: Chiara Mooney <[email protected]>
Co-authored-by: Julio César Rocha <[email protected]>
Co-authored-by: Tiago <[email protected]>
Co-authored-by: JesseCol <[email protected]>
Co-authored-by: Jon Thysell <[email protected]>
Co-authored-by: Tatiana Kapos <[email protected]>
Yajur-Grover pushed a commit to Yajur-Grover/react-native-windows that referenced this pull request Apr 4, 2025
…14256)

* Rework modal implementation to use public APIs

* shutdown fix

* Change files

* format

* remove dead code

* format

* fixes

* fix

* UIA tree for root component should be kept distinct from main UIA tree

* input offset fix for sub rootviews

* Split modal into two componentview's so that we dont have multiple roots in our componentview tree

* format

* Ensure rootview removes itself from the island, before a new one adds itself on instance reload

* defork some modal test pages

* remove override
Yajur-Grover added a commit that referenced this pull request Apr 8, 2025
* Rework modal to be implemented entirely using public APIs (#14256)

* Rework modal implementation to use public APIs

* shutdown fix

* Change files

* format

* remove dead code

* format

* fixes

* fix

* UIA tree for root component should be kept distinct from main UIA tree

* input offset fix for sub rootviews

* Split modal into two componentview's so that we dont have multiple roots in our componentview tree

* format

* Ensure rootview removes itself from the island, before a new one adds itself on instance reload

* defork some modal test pages

* remove override

* Allow portals to have independent layout constraints and scale factor (#14315)

* Allow portals to have independent layout constraints and scale factor

* format

* change files

* fix

* Change files

* fix bad merge

* [Fabric] Fix modal height (#14343)

* fix modal height

* Change files

* reverse change

* add override

* remove old change file

* fix linting

---------

Co-authored-by: Andrew Coates <[email protected]>
Co-authored-by: Tatiana Kapos <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

3 participants