react-native-windows 0.74.24 → 0.74.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Microsoft.ReactNative/Fabric/ComponentView.cpp +8 -0
- package/Microsoft.ReactNative/Fabric/ComponentView.h +5 -1
- package/Microsoft.ReactNative/Fabric/Composition/BorderPrimitive.cpp +5 -0
- package/Microsoft.ReactNative/Fabric/Composition/BorderPrimitive.h +4 -0
- package/Microsoft.ReactNative/Fabric/Composition/CompositionRootAutomationProvider.cpp +8 -32
- package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +190 -84
- package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +15 -10
- package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +2 -1
- package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +23 -0
- package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +3 -0
- package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.cpp +20 -0
- package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.h +3 -0
- package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +10 -0
- package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +3 -0
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +16 -4
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +1 -0
- package/Microsoft.ReactNative/Fabric/Composition/UnimplementedNativeViewComponentView.cpp +1 -1
- package/Microsoft.ReactNative/packages.lock.json +55 -83
- package/Microsoft.ReactNative.Cxx/ComponentView.Experimental.interop.h +14 -0
- package/Microsoft.ReactNative.Managed/packages.lock.json +107 -107
- package/PropertySheets/CppAppConsumeCSharpModule.props +2 -0
- package/PropertySheets/External/Microsoft.ReactNative.CSharp.Dependencies.props +1 -1
- package/PropertySheets/Generated/PackageVersion.g.props +3 -3
- package/ReactCommon/packages.lock.json +2 -2
- package/package.json +1 -1
|
@@ -363,6 +363,14 @@ RECT ComponentView::getClientRect() const noexcept {
|
|
|
363
363
|
return {};
|
|
364
364
|
}
|
|
365
365
|
|
|
366
|
+
winrt::Windows::Foundation::Point ComponentView::ScreenToLocal(winrt::Windows::Foundation::Point pt) noexcept {
|
|
367
|
+
return rootComponentView()->ConvertScreenToLocal(pt);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
winrt::Windows::Foundation::Point ComponentView::LocalToScreen(winrt::Windows::Foundation::Point pt) noexcept {
|
|
371
|
+
return rootComponentView()->ConvertLocalToScreen(pt);
|
|
372
|
+
}
|
|
373
|
+
|
|
366
374
|
// The offset from this elements parent to its children (accounts for things like scroll position)
|
|
367
375
|
facebook::react::Point ComponentView::getClientOffset() const noexcept {
|
|
368
376
|
assert(false);
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
#include <react/renderer/components/view/ViewProps.h>
|
|
12
12
|
#include <react/renderer/core/LayoutMetrics.h>
|
|
13
13
|
|
|
14
|
+
#include <ComponentView.Experimental.interop.h>
|
|
14
15
|
#include <Fabric/Composition/Theme.h>
|
|
15
16
|
#include <uiautomationcore.h>
|
|
16
17
|
#include <winrt/Microsoft.ReactNative.Composition.Input.h>
|
|
@@ -77,7 +78,8 @@ struct UnmountChildComponentViewArgs : public UnmountChildComponentViewArgsT<Unm
|
|
|
77
78
|
uint32_t m_index;
|
|
78
79
|
};
|
|
79
80
|
|
|
80
|
-
struct ComponentView
|
|
81
|
+
struct ComponentView
|
|
82
|
+
: public ComponentViewT<ComponentView, ::Microsoft::ReactNative::Composition::Experimental::IComponentViewInterop> {
|
|
81
83
|
ComponentView(facebook::react::Tag tag, winrt::Microsoft::ReactNative::ReactContext const &reactContext);
|
|
82
84
|
|
|
83
85
|
virtual std::vector<facebook::react::ComponentDescriptorProvider> supplementalComponentDescriptorProviders() noexcept;
|
|
@@ -105,6 +107,8 @@ struct ComponentView : public ComponentViewT<ComponentView> {
|
|
|
105
107
|
// returns true if the fn ever returned true
|
|
106
108
|
bool runOnChildren(bool forward, Mso::Functor<bool(ComponentView &)> &fn) noexcept;
|
|
107
109
|
virtual RECT getClientRect() const noexcept;
|
|
110
|
+
winrt::Windows::Foundation::Point ScreenToLocal(winrt::Windows::Foundation::Point pt) noexcept;
|
|
111
|
+
winrt::Windows::Foundation::Point LocalToScreen(winrt::Windows::Foundation::Point pt) noexcept;
|
|
108
112
|
// The offset from this elements parent to its children (accounts for things like scroll position)
|
|
109
113
|
virtual facebook::react::Point getClientOffset() const noexcept;
|
|
110
114
|
virtual void onLosingFocus(const winrt::Microsoft::ReactNative::LosingFocusEventArgs &args) noexcept;
|
|
@@ -818,6 +818,11 @@ uint8_t BorderPrimitive::numberOfVisuals() const noexcept {
|
|
|
818
818
|
return m_numBorderVisuals;
|
|
819
819
|
}
|
|
820
820
|
|
|
821
|
+
void BorderPrimitive::setOuter(
|
|
822
|
+
winrt::Microsoft::ReactNative::Composition::implementation::ComponentView *outer) noexcept {
|
|
823
|
+
m_outer = outer;
|
|
824
|
+
}
|
|
825
|
+
|
|
821
826
|
bool BorderPrimitive::TryUpdateSpecialBorderLayers(
|
|
822
827
|
winrt::Microsoft::ReactNative::Composition::implementation::Theme *theme,
|
|
823
828
|
std::array<winrt::Microsoft::ReactNative::Composition::Experimental::ISpriteVisual, SpecialBorderLayerCount>
|
|
@@ -29,6 +29,10 @@ struct BorderPrimitive {
|
|
|
29
29
|
|
|
30
30
|
void markNeedsUpdate() noexcept;
|
|
31
31
|
|
|
32
|
+
// We hoist focus visuals up the tree to allow them to be higher in the z-order.
|
|
33
|
+
// This means a single BorderPrimitive may change the owning ComponentView as focus moves around
|
|
34
|
+
void setOuter(winrt::Microsoft::ReactNative::Composition::implementation::ComponentView *outer) noexcept;
|
|
35
|
+
|
|
32
36
|
void updateProps(
|
|
33
37
|
const facebook::react::ViewProps &oldViewProps,
|
|
34
38
|
const facebook::react::ViewProps &newViewProps) noexcept;
|
|
@@ -189,40 +189,16 @@ HRESULT __stdcall CompositionRootAutomationProvider::ElementProviderFromPoint(
|
|
|
189
189
|
*pRetVal = nullptr;
|
|
190
190
|
|
|
191
191
|
if (auto rootView = rootComponentView()) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
static_cast<LONG>(local.Y * m_island.RasterizationScale())});
|
|
200
|
-
auto spFragment = provider.try_as<IRawElementProviderFragment>();
|
|
201
|
-
if (spFragment) {
|
|
202
|
-
*pRetVal = spFragment.detach();
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
return S_OK;
|
|
192
|
+
auto local = rootView->ConvertScreenToLocal({static_cast<float>(x), static_cast<float>(y)});
|
|
193
|
+
auto provider = rootView->UiaProviderFromPoint(
|
|
194
|
+
{static_cast<LONG>(local.X * rootView->LayoutMetrics().PointScaleFactor),
|
|
195
|
+
static_cast<LONG>(local.Y * rootView->LayoutMetrics().PointScaleFactor)});
|
|
196
|
+
auto spFragment = provider.try_as<IRawElementProviderFragment>();
|
|
197
|
+
if (spFragment) {
|
|
198
|
+
*pRetVal = spFragment.detach();
|
|
206
199
|
}
|
|
207
|
-
#endif
|
|
208
200
|
|
|
209
|
-
|
|
210
|
-
if (!IsWindow(m_hwnd)) {
|
|
211
|
-
// TODO: Add support for non-HWND based hosting
|
|
212
|
-
assert(false);
|
|
213
|
-
return E_FAIL;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
POINT clientPoint{static_cast<LONG>(x), static_cast<LONG>(y)};
|
|
217
|
-
ScreenToClient(m_hwnd, &clientPoint);
|
|
218
|
-
|
|
219
|
-
auto provider = rootView->UiaProviderFromPoint(clientPoint);
|
|
220
|
-
auto spFragment = provider.try_as<IRawElementProviderFragment>();
|
|
221
|
-
if (spFragment) {
|
|
222
|
-
*pRetVal = spFragment.detach();
|
|
223
|
-
return S_OK;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
201
|
+
return S_OK;
|
|
226
202
|
}
|
|
227
203
|
|
|
228
204
|
AddRef();
|
|
@@ -40,7 +40,7 @@ constexpr float FOCUS_VISUAL_WIDTH = 2.0f;
|
|
|
40
40
|
// ----- m_visual <-- Background / clip - Can be a custom visual depending on Component type
|
|
41
41
|
// |
|
|
42
42
|
// ----- Border Visuals x N (BorderPrimitive attached to m_visual)
|
|
43
|
-
// ------Focus Visual Container
|
|
43
|
+
// ------Focus Visual Container (created when hosting focus visuals)
|
|
44
44
|
// |
|
|
45
45
|
// |------Inner Focus Visual
|
|
46
46
|
// |
|
|
@@ -57,9 +57,6 @@ ComponentView::ComponentView(
|
|
|
57
57
|
: base_type(tag, reactContext), m_compContext(compContext), m_flags(flags) {
|
|
58
58
|
m_outerVisual = compContext.CreateSpriteVisual(); // TODO could be a raw ContainerVisual if we had a
|
|
59
59
|
// CreateContainerVisual in ICompositionContext
|
|
60
|
-
m_focusVisual = compContext.CreateSpriteVisual(); // TODO could be a raw ContainerVisual if we had a
|
|
61
|
-
// CreateContainerVisual in ICompositionContext
|
|
62
|
-
m_outerVisual.InsertAt(m_focusVisual, 0);
|
|
63
60
|
}
|
|
64
61
|
|
|
65
62
|
ComponentView::~ComponentView() {
|
|
@@ -90,13 +87,17 @@ void ComponentView::onThemeChanged() noexcept {
|
|
|
90
87
|
m_borderPrimitive->onThemeChanged(
|
|
91
88
|
m_layoutMetrics, BorderPrimitive::resolveAndAlignBorderMetrics(m_layoutMetrics, *viewProps()));
|
|
92
89
|
}
|
|
93
|
-
if (
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
90
|
+
if (m_componentHostingFocusVisual) {
|
|
91
|
+
if (m_componentHostingFocusVisual->m_focusPrimitive->m_focusInnerPrimitive) {
|
|
92
|
+
auto innerFocusMetrics = focusLayoutMetrics(true /*inner*/);
|
|
93
|
+
m_componentHostingFocusVisual->m_focusPrimitive->m_focusInnerPrimitive->onThemeChanged(
|
|
94
|
+
innerFocusMetrics, focusBorderMetrics(true /*inner*/, innerFocusMetrics));
|
|
95
|
+
}
|
|
96
|
+
if (m_componentHostingFocusVisual->m_focusPrimitive->m_focusOuterPrimitive) {
|
|
97
|
+
auto outerFocusMetrics = focusLayoutMetrics(true /*inner*/);
|
|
98
|
+
m_componentHostingFocusVisual->m_focusPrimitive->m_focusOuterPrimitive->onThemeChanged(
|
|
99
|
+
outerFocusMetrics, focusBorderMetrics(false /*inner*/, outerFocusMetrics));
|
|
100
|
+
}
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
if ((m_flags & ComponentViewFeatures::ShadowProps) == ComponentViewFeatures::ShadowProps) {
|
|
@@ -160,14 +161,18 @@ void ComponentView::updateProps(
|
|
|
160
161
|
if (m_borderPrimitive) {
|
|
161
162
|
m_borderPrimitive->updateProps(oldViewProps, newViewProps);
|
|
162
163
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
164
|
+
|
|
165
|
+
if (m_componentHostingFocusVisual) {
|
|
166
|
+
if (!newViewProps.enableFocusRing) {
|
|
167
|
+
m_componentHostingFocusVisual->hostFocusVisual(false, get_strong());
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (m_componentHostingFocusVisual->m_focusPrimitive->m_focusInnerPrimitive) {
|
|
171
|
+
m_componentHostingFocusVisual->m_focusPrimitive->m_focusInnerPrimitive->updateProps(oldViewProps, newViewProps);
|
|
172
|
+
}
|
|
173
|
+
if (m_componentHostingFocusVisual->m_focusPrimitive->m_focusOuterPrimitive) {
|
|
174
|
+
m_componentHostingFocusVisual->m_focusPrimitive->m_focusOuterPrimitive->updateProps(oldViewProps, newViewProps);
|
|
175
|
+
}
|
|
171
176
|
}
|
|
172
177
|
if ((m_flags & ComponentViewFeatures::ShadowProps) == ComponentViewFeatures::ShadowProps) {
|
|
173
178
|
updateShadowProps(oldViewProps, newViewProps);
|
|
@@ -200,44 +205,70 @@ void ComponentView::updateLayoutMetrics(
|
|
|
200
205
|
});
|
|
201
206
|
}
|
|
202
207
|
|
|
203
|
-
|
|
208
|
+
base_type::updateLayoutMetrics(layoutMetrics, oldLayoutMetrics);
|
|
204
209
|
|
|
205
210
|
if (layoutMetrics != oldLayoutMetrics) {
|
|
206
211
|
if (m_borderPrimitive) {
|
|
207
212
|
m_borderPrimitive->markNeedsUpdate();
|
|
208
213
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (m_focusOuterPrimitive) {
|
|
213
|
-
m_focusOuterPrimitive->markNeedsUpdate();
|
|
214
|
+
|
|
215
|
+
if (m_componentHostingFocusVisual) {
|
|
216
|
+
m_componentHostingFocusVisual->updateFocusLayoutMetrics();
|
|
214
217
|
}
|
|
215
218
|
}
|
|
216
219
|
|
|
217
|
-
base_type::updateLayoutMetrics(layoutMetrics, oldLayoutMetrics);
|
|
218
220
|
UpdateCenterPropertySet();
|
|
219
221
|
}
|
|
220
222
|
|
|
221
|
-
void ComponentView::updateFocusLayoutMetrics(
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
223
|
+
void ComponentView::updateFocusLayoutMetrics() noexcept {
|
|
224
|
+
facebook::react::RectangleEdges<bool> nudgeEdges;
|
|
225
|
+
auto scaleFactor = m_focusPrimitive->m_focusVisualComponent->m_layoutMetrics.pointScaleFactor;
|
|
226
|
+
if (m_focusPrimitive) {
|
|
227
|
+
if (m_focusPrimitive->m_focusOuterPrimitive) {
|
|
228
|
+
auto outerFocusMetrics = m_focusPrimitive->m_focusVisualComponent->focusLayoutMetrics(false /*inner*/);
|
|
229
|
+
|
|
230
|
+
if (outerFocusMetrics.frame.origin.x < 0) {
|
|
231
|
+
nudgeEdges.left = true;
|
|
232
|
+
}
|
|
233
|
+
if (outerFocusMetrics.frame.origin.y < 0) {
|
|
234
|
+
nudgeEdges.top = true;
|
|
235
|
+
}
|
|
236
|
+
if (outerFocusMetrics.frame.getMaxX() > m_layoutMetrics.frame.getMaxX()) {
|
|
237
|
+
nudgeEdges.right = true;
|
|
238
|
+
}
|
|
239
|
+
if (outerFocusMetrics.frame.getMaxY() > m_layoutMetrics.frame.getMaxY()) {
|
|
240
|
+
nudgeEdges.bottom = true;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
m_focusPrimitive->m_focusOuterPrimitive->RootVisual().Size(
|
|
244
|
+
{outerFocusMetrics.frame.size.width * scaleFactor -
|
|
245
|
+
(nudgeEdges.left ? (FOCUS_VISUAL_WIDTH * 2 * scaleFactor) : 0) -
|
|
246
|
+
(nudgeEdges.right ? (FOCUS_VISUAL_WIDTH * 2 * scaleFactor) : 0),
|
|
247
|
+
outerFocusMetrics.frame.size.height * scaleFactor -
|
|
248
|
+
(nudgeEdges.top ? (FOCUS_VISUAL_WIDTH * 2 * scaleFactor) : 0) -
|
|
249
|
+
(nudgeEdges.bottom ? (FOCUS_VISUAL_WIDTH * 2 * scaleFactor) : 0)});
|
|
250
|
+
m_focusPrimitive->m_focusOuterPrimitive->RootVisual().Offset(
|
|
251
|
+
{nudgeEdges.left ? 0 : -(FOCUS_VISUAL_WIDTH * 2 * scaleFactor),
|
|
252
|
+
nudgeEdges.top ? 0 : -(FOCUS_VISUAL_WIDTH * 2 * scaleFactor),
|
|
253
|
+
0.0f});
|
|
254
|
+
m_focusPrimitive->m_focusOuterPrimitive->markNeedsUpdate();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (m_focusPrimitive->m_focusInnerPrimitive) {
|
|
258
|
+
auto innerFocusMetrics = m_focusPrimitive->m_focusVisualComponent->focusLayoutMetrics(true /*inner*/);
|
|
259
|
+
m_focusPrimitive->m_focusInnerPrimitive->RootVisual().Size(
|
|
260
|
+
{innerFocusMetrics.frame.size.width * scaleFactor -
|
|
261
|
+
(nudgeEdges.left ? (FOCUS_VISUAL_WIDTH * scaleFactor) : 0) -
|
|
262
|
+
(nudgeEdges.right ? (FOCUS_VISUAL_WIDTH * scaleFactor) : 0),
|
|
263
|
+
innerFocusMetrics.frame.size.height * scaleFactor -
|
|
264
|
+
(nudgeEdges.top ? (FOCUS_VISUAL_WIDTH * scaleFactor) : 0) -
|
|
265
|
+
(nudgeEdges.bottom ? (FOCUS_VISUAL_WIDTH * scaleFactor) : 0)});
|
|
266
|
+
m_focusPrimitive->m_focusInnerPrimitive->RootVisual().Offset(
|
|
267
|
+
{nudgeEdges.left ? 0 : -FOCUS_VISUAL_WIDTH * scaleFactor,
|
|
268
|
+
nudgeEdges.top ? 0 : -FOCUS_VISUAL_WIDTH * scaleFactor,
|
|
269
|
+
0.0f});
|
|
270
|
+
m_focusPrimitive->m_focusInnerPrimitive->markNeedsUpdate();
|
|
271
|
+
}
|
|
241
272
|
}
|
|
242
273
|
}
|
|
243
274
|
|
|
@@ -288,13 +319,17 @@ void ComponentView::FinalizeUpdates(winrt::Microsoft::ReactNative::ComponentView
|
|
|
288
319
|
}
|
|
289
320
|
}
|
|
290
321
|
|
|
291
|
-
if (
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
322
|
+
if (m_componentHostingFocusVisual) {
|
|
323
|
+
if (m_componentHostingFocusVisual->m_focusPrimitive->m_focusInnerPrimitive) {
|
|
324
|
+
auto innerFocusMetrics = focusLayoutMetrics(true /*inner*/);
|
|
325
|
+
m_componentHostingFocusVisual->m_focusPrimitive->m_focusInnerPrimitive->finalize(
|
|
326
|
+
innerFocusMetrics, focusBorderMetrics(true /*inner*/, innerFocusMetrics));
|
|
327
|
+
}
|
|
328
|
+
if (m_componentHostingFocusVisual->m_focusPrimitive->m_focusOuterPrimitive) {
|
|
329
|
+
auto outerFocusMetrics = focusLayoutMetrics(false /*inner*/);
|
|
330
|
+
m_componentHostingFocusVisual->m_focusPrimitive->m_focusOuterPrimitive->finalize(
|
|
331
|
+
outerFocusMetrics, focusBorderMetrics(false /*inner*/, outerFocusMetrics));
|
|
332
|
+
}
|
|
298
333
|
}
|
|
299
334
|
|
|
300
335
|
if (m_FinalizeTransform) {
|
|
@@ -308,7 +343,12 @@ void ComponentView::onLostFocus(
|
|
|
308
343
|
const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept {
|
|
309
344
|
if (args.OriginalSource() == Tag()) {
|
|
310
345
|
m_eventEmitter->onBlur();
|
|
311
|
-
|
|
346
|
+
|
|
347
|
+
if (m_componentHostingFocusVisual) {
|
|
348
|
+
auto s = get_strong();
|
|
349
|
+
|
|
350
|
+
m_componentHostingFocusVisual->hostFocusVisual(false, get_strong());
|
|
351
|
+
}
|
|
312
352
|
if (m_uiaProvider) {
|
|
313
353
|
winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
|
|
314
354
|
m_uiaProvider, UIA_HasKeyboardFocusPropertyId, true, false);
|
|
@@ -317,12 +357,47 @@ void ComponentView::onLostFocus(
|
|
|
317
357
|
base_type::onLostFocus(args);
|
|
318
358
|
}
|
|
319
359
|
|
|
360
|
+
winrt::Microsoft::ReactNative::Composition::Experimental::IVisual ComponentView::visualToHostFocus() noexcept {
|
|
361
|
+
return OuterVisual();
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// We want to host focus visuals as close to the focused component as possible. However since the focus visuals extend
|
|
365
|
+
// past the bounds of the component, in cases where additional components are positioned directly next to this one, we'd
|
|
366
|
+
// get zorder issues causing most of the focus rect to be obscured. So we go up the tree until we find a component who's
|
|
367
|
+
// bounds will fix the entire focus rect.
|
|
368
|
+
winrt::com_ptr<ComponentView> ComponentView::focusVisualRoot(const facebook::react::Rect &focusRect) noexcept {
|
|
369
|
+
auto compVisual =
|
|
370
|
+
winrt::Microsoft::ReactNative::Composition::Experimental::CompositionContextHelper::InnerVisual(OuterVisual());
|
|
371
|
+
if (!compVisual) {
|
|
372
|
+
return get_strong();
|
|
373
|
+
// When not using lifted composition, force the focus visual to host within its own component, as we do not support
|
|
374
|
+
// ParentForTransform
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (facebook::react::Rect::intersect(focusRect, m_layoutMetrics.frame) == focusRect) {
|
|
378
|
+
return get_strong();
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (!m_parent) {
|
|
382
|
+
return get_strong();
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return m_parent.as<ComponentView>()->focusVisualRoot(
|
|
386
|
+
{{focusRect.origin.x + m_layoutMetrics.frame.origin.x, focusRect.origin.y + m_layoutMetrics.frame.origin.y},
|
|
387
|
+
focusRect.size});
|
|
388
|
+
}
|
|
389
|
+
|
|
320
390
|
void ComponentView::onGotFocus(
|
|
321
391
|
const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept {
|
|
322
392
|
if (args.OriginalSource() == Tag()) {
|
|
323
393
|
m_eventEmitter->onFocus();
|
|
324
394
|
if (viewProps()->enableFocusRing) {
|
|
325
|
-
|
|
395
|
+
facebook::react::Rect focusRect = m_layoutMetrics.frame;
|
|
396
|
+
focusRect.origin.x -= (FOCUS_VISUAL_WIDTH * 2);
|
|
397
|
+
focusRect.origin.y -= (FOCUS_VISUAL_WIDTH * 2);
|
|
398
|
+
focusRect.size.width += (FOCUS_VISUAL_WIDTH * 2);
|
|
399
|
+
focusRect.size.height += (FOCUS_VISUAL_WIDTH * 2);
|
|
400
|
+
focusVisualRoot(focusRect)->hostFocusVisual(true, get_strong());
|
|
326
401
|
}
|
|
327
402
|
if (m_uiaProvider) {
|
|
328
403
|
auto spProviderSimple = m_uiaProvider.try_as<IRawElementProviderSimple>();
|
|
@@ -493,39 +568,70 @@ facebook::react::BorderMetrics ComponentView::focusBorderMetrics(
|
|
|
493
568
|
return metrics;
|
|
494
569
|
}
|
|
495
570
|
|
|
496
|
-
void ComponentView::
|
|
497
|
-
if ((m_flags & ComponentViewFeatures::FocusVisual) == ComponentViewFeatures::FocusVisual) {
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
571
|
+
void ComponentView::hostFocusVisual(bool show, winrt::com_ptr<ComponentView> view) noexcept {
|
|
572
|
+
if ((view->m_flags & ComponentViewFeatures::FocusVisual) == ComponentViewFeatures::FocusVisual) {
|
|
573
|
+
// Any previous view showing focus visuals should have removed them before another shows it
|
|
574
|
+
assert(
|
|
575
|
+
!m_focusPrimitive || !m_focusPrimitive->m_focusVisualComponent ||
|
|
576
|
+
m_focusPrimitive->m_focusVisualComponent == view);
|
|
577
|
+
assert(
|
|
578
|
+
!m_focusPrimitive || !m_focusPrimitive->m_focusVisualComponent ||
|
|
579
|
+
view->m_componentHostingFocusVisual.get() == this);
|
|
580
|
+
if (show && !view->m_componentHostingFocusVisual) {
|
|
581
|
+
view->m_componentHostingFocusVisual = get_strong();
|
|
582
|
+
|
|
583
|
+
if (!m_focusPrimitive) {
|
|
584
|
+
m_focusPrimitive = std::make_unique<FocusPrimitive>();
|
|
506
585
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
586
|
+
m_focusPrimitive->m_focusVisualComponent = view;
|
|
587
|
+
|
|
588
|
+
if (!m_focusPrimitive->m_focusVisual) {
|
|
589
|
+
m_focusPrimitive->m_focusVisual = m_compContext.CreateSpriteVisual();
|
|
590
|
+
auto hostingVisual =
|
|
591
|
+
winrt::Microsoft::ReactNative::Composition::Experimental::CompositionContextHelper::InnerVisual(
|
|
592
|
+
visualToHostFocus())
|
|
593
|
+
.as<winrt::Microsoft::UI::Composition::ContainerVisual>();
|
|
594
|
+
if (hostingVisual) {
|
|
595
|
+
hostingVisual.Children().InsertAtTop(
|
|
596
|
+
winrt::Microsoft::ReactNative::Composition::Experimental::CompositionContextHelper::InnerVisual(
|
|
597
|
+
m_focusPrimitive->m_focusVisual));
|
|
598
|
+
} else {
|
|
599
|
+
assert(
|
|
600
|
+
view.get() ==
|
|
601
|
+
this); // When not using lifted comp, focus visuals should always host within their own component
|
|
602
|
+
OuterVisual().InsertAt(m_focusPrimitive->m_focusVisual, 1);
|
|
603
|
+
}
|
|
510
604
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
auto innerFocusMetrics = focusLayoutMetrics(true /*inner*/);
|
|
522
|
-
m_focusInnerPrimitive->finalize(innerFocusMetrics, focusBorderMetrics(true /*inner*/, innerFocusMetrics));
|
|
605
|
+
|
|
606
|
+
m_focusPrimitive->m_focusVisual.IsVisible(true);
|
|
607
|
+
assert(view->viewProps()->enableFocusRing);
|
|
608
|
+
if (!m_focusPrimitive->m_focusInnerPrimitive) {
|
|
609
|
+
m_focusPrimitive->m_focusInnerPrimitive = std::make_shared<BorderPrimitive>(*this);
|
|
610
|
+
m_focusPrimitive->m_focusVisual.InsertAt(m_focusPrimitive->m_focusInnerPrimitive->RootVisual(), 0);
|
|
611
|
+
}
|
|
612
|
+
if (!m_focusPrimitive->m_focusOuterPrimitive) {
|
|
613
|
+
m_focusPrimitive->m_focusOuterPrimitive = std::make_shared<BorderPrimitive>(*this);
|
|
614
|
+
m_focusPrimitive->m_focusVisual.InsertAt(m_focusPrimitive->m_focusOuterPrimitive->RootVisual(), 0);
|
|
523
615
|
}
|
|
524
|
-
if (
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
616
|
+
if (auto focusVisual =
|
|
617
|
+
winrt::Microsoft::ReactNative::Composition::Experimental::CompositionContextHelper::InnerVisual(
|
|
618
|
+
m_focusPrimitive->m_focusVisual)) {
|
|
619
|
+
auto outerVisual =
|
|
620
|
+
winrt::Microsoft::ReactNative::Composition::Experimental::CompositionContextHelper::InnerVisual(
|
|
621
|
+
view->OuterVisual());
|
|
622
|
+
focusVisual.ParentForTransform(outerVisual);
|
|
528
623
|
}
|
|
624
|
+
updateFocusLayoutMetrics();
|
|
625
|
+
auto innerFocusMetrics = view->focusLayoutMetrics(true /*inner*/);
|
|
626
|
+
m_focusPrimitive->m_focusInnerPrimitive->finalize(
|
|
627
|
+
innerFocusMetrics, view->focusBorderMetrics(true /*inner*/, innerFocusMetrics));
|
|
628
|
+
auto outerFocusMetrics = view->focusLayoutMetrics(false /*inner*/);
|
|
629
|
+
m_focusPrimitive->m_focusOuterPrimitive->finalize(
|
|
630
|
+
outerFocusMetrics, view->focusBorderMetrics(false /*inner*/, outerFocusMetrics));
|
|
631
|
+
} else if (!show && view->m_componentHostingFocusVisual && m_focusPrimitive) {
|
|
632
|
+
m_focusPrimitive->m_focusVisualComponent = nullptr;
|
|
633
|
+
m_focusPrimitive->m_focusVisual.IsVisible(false);
|
|
634
|
+
view->m_componentHostingFocusVisual = nullptr;
|
|
529
635
|
}
|
|
530
636
|
}
|
|
531
637
|
}
|
|
@@ -20,6 +20,13 @@ struct CompContext;
|
|
|
20
20
|
|
|
21
21
|
namespace winrt::Microsoft::ReactNative::Composition::implementation {
|
|
22
22
|
|
|
23
|
+
struct FocusPrimitive {
|
|
24
|
+
std::shared_ptr<BorderPrimitive> m_focusInnerPrimitive;
|
|
25
|
+
std::shared_ptr<BorderPrimitive> m_focusOuterPrimitive;
|
|
26
|
+
winrt::com_ptr<ComponentView> m_focusVisualComponent{nullptr}; // The owning component of focus visuals being hosted
|
|
27
|
+
winrt::Microsoft::ReactNative::Composition::Experimental::IVisual m_focusVisual{nullptr};
|
|
28
|
+
};
|
|
29
|
+
|
|
23
30
|
struct ComponentView : public ComponentViewT<
|
|
24
31
|
ComponentView,
|
|
25
32
|
winrt::Microsoft::ReactNative::implementation::ComponentView,
|
|
@@ -125,13 +132,10 @@ struct ComponentView : public ComponentViewT<
|
|
|
125
132
|
facebook::react::SharedViewEventEmitter m_eventEmitter;
|
|
126
133
|
|
|
127
134
|
private:
|
|
128
|
-
void updateFocusLayoutMetrics(
|
|
135
|
+
void updateFocusLayoutMetrics() noexcept;
|
|
129
136
|
void updateClippingPath(
|
|
130
137
|
facebook::react::LayoutMetrics const &layoutMetrics,
|
|
131
138
|
const facebook::react::ViewProps &viewProps) noexcept;
|
|
132
|
-
void finalizeFocusVisual(
|
|
133
|
-
facebook::react::LayoutMetrics const &layoutMetrics,
|
|
134
|
-
const facebook::react::ViewProps &viewProps) noexcept;
|
|
135
139
|
void UpdateCenterPropertySet() noexcept;
|
|
136
140
|
void FinalizeTransform(
|
|
137
141
|
facebook::react::LayoutMetrics const &layoutMetrics,
|
|
@@ -140,16 +144,18 @@ struct ComponentView : public ComponentViewT<
|
|
|
140
144
|
facebook::react::BorderMetrics focusBorderMetrics(bool inner, const facebook::react::LayoutMetrics &layoutMetrics)
|
|
141
145
|
const noexcept;
|
|
142
146
|
|
|
147
|
+
virtual winrt::Microsoft::ReactNative::Composition::Experimental::IVisual visualToHostFocus() noexcept;
|
|
148
|
+
virtual winrt::com_ptr<ComponentView> focusVisualRoot(const facebook::react::Rect &focusRect) noexcept;
|
|
149
|
+
|
|
143
150
|
bool m_hasTransformMatrixFacade : 1 {false};
|
|
144
|
-
bool m_showingFocusVisual : 1 {false};
|
|
145
151
|
bool m_FinalizeTransform : 1 {false};
|
|
146
152
|
bool m_tooltipTracked : 1 {false};
|
|
147
153
|
ComponentViewFeatures m_flags;
|
|
148
|
-
void
|
|
154
|
+
void hostFocusVisual(bool show, winrt::com_ptr<ComponentView> view) noexcept;
|
|
155
|
+
winrt::com_ptr<ComponentView>
|
|
156
|
+
m_componentHostingFocusVisual; // The component that we are showing our focus visuals within
|
|
149
157
|
std::shared_ptr<BorderPrimitive> m_borderPrimitive;
|
|
150
|
-
std::
|
|
151
|
-
std::shared_ptr<BorderPrimitive> m_focusOuterPrimitive;
|
|
152
|
-
winrt::Microsoft::ReactNative::Composition::Experimental::IVisual m_focusVisual{nullptr};
|
|
158
|
+
std::unique_ptr<FocusPrimitive> m_focusPrimitive{nullptr};
|
|
153
159
|
winrt::Microsoft::ReactNative::Composition::Experimental::IVisual m_outerVisual{nullptr};
|
|
154
160
|
winrt::event<winrt::Windows::Foundation::EventHandler<winrt::IInspectable>> m_themeChangedEvent;
|
|
155
161
|
};
|
|
@@ -176,7 +182,6 @@ struct ViewComponentView : public ViewComponentViewT<
|
|
|
176
182
|
facebook::react::LayoutMetrics const &layoutMetrics,
|
|
177
183
|
facebook::react::LayoutMetrics const &oldLayoutMetrics) noexcept override;
|
|
178
184
|
void prepareForRecycle() noexcept override;
|
|
179
|
-
bool TryFocus() noexcept;
|
|
180
185
|
bool focusable() const noexcept override;
|
|
181
186
|
void OnKeyDown(const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept override;
|
|
182
187
|
void OnKeyUp(const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept override;
|
package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp
CHANGED
|
@@ -76,7 +76,8 @@ void WindowsModalHostComponentView::EnsureModalCreated() {
|
|
|
76
76
|
// get the root hwnd
|
|
77
77
|
m_prevWindowID =
|
|
78
78
|
winrt::Microsoft::ReactNative::ReactCoreInjection::GetTopLevelWindowId(m_reactContext.Properties().Handle());
|
|
79
|
-
|
|
79
|
+
|
|
80
|
+
auto roothwnd = GetHwndForParenting();
|
|
80
81
|
|
|
81
82
|
m_hwnd = CreateWindow(
|
|
82
83
|
c_modalWindowClassName,
|
|
@@ -360,6 +360,29 @@ winrt::IInspectable ReactNativeIsland::GetUiaProvider() noexcept {
|
|
|
360
360
|
return m_uiaProvider;
|
|
361
361
|
}
|
|
362
362
|
|
|
363
|
+
winrt::Windows::Foundation::Point ReactNativeIsland::ConvertScreenToLocal(
|
|
364
|
+
winrt::Windows::Foundation::Point pt) noexcept {
|
|
365
|
+
if (m_island) {
|
|
366
|
+
auto pp = m_island.CoordinateConverter().ConvertScreenToLocal(
|
|
367
|
+
winrt::Windows::Graphics::PointInt32{static_cast<int32_t>(pt.X), static_cast<int32_t>(pt.Y)});
|
|
368
|
+
return {static_cast<float>(pp.X), static_cast<float>(pp.Y)};
|
|
369
|
+
}
|
|
370
|
+
POINT p{static_cast<LONG>(pt.X), static_cast<LONG>(pt.Y)};
|
|
371
|
+
ScreenToClient(m_hwnd, &p);
|
|
372
|
+
return {static_cast<float>(p.x) / m_scaleFactor, static_cast<float>(p.y) / m_scaleFactor};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
winrt::Windows::Foundation::Point ReactNativeIsland::ConvertLocalToScreen(
|
|
376
|
+
winrt::Windows::Foundation::Point pt) noexcept {
|
|
377
|
+
if (m_island) {
|
|
378
|
+
auto pp = m_island.CoordinateConverter().ConvertLocalToScreen(pt);
|
|
379
|
+
return {static_cast<float>(pp.X), static_cast<float>(pp.Y)};
|
|
380
|
+
}
|
|
381
|
+
POINT p{static_cast<LONG>(pt.X * m_scaleFactor), static_cast<LONG>(pt.Y * m_scaleFactor)};
|
|
382
|
+
ClientToScreen(m_hwnd, &p);
|
|
383
|
+
return {static_cast<float>(p.x), static_cast<float>(p.y)};
|
|
384
|
+
}
|
|
385
|
+
|
|
363
386
|
void ReactNativeIsland::SetWindow(uint64_t hwnd) noexcept {
|
|
364
387
|
m_hwnd = reinterpret_cast<HWND>(hwnd);
|
|
365
388
|
}
|
|
@@ -114,6 +114,9 @@ struct ReactNativeIsland
|
|
|
114
114
|
void SetWindow(uint64_t hwnd) noexcept;
|
|
115
115
|
int64_t SendMessage(uint32_t msg, uint64_t wParam, int64_t lParam) noexcept;
|
|
116
116
|
|
|
117
|
+
winrt::Windows::Foundation::Point ConvertScreenToLocal(winrt::Windows::Foundation::Point pt) noexcept;
|
|
118
|
+
winrt::Windows::Foundation::Point ConvertLocalToScreen(winrt::Windows::Foundation::Point pt) noexcept;
|
|
119
|
+
|
|
117
120
|
bool CapturePointer(
|
|
118
121
|
const winrt::Microsoft::ReactNative::Composition::Input::Pointer &pointer,
|
|
119
122
|
facebook::react::Tag tag) noexcept;
|
|
@@ -248,6 +248,26 @@ float RootComponentView::FontSizeMultiplier() const noexcept {
|
|
|
248
248
|
return 1.0f;
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
+
winrt::Windows::Foundation::Point RootComponentView::ConvertScreenToLocal(
|
|
252
|
+
winrt::Windows::Foundation::Point pt) noexcept {
|
|
253
|
+
if (auto rootView = m_wkRootView.get()) {
|
|
254
|
+
return winrt::get_self<winrt::Microsoft::ReactNative::implementation::ReactNativeIsland>(rootView)
|
|
255
|
+
->ConvertScreenToLocal(pt);
|
|
256
|
+
}
|
|
257
|
+
assert(false);
|
|
258
|
+
return {};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
winrt::Windows::Foundation::Point RootComponentView::ConvertLocalToScreen(
|
|
262
|
+
winrt::Windows::Foundation::Point pt) noexcept {
|
|
263
|
+
if (auto rootView = m_wkRootView.get()) {
|
|
264
|
+
return winrt::get_self<winrt::Microsoft::ReactNative::implementation::ReactNativeIsland>(rootView)
|
|
265
|
+
->ConvertLocalToScreen(pt);
|
|
266
|
+
}
|
|
267
|
+
assert(false);
|
|
268
|
+
return {};
|
|
269
|
+
}
|
|
270
|
+
|
|
251
271
|
winrt::Microsoft::UI::Content::ContentIsland RootComponentView::parentContentIsland() noexcept {
|
|
252
272
|
if (auto rootView = m_wkRootView.get()) {
|
|
253
273
|
return winrt::get_self<winrt::Microsoft::ReactNative::implementation::ReactNativeIsland>(rootView)->Island();
|
|
@@ -38,6 +38,9 @@ struct RootComponentView : RootComponentViewT<RootComponentView, ViewComponentVi
|
|
|
38
38
|
|
|
39
39
|
RootComponentView *rootComponentView() const noexcept override;
|
|
40
40
|
|
|
41
|
+
winrt::Windows::Foundation::Point ConvertScreenToLocal(winrt::Windows::Foundation::Point pt) noexcept;
|
|
42
|
+
winrt::Windows::Foundation::Point ConvertLocalToScreen(winrt::Windows::Foundation::Point pt) noexcept;
|
|
43
|
+
|
|
41
44
|
winrt::Microsoft::UI::Content::ContentIsland parentContentIsland() noexcept;
|
|
42
45
|
|
|
43
46
|
// Index that visuals can be inserted into OuterVisual for debugging UI
|
|
@@ -1258,4 +1258,14 @@ std::string ScrollViewComponentView::DefaultControlType() const noexcept {
|
|
|
1258
1258
|
return "scrollbar";
|
|
1259
1259
|
}
|
|
1260
1260
|
|
|
1261
|
+
winrt::com_ptr<ComponentView> ScrollViewComponentView::focusVisualRoot(
|
|
1262
|
+
const facebook::react::Rect &focusRect) noexcept {
|
|
1263
|
+
return get_strong();
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
winrt::Microsoft::ReactNative::Composition::Experimental::IVisual
|
|
1267
|
+
ScrollViewComponentView::visualToHostFocus() noexcept {
|
|
1268
|
+
return m_scrollVisual;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1261
1271
|
} // namespace winrt::Microsoft::ReactNative::Composition::implementation
|