react-native-windows 0.81.3 → 0.81.5
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/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/NativeComponent/ViewConfigIgnore.windows.js +45 -0
- package/Libraries/Renderer/implementations/ReactFabric-dev.js +38 -35
- package/Libraries/Renderer/implementations/ReactFabric-prod.js +51 -22
- package/Libraries/Renderer/implementations/ReactFabric-profiling.js +54 -24
- package/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js +36 -33
- package/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js +5 -5
- package/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js +5 -5
- package/Libraries/Renderer/shims/ReactNativeTypes.js +23 -11
- package/Libraries/Renderer/shims/ReactNativeTypes.windows.js +23 -12
- package/Microsoft.ReactNative/ABIViewManager.cpp +12 -1
- package/Microsoft.ReactNative/ComponentView.idl +2 -0
- package/Microsoft.ReactNative/Composition.Input.idl +7 -0
- package/Microsoft.ReactNative/CompositionComponentView.idl +5 -0
- package/Microsoft.ReactNative/CompositionHwndHost.idl +1 -0
- package/Microsoft.ReactNative/CompositionSwitcher.idl +16 -9
- package/Microsoft.ReactNative/Fabric/ComponentView.cpp +19 -1
- package/Microsoft.ReactNative/Fabric/ComponentView.h +10 -1
- package/Microsoft.ReactNative/Fabric/Composition/Composition.Input.cpp +12 -0
- package/Microsoft.ReactNative/Fabric/Composition/Composition.Input.h +15 -0
- package/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp +15 -0
- package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +75 -0
- package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.h +1 -0
- package/Microsoft.ReactNative/Fabric/Composition/CompositionHwndHost.cpp +10 -45
- package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +86 -19
- package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +4 -0
- package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp +95 -22
- package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.h +15 -0
- package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +61 -74
- package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +71 -12
- package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h +11 -0
- package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +4 -3
- package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +2 -1
- package/Microsoft.ReactNative/Fabric/Composition/ReactNativeWindow.cpp +245 -0
- package/Microsoft.ReactNative/Fabric/Composition/ReactNativeWindow.h +80 -0
- package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +33 -1
- package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +17 -0
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +47 -23
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +3 -0
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.cpp +3 -1
- package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp +8 -4
- package/Microsoft.ReactNative/Modules/ImageViewManagerModule.cpp +41 -15
- package/Microsoft.ReactNative/Modules/LogBoxModule.cpp +20 -95
- package/Microsoft.ReactNative/Modules/LogBoxModule.h +1 -1
- package/Microsoft.ReactNative/ReactNativeAppBuilder.cpp +0 -41
- package/Microsoft.ReactNative/ReactNativeAppBuilder.idl +0 -11
- package/Microsoft.ReactNative/ReactNativeIsland.idl +2 -3
- package/Microsoft.ReactNative/ReactNativeWin32App.cpp +31 -101
- package/Microsoft.ReactNative/ReactNativeWin32App.h +2 -13
- package/Microsoft.ReactNative/ReactNativeWindow.idl +44 -0
- package/Mso/src/dispatchQueue/queueService.cpp +3 -1
- package/Mso/src/dispatchQueue/uiScheduler_winrt.cpp +2 -1
- package/PropertySheets/Generated/PackageVersion.g.props +3 -3
- package/Shared/Networking/OriginPolicyHttpFilter.cpp +2 -1
- package/Shared/Shared.vcxitems +7 -0
- package/Shared/Shared.vcxitems.filters +6 -0
- package/codegen/react/components/rnwcore/ActivityIndicatorView.g.h +2 -1
- package/codegen/react/components/rnwcore/AndroidDrawerLayout.g.h +42 -25
- package/codegen/react/components/rnwcore/AndroidHorizontalScrollContentView.g.h +2 -1
- package/codegen/react/components/rnwcore/AndroidProgressBar.g.h +2 -1
- package/codegen/react/components/rnwcore/AndroidSwipeRefreshLayout.g.h +11 -6
- package/codegen/react/components/rnwcore/AndroidSwitch.g.h +11 -6
- package/codegen/react/components/rnwcore/DebuggingOverlay.g.h +1 -0
- package/codegen/react/components/rnwcore/InputAccessory.g.h +2 -1
- package/codegen/react/components/rnwcore/ModalHostView.g.h +40 -23
- package/codegen/react/components/rnwcore/PullToRefreshView.g.h +11 -6
- package/codegen/react/components/rnwcore/SafeAreaView.g.h +1 -0
- package/codegen/react/components/rnwcore/Switch.g.h +11 -6
- package/codegen/react/components/rnwcore/UnimplementedNativeView.g.h +2 -1
- package/codegen/react/components/rnwcore/VirtualView.g.h +41 -8
- package/package.json +21 -21
|
@@ -32,6 +32,8 @@ struct ContentIslandComponentView : ContentIslandComponentViewT<ContentIslandCom
|
|
|
32
32
|
uint32_t index) noexcept override;
|
|
33
33
|
void Connect(const winrt::Microsoft::UI::Content::ContentIsland &contentIsland) noexcept;
|
|
34
34
|
|
|
35
|
+
winrt::Microsoft::UI::Content::ChildSiteLink ChildSiteLink() noexcept;
|
|
36
|
+
|
|
35
37
|
void updateLayoutMetrics(
|
|
36
38
|
facebook::react::LayoutMetrics const &layoutMetrics,
|
|
37
39
|
facebook::react::LayoutMetrics const &oldLayoutMetrics) noexcept;
|
|
@@ -58,15 +60,28 @@ struct ContentIslandComponentView : ContentIslandComponentViewT<ContentIslandCom
|
|
|
58
60
|
void OnMounted() noexcept;
|
|
59
61
|
void OnUnmounted() noexcept;
|
|
60
62
|
void ParentLayoutChanged() noexcept;
|
|
63
|
+
void ConnectInternal() noexcept;
|
|
64
|
+
winrt::Microsoft::UI::Content::ContentIsland ParentContentIsland() noexcept;
|
|
61
65
|
|
|
62
66
|
bool m_layoutChangePosted{false};
|
|
67
|
+
winrt::Microsoft::UI::Content::ContentIsland m_parentContentIsland{nullptr};
|
|
63
68
|
winrt::Microsoft::UI::Content::ContentIsland m_islandToConnect{nullptr};
|
|
69
|
+
std::optional<winrt::Microsoft::UI::Input::FocusNavigationReason> m_pendingNavigateFocus;
|
|
70
|
+
|
|
64
71
|
winrt::event_token m_mountedToken;
|
|
65
72
|
winrt::event_token m_unmountedToken;
|
|
66
73
|
std::vector<winrt::Microsoft::ReactNative::ComponentView::LayoutMetricsChanged_revoker> m_layoutMetricChangedRevokers;
|
|
67
74
|
winrt::Microsoft::UI::Content::ChildSiteLink m_childSiteLink{nullptr};
|
|
68
75
|
winrt::Microsoft::UI::Input::InputFocusNavigationHost m_navigationHost{nullptr};
|
|
69
76
|
winrt::event_token m_navigationHostDepartFocusRequestedToken{};
|
|
77
|
+
std::optional<winrt::Microsoft::UI::Input::FocusNavigationReason> m_pendingFocus;
|
|
78
|
+
|
|
79
|
+
// Issue #15557: Store ViewChanged subscriptions to parent ScrollViews for transform updates
|
|
80
|
+
struct ViewChangedSubscription {
|
|
81
|
+
winrt::weak_ref<winrt::Microsoft::ReactNative::Composition::ScrollViewComponentView> scrollView;
|
|
82
|
+
winrt::event_token token;
|
|
83
|
+
};
|
|
84
|
+
std::vector<ViewChangedSubscription> m_viewChangedSubscriptions;
|
|
70
85
|
|
|
71
86
|
// Automation
|
|
72
87
|
void ConfigureChildSiteLinkAutomation() noexcept;
|
package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp
CHANGED
|
@@ -37,9 +37,9 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
|
|
|
37
37
|
~ModalHostView() {
|
|
38
38
|
if (m_popUp) {
|
|
39
39
|
// Unregister closing event handler
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
m_appWindowClosingToken
|
|
40
|
+
if (m_appWindowClosingToken) {
|
|
41
|
+
m_rnWindow.AppWindow().Closing(m_appWindowClosingToken);
|
|
42
|
+
m_appWindowClosingToken = {};
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
// Reset topWindowID before destroying
|
|
@@ -49,21 +49,15 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
|
|
|
49
49
|
m_prevWindowID = 0;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
// Close island
|
|
53
|
-
if (m_reactNativeIsland) {
|
|
54
|
-
m_reactNativeIsland.Island().Close();
|
|
55
|
-
m_reactNativeIsland = nullptr;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
52
|
// Hide popup
|
|
59
53
|
if (m_popUp.IsVisible()) {
|
|
60
54
|
m_popUp.Hide();
|
|
61
55
|
}
|
|
62
56
|
|
|
63
57
|
// Destroy AppWindow this automatically resumes parent window to receive inputs
|
|
64
|
-
if (
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
if (m_rnWindow.AppWindow()) {
|
|
59
|
+
m_rnWindow.Close();
|
|
60
|
+
m_rnWindow = nullptr;
|
|
67
61
|
}
|
|
68
62
|
|
|
69
63
|
// Bring parent window to foreground
|
|
@@ -111,11 +105,11 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
|
|
|
111
105
|
}
|
|
112
106
|
|
|
113
107
|
// Update Title if changed and AppWindow exists
|
|
114
|
-
if (
|
|
108
|
+
if (m_rnWindow && (!oldProps || newViewProps.title != oldViewProps.title)) {
|
|
115
109
|
// Use empty string if title is not set
|
|
116
110
|
winrt::hstring titleValue =
|
|
117
111
|
newViewProps.title.has_value() ? winrt::to_hstring(newViewProps.title.value()) : winrt::hstring();
|
|
118
|
-
|
|
112
|
+
m_rnWindow.AppWindow().Title(titleValue);
|
|
119
113
|
}
|
|
120
114
|
|
|
121
115
|
::Microsoft::ReactNativeSpecs::BaseModalHostView<ModalHostView>::UpdateProps(view, newProps, oldProps);
|
|
@@ -181,7 +175,7 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
|
|
|
181
175
|
}
|
|
182
176
|
|
|
183
177
|
void AdjustWindowSize(const winrt::Microsoft::ReactNative::LayoutMetrics &layoutMetrics) noexcept {
|
|
184
|
-
if (!
|
|
178
|
+
if (!m_rnWindow) {
|
|
185
179
|
return;
|
|
186
180
|
}
|
|
187
181
|
|
|
@@ -198,17 +192,17 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
|
|
|
198
192
|
clientHeightPx = std::max(100, clientHeightPx);
|
|
199
193
|
|
|
200
194
|
// Size the client area directly
|
|
201
|
-
|
|
195
|
+
m_rnWindow.AppWindow().ResizeClient({clientWidthPx, clientHeightPx});
|
|
202
196
|
|
|
203
197
|
// Center the window on its parent
|
|
204
198
|
RECT parentRC;
|
|
205
199
|
GetWindowRect(m_parentHwnd, &parentRC);
|
|
206
|
-
auto outerSize =
|
|
200
|
+
auto outerSize = m_rnWindow.AppWindow().Size();
|
|
207
201
|
|
|
208
202
|
int32_t xCor = parentRC.left + (parentRC.right - parentRC.left - outerSize.Width) / 2;
|
|
209
203
|
int32_t yCor = parentRC.top + (parentRC.bottom - parentRC.top - outerSize.Height) / 2;
|
|
210
204
|
|
|
211
|
-
|
|
205
|
+
m_rnWindow.AppWindow().Move({xCor, yCor});
|
|
212
206
|
};
|
|
213
207
|
|
|
214
208
|
void ShowOnUIThread(const winrt::Microsoft::ReactNative::ComponentView &view) {
|
|
@@ -231,8 +225,7 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
|
|
|
231
225
|
|
|
232
226
|
// dispatch onShow event
|
|
233
227
|
if (auto eventEmitter = EventEmitter()) {
|
|
234
|
-
|
|
235
|
-
eventEmitter->onShow(eventArgs);
|
|
228
|
+
eventEmitter->onShow({});
|
|
236
229
|
}
|
|
237
230
|
}
|
|
238
231
|
}
|
|
@@ -261,8 +254,7 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
|
|
|
261
254
|
|
|
262
255
|
// Dispatch onDismiss event
|
|
263
256
|
if (auto eventEmitter = EventEmitter()) {
|
|
264
|
-
|
|
265
|
-
eventEmitter->onDismiss(eventArgs);
|
|
257
|
+
eventEmitter->onDismiss({});
|
|
266
258
|
}
|
|
267
259
|
}
|
|
268
260
|
|
|
@@ -279,59 +271,55 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
|
|
|
279
271
|
view.as<::Microsoft::ReactNative::Composition::Experimental::IComponentViewInterop>()->GetHwndForParenting();
|
|
280
272
|
|
|
281
273
|
auto portal = view.as<winrt::Microsoft::ReactNative::Composition::PortalComponentView>();
|
|
282
|
-
m_reactNativeIsland = winrt::Microsoft::ReactNative::ReactNativeIsland::CreatePortal(portal);
|
|
283
|
-
auto contentIsland = m_reactNativeIsland.Island();
|
|
284
|
-
|
|
285
274
|
m_popUp = winrt::Microsoft::UI::Content::DesktopPopupSiteBridge::Create(
|
|
286
275
|
portal.Parent()
|
|
287
276
|
.as<winrt::Microsoft::ReactNative::Composition::ComponentView>()
|
|
288
277
|
.Root()
|
|
289
278
|
.ReactNativeIsland()
|
|
290
279
|
.Island());
|
|
291
|
-
m_popUp.Connect(contentIsland);
|
|
292
280
|
|
|
293
281
|
// Get AppWindow and configure presenter
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
282
|
+
m_rnWindow = winrt::Microsoft::ReactNative::ReactNativeWindow::CreateFromContentSiteBridgeAndIsland(
|
|
283
|
+
m_popUp, winrt::Microsoft::ReactNative::ReactNativeIsland::CreatePortal(portal));
|
|
284
|
+
m_rnWindow.ResizePolicy(winrt::Microsoft::ReactNative::ContentSizePolicy::None);
|
|
285
|
+
auto overlappedPresenter = winrt::Microsoft::UI::Windowing::OverlappedPresenter::Create();
|
|
286
|
+
|
|
287
|
+
// Configure presenter for modal behavior
|
|
288
|
+
overlappedPresenter.IsModal(true);
|
|
289
|
+
overlappedPresenter.SetBorderAndTitleBar(true, true);
|
|
290
|
+
|
|
291
|
+
// modal should only have close button
|
|
292
|
+
overlappedPresenter.IsMinimizable(false);
|
|
293
|
+
overlappedPresenter.IsMaximizable(false);
|
|
294
|
+
|
|
295
|
+
// Apply the presenter to the window
|
|
296
|
+
m_rnWindow.AppWindow().SetPresenter(overlappedPresenter);
|
|
297
|
+
|
|
298
|
+
// Hide the title bar icon
|
|
299
|
+
m_rnWindow.AppWindow().TitleBar().IconShowOptions(
|
|
300
|
+
winrt::Microsoft::UI::Windowing::IconShowOptions::HideIconAndSystemMenu);
|
|
301
|
+
|
|
302
|
+
// Set initial title using the stored local props
|
|
303
|
+
if (m_localProps && m_localProps->title.has_value()) {
|
|
304
|
+
winrt::hstring titleValue = winrt::to_hstring(m_localProps->title.value());
|
|
305
|
+
m_rnWindow.AppWindow().Title(titleValue);
|
|
306
|
+
} else {
|
|
307
|
+
m_rnWindow.AppWindow().Title(L""); // Empty title if not provided
|
|
308
|
+
}
|
|
319
309
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
eventEmitter->onRequestClose(eventArgs);
|
|
331
|
-
}
|
|
310
|
+
// Handle close request ('X' button)
|
|
311
|
+
m_appWindowClosingToken =
|
|
312
|
+
m_rnWindow.AppWindow().Closing([wkThis = get_weak()](
|
|
313
|
+
const winrt::Microsoft::UI::Windowing::AppWindow & /*sender*/,
|
|
314
|
+
const winrt::Microsoft::UI::Windowing::AppWindowClosingEventArgs &args) {
|
|
315
|
+
args.Cancel(true); // Prevent default close
|
|
316
|
+
if (auto strongThis = wkThis.get()) {
|
|
317
|
+
// Dispatch onRequestClose event
|
|
318
|
+
if (auto eventEmitter = strongThis->EventEmitter()) {
|
|
319
|
+
eventEmitter->onRequestClose({});
|
|
332
320
|
}
|
|
333
|
-
}
|
|
334
|
-
|
|
321
|
+
}
|
|
322
|
+
});
|
|
335
323
|
|
|
336
324
|
// set the top-level windows as the new hwnd
|
|
337
325
|
winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId(
|
|
@@ -352,10 +340,10 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
|
|
|
352
340
|
});
|
|
353
341
|
*/
|
|
354
342
|
|
|
355
|
-
m_islandStateChangedToken =
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
343
|
+
m_islandStateChangedToken = m_rnWindow.ReactNativeIsland().Island().StateChanged(
|
|
344
|
+
[weakThis = get_weak()](
|
|
345
|
+
winrt::Microsoft::UI::Content::ContentIsland const &island,
|
|
346
|
+
winrt::Microsoft::UI::Content::ContentIslandStateChangedEventArgs const &args) {
|
|
359
347
|
if (auto pThis = weakThis.get()) {
|
|
360
348
|
if (args.DidRasterizationScaleChange() || args.DidLayoutDirectionChange()) {
|
|
361
349
|
pThis->UpdateConstraints();
|
|
@@ -375,7 +363,7 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
|
|
|
375
363
|
m_popUp.SiteView().EnvironmentView().DisplayId());
|
|
376
364
|
auto workArea = displayArea.WorkArea();
|
|
377
365
|
|
|
378
|
-
float scale =
|
|
366
|
+
float scale = m_rnWindow.ReactNativeIsland().Island().RasterizationScale();
|
|
379
367
|
|
|
380
368
|
winrt::Microsoft::ReactNative::LayoutConstraints constraints;
|
|
381
369
|
constraints.MinimumSize = {0, 0};
|
|
@@ -384,7 +372,7 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
|
|
|
384
372
|
static_cast<float>((workArea.Width / scale) * 0.9), static_cast<float>((workArea.Height / scale) * 0.9)};
|
|
385
373
|
constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::Undefined;
|
|
386
374
|
|
|
387
|
-
auto layoutDirection =
|
|
375
|
+
auto layoutDirection = m_rnWindow.ReactNativeIsland().Island().LayoutDirection();
|
|
388
376
|
if (layoutDirection == winrt::Microsoft::UI::Content::ContentLayoutDirection::LeftToRight)
|
|
389
377
|
constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::LeftToRight;
|
|
390
378
|
else if (layoutDirection == winrt::Microsoft::UI::Content::ContentLayoutDirection::RightToLeft)
|
|
@@ -394,7 +382,7 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
|
|
|
394
382
|
// When no constraint is set (maxSize is std::numeric_limits<Float>::infinity()), yoga will layout the content to a
|
|
395
383
|
// desired size If we provide a specific max size, then contents with a flex:1 will expand to fill that size. We
|
|
396
384
|
// might want to provide a windows specific property to control this behavior.
|
|
397
|
-
m_state.UpdateState(winrt::make<ModalHostState>(constraints,
|
|
385
|
+
m_state.UpdateState(winrt::make<ModalHostState>(constraints, scale));
|
|
398
386
|
}
|
|
399
387
|
|
|
400
388
|
static void TrySetFocus(const winrt::Microsoft::ReactNative::ComponentView &view) {
|
|
@@ -414,9 +402,8 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
|
|
|
414
402
|
winrt::event_token m_departFocusToken;
|
|
415
403
|
winrt::event_token m_childLayoutMetricsToken;
|
|
416
404
|
winrt::Microsoft::ReactNative::IComponentState m_state{nullptr};
|
|
417
|
-
winrt::Microsoft::ReactNative::
|
|
405
|
+
winrt::Microsoft::ReactNative::ReactNativeWindow m_rnWindow{nullptr};
|
|
418
406
|
winrt::Microsoft::UI::Content::DesktopPopupSiteBridge m_popUp{nullptr};
|
|
419
|
-
winrt::Microsoft::UI::Windowing::AppWindow m_appWindow{nullptr};
|
|
420
407
|
winrt::event_token m_appWindowClosingToken;
|
|
421
408
|
winrt::com_ptr<::Microsoft::ReactNativeSpecs::ModalHostViewProps> m_localProps{nullptr};
|
|
422
409
|
};
|
|
@@ -167,6 +167,26 @@ void ParagraphComponentView::updateTextAlignment(
|
|
|
167
167
|
m_textLayout = nullptr;
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
facebook::react::Tag ParagraphComponentView::hitTest(
|
|
171
|
+
facebook::react::Point pt,
|
|
172
|
+
facebook::react::Point &localPt,
|
|
173
|
+
bool ignorePointerEvents) const noexcept {
|
|
174
|
+
facebook::react::Point ptLocal{pt.x - m_layoutMetrics.frame.origin.x, pt.y - m_layoutMetrics.frame.origin.y};
|
|
175
|
+
const auto &props = paragraphProps();
|
|
176
|
+
const auto &vProps = *viewProps();
|
|
177
|
+
|
|
178
|
+
if (props.isSelectable && ptLocal.x >= 0 && ptLocal.x <= m_layoutMetrics.frame.size.width && ptLocal.y >= 0 &&
|
|
179
|
+
ptLocal.y <= m_layoutMetrics.frame.size.height) {
|
|
180
|
+
// claims if pointer events are enabled for this component
|
|
181
|
+
if (ignorePointerEvents || vProps.pointerEvents == facebook::react::PointerEventsMode::Auto ||
|
|
182
|
+
vProps.pointerEvents == facebook::react::PointerEventsMode::BoxOnly) {
|
|
183
|
+
localPt = ptLocal;
|
|
184
|
+
return Tag();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return Super::hitTest(pt, localPt, ignorePointerEvents);
|
|
188
|
+
}
|
|
189
|
+
|
|
170
190
|
bool ParagraphComponentView::IsTextSelectableAtPoint(facebook::react::Point pt) noexcept {
|
|
171
191
|
// paragraph-level selectable prop is enabled
|
|
172
192
|
const auto &props = paragraphProps();
|
|
@@ -519,6 +539,7 @@ void ParagraphComponentView::ClearSelection() noexcept {
|
|
|
519
539
|
m_selectionStart = std::nullopt;
|
|
520
540
|
m_selectionEnd = std::nullopt;
|
|
521
541
|
m_isSelecting = false;
|
|
542
|
+
m_isWordSelecting = false;
|
|
522
543
|
if (hadSelection) {
|
|
523
544
|
// Clears selection highlight
|
|
524
545
|
DrawText();
|
|
@@ -534,7 +555,8 @@ void ParagraphComponentView::OnPointerPressed(
|
|
|
534
555
|
return;
|
|
535
556
|
}
|
|
536
557
|
|
|
537
|
-
|
|
558
|
+
// Use Tag() to get coordinates in component's local space
|
|
559
|
+
auto pp = args.GetCurrentPoint(static_cast<int32_t>(Tag()));
|
|
538
560
|
|
|
539
561
|
// Ignores right-click
|
|
540
562
|
if (pp.Properties().PointerUpdateKind() ==
|
|
@@ -545,8 +567,8 @@ void ParagraphComponentView::OnPointerPressed(
|
|
|
545
567
|
|
|
546
568
|
auto position = pp.Position();
|
|
547
569
|
|
|
548
|
-
|
|
549
|
-
|
|
570
|
+
// GetCurrentPoint(Tag()) returns position relative to component origin
|
|
571
|
+
facebook::react::Point localPt{position.X, position.Y};
|
|
550
572
|
|
|
551
573
|
std::optional<int32_t> charPosition = GetTextPositionAtPoint(localPt);
|
|
552
574
|
|
|
@@ -568,7 +590,13 @@ void ParagraphComponentView::OnPointerPressed(
|
|
|
568
590
|
|
|
569
591
|
if (isDoubleClick) {
|
|
570
592
|
SelectWordAtPosition(*charPosition);
|
|
571
|
-
|
|
593
|
+
if (m_selectionStart && m_selectionEnd) {
|
|
594
|
+
m_isWordSelecting = true;
|
|
595
|
+
m_wordAnchorStart = *m_selectionStart;
|
|
596
|
+
m_wordAnchorEnd = *m_selectionEnd;
|
|
597
|
+
m_isSelecting = true;
|
|
598
|
+
CapturePointer(args.Pointer());
|
|
599
|
+
}
|
|
572
600
|
} else {
|
|
573
601
|
// Single-click: start drag selection
|
|
574
602
|
m_selectionStart = charPosition;
|
|
@@ -610,17 +638,35 @@ void ParagraphComponentView::OnPointerMoved(
|
|
|
610
638
|
facebook::react::Point localPt{position.X, position.Y};
|
|
611
639
|
std::optional<int32_t> charPosition = GetClampedTextPosition(localPt);
|
|
612
640
|
|
|
613
|
-
if (charPosition
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
641
|
+
if (charPosition) {
|
|
642
|
+
if (m_isWordSelecting) {
|
|
643
|
+
// Extend selection by whole words
|
|
644
|
+
auto [wordStart, wordEnd] = GetWordBoundariesAtPosition(*charPosition);
|
|
645
|
+
|
|
646
|
+
if (*charPosition < m_wordAnchorStart) {
|
|
647
|
+
m_selectionStart = wordStart;
|
|
648
|
+
m_selectionEnd = m_wordAnchorEnd;
|
|
649
|
+
} else if (*charPosition >= m_wordAnchorEnd) {
|
|
650
|
+
m_selectionStart = m_wordAnchorStart;
|
|
651
|
+
m_selectionEnd = wordEnd;
|
|
652
|
+
} else {
|
|
653
|
+
m_selectionStart = m_wordAnchorStart;
|
|
654
|
+
m_selectionEnd = m_wordAnchorEnd;
|
|
655
|
+
}
|
|
656
|
+
DrawText();
|
|
657
|
+
args.Handled(true);
|
|
658
|
+
} else if (charPosition != m_selectionEnd) {
|
|
659
|
+
m_selectionEnd = charPosition;
|
|
660
|
+
DrawText();
|
|
661
|
+
args.Handled(true);
|
|
662
|
+
}
|
|
617
663
|
}
|
|
618
664
|
}
|
|
619
665
|
|
|
620
666
|
void ParagraphComponentView::OnPointerReleased(
|
|
621
667
|
const winrt::Microsoft::ReactNative::Composition::Input::PointerRoutedEventArgs &args) noexcept {
|
|
622
668
|
// Check for right-click to show context menu
|
|
623
|
-
auto pp = args.GetCurrentPoint(
|
|
669
|
+
auto pp = args.GetCurrentPoint(static_cast<int32_t>(Tag()));
|
|
624
670
|
if (pp.Properties().PointerUpdateKind() ==
|
|
625
671
|
winrt::Microsoft::ReactNative::Composition::Input::PointerUpdateKind::RightButtonReleased) {
|
|
626
672
|
const auto &props = paragraphProps();
|
|
@@ -637,6 +683,7 @@ void ParagraphComponentView::OnPointerReleased(
|
|
|
637
683
|
}
|
|
638
684
|
|
|
639
685
|
m_isSelecting = false;
|
|
686
|
+
m_isWordSelecting = false;
|
|
640
687
|
|
|
641
688
|
ReleasePointerCapture(args.Pointer());
|
|
642
689
|
|
|
@@ -661,6 +708,7 @@ void ParagraphComponentView::OnPointerCaptureLost() noexcept {
|
|
|
661
708
|
// Pointer capture was lost stop any active selection drag
|
|
662
709
|
if (m_isSelecting) {
|
|
663
710
|
m_isSelecting = false;
|
|
711
|
+
m_isWordSelecting = false;
|
|
664
712
|
|
|
665
713
|
if (!m_selectionStart || !m_selectionEnd || *m_selectionStart == *m_selectionEnd) {
|
|
666
714
|
m_selectionStart = std::nullopt;
|
|
@@ -711,12 +759,17 @@ void ParagraphComponentView::CopySelectionToClipboard() noexcept {
|
|
|
711
759
|
winrt::Windows::ApplicationModel::DataTransfer::Clipboard::SetContent(dataPackage);
|
|
712
760
|
}
|
|
713
761
|
|
|
714
|
-
|
|
762
|
+
std::pair<int32_t, int32_t> ParagraphComponentView::GetWordBoundariesAtPosition(int32_t charPosition) noexcept {
|
|
715
763
|
const std::wstring utf16Text{facebook::react::WindowsTextLayoutManager::GetTransformedText(m_attributedStringBox)};
|
|
716
764
|
const int32_t textLength = static_cast<int32_t>(utf16Text.length());
|
|
717
765
|
|
|
718
|
-
if (utf16Text.empty() || charPosition < 0
|
|
719
|
-
return;
|
|
766
|
+
if (utf16Text.empty() || charPosition < 0) {
|
|
767
|
+
return {0, 0};
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
charPosition = std::min(charPosition, textLength - 1);
|
|
771
|
+
if (charPosition < 0) {
|
|
772
|
+
return {0, 0};
|
|
720
773
|
}
|
|
721
774
|
|
|
722
775
|
int32_t wordStart = charPosition;
|
|
@@ -749,6 +802,12 @@ void ParagraphComponentView::SelectWordAtPosition(int32_t charPosition) noexcept
|
|
|
749
802
|
}
|
|
750
803
|
}
|
|
751
804
|
|
|
805
|
+
return {wordStart, wordEnd};
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
void ParagraphComponentView::SelectWordAtPosition(int32_t charPosition) noexcept {
|
|
809
|
+
auto [wordStart, wordEnd] = GetWordBoundariesAtPosition(charPosition);
|
|
810
|
+
|
|
752
811
|
if (wordEnd > wordStart) {
|
|
753
812
|
SetSelection(wordStart, wordEnd);
|
|
754
813
|
DrawText();
|
|
@@ -49,6 +49,11 @@ struct ParagraphComponentView : ParagraphComponentViewT<ParagraphComponentView,
|
|
|
49
49
|
static facebook::react::SharedViewProps defaultProps() noexcept;
|
|
50
50
|
const facebook::react::ParagraphProps ¶graphProps() const noexcept;
|
|
51
51
|
|
|
52
|
+
facebook::react::Tag hitTest(
|
|
53
|
+
facebook::react::Point pt,
|
|
54
|
+
facebook::react::Point &localPt,
|
|
55
|
+
bool ignorePointerEvents = false) const noexcept override;
|
|
56
|
+
|
|
52
57
|
// Returns true when text is selectable
|
|
53
58
|
bool focusable() const noexcept override;
|
|
54
59
|
|
|
@@ -95,6 +100,7 @@ struct ParagraphComponentView : ParagraphComponentViewT<ParagraphComponentView,
|
|
|
95
100
|
|
|
96
101
|
// Selects the word at the given character position
|
|
97
102
|
void SelectWordAtPosition(int32_t charPosition) noexcept;
|
|
103
|
+
std::pair<int32_t, int32_t> GetWordBoundariesAtPosition(int32_t charPosition) noexcept;
|
|
98
104
|
|
|
99
105
|
// Shows a context menu with Copy/Select All options on right-click
|
|
100
106
|
void ShowContextMenu() noexcept;
|
|
@@ -113,6 +119,11 @@ struct ParagraphComponentView : ParagraphComponentViewT<ParagraphComponentView,
|
|
|
113
119
|
std::optional<int32_t> m_selectionEnd;
|
|
114
120
|
bool m_isSelecting{false};
|
|
115
121
|
|
|
122
|
+
// Double click + drag selection
|
|
123
|
+
bool m_isWordSelecting{false};
|
|
124
|
+
int32_t m_wordAnchorStart{0};
|
|
125
|
+
int32_t m_wordAnchorEnd{0};
|
|
126
|
+
|
|
116
127
|
// Double-click detection
|
|
117
128
|
std::chrono::steady_clock::time_point m_lastClickTime{};
|
|
118
129
|
std::optional<int32_t> m_lastClickPosition;
|
|
@@ -168,9 +168,6 @@ winrt::Microsoft::ReactNative::ReactNativeIsland ReactNativeIsland::CreatePortal
|
|
|
168
168
|
return winrt::make<ReactNativeIsland>(portal);
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
ReactNativeIsland::ReactNativeIsland() noexcept
|
|
172
|
-
: ReactNativeIsland(winrt::Microsoft::UI::Composition::Compositor{nullptr}) {}
|
|
173
|
-
|
|
174
171
|
ReactNativeIsland::~ReactNativeIsland() noexcept {
|
|
175
172
|
#ifdef USE_WINUI3
|
|
176
173
|
if (m_island) {
|
|
@@ -220,6 +217,10 @@ void ReactNativeIsland::ReactViewHost(winrt::Microsoft::ReactNative::IReactViewH
|
|
|
220
217
|
}
|
|
221
218
|
}
|
|
222
219
|
|
|
220
|
+
winrt::Microsoft::UI::Composition::Compositor ReactNativeIsland::Compositor() noexcept {
|
|
221
|
+
return m_compositor;
|
|
222
|
+
}
|
|
223
|
+
|
|
223
224
|
winrt::Microsoft::UI::Composition::Visual ReactNativeIsland::RootVisual() noexcept {
|
|
224
225
|
return winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper::InnerVisual(
|
|
225
226
|
m_rootVisual);
|
|
@@ -48,7 +48,6 @@ struct FocusNavigationResult : FocusNavigationResultT<FocusNavigationResult> {
|
|
|
48
48
|
|
|
49
49
|
struct ReactNativeIsland
|
|
50
50
|
: ReactNativeIslandT<ReactNativeIsland, Composition::Experimental::IInternalCompositionRootView> {
|
|
51
|
-
ReactNativeIsland() noexcept;
|
|
52
51
|
~ReactNativeIsland() noexcept;
|
|
53
52
|
|
|
54
53
|
ReactNativeIsland(const winrt::Microsoft::UI::Composition::Compositor &compositor) noexcept;
|
|
@@ -65,6 +64,8 @@ struct ReactNativeIsland
|
|
|
65
64
|
ReactNative::IReactViewHost ReactViewHost() noexcept;
|
|
66
65
|
void ReactViewHost(ReactNative::IReactViewHost const &value);
|
|
67
66
|
|
|
67
|
+
winrt::Microsoft::UI::Composition::Compositor Compositor() noexcept;
|
|
68
|
+
|
|
68
69
|
winrt::Microsoft::UI::Composition::Visual RootVisual() noexcept;
|
|
69
70
|
|
|
70
71
|
// property RootVisual
|