react-native-windows 0.82.0-preview.1 → 0.82.0-preview.10
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/Animated/nodes/AnimatedValue.js +0 -8
- package/Libraries/BatchedBridge/BatchedBridge.js +1 -0
- package/Libraries/BatchedBridge/MessageQueue.js +1 -0
- package/Libraries/Components/Switch/Switch.js +1 -1
- package/Libraries/Components/Switch/Switch.windows.js +1 -1
- package/Libraries/Core/ReactNativeVersion.js +2 -2
- package/Libraries/Core/Timers/JSTimers.js +1 -0
- package/Libraries/Core/Timers/NativeTiming.js +1 -0
- package/Libraries/Core/Timers/immediateShim.js +1 -0
- package/Libraries/Core/setUpPerformance.js +3 -5
- package/Libraries/Interaction/PanResponder.js +6 -51
- package/Microsoft.ReactNative/ComponentView.idl +2 -0
- package/Microsoft.ReactNative/Composition.Input.idl +7 -0
- package/Microsoft.ReactNative/Fabric/ComponentView.cpp +18 -0
- package/Microsoft.ReactNative/Fabric/ComponentView.h +9 -0
- 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/CompositionEventHandler.cpp +75 -0
- package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.h +1 -0
- package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp +6 -67
- package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.h +0 -4
- package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +82 -14
- package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h +11 -4
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +59 -31
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +3 -0
- package/Microsoft.ReactNative/Modules/ImageViewManagerModule.cpp +42 -15
- package/Microsoft.ReactNative.Cxx/ReactCommon/react/timing/primitives.h +12 -0
- package/PropertySheets/Generated/PackageVersion.g.props +2 -2
- package/PropertySheets/Warnings.props +1 -2
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/BaseParagraphProps.cpp +174 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/BaseParagraphProps.h +69 -0
- package/Scripts/rnw-dependencies.ps1 +15 -1
- package/Shared/Shared.vcxitems +1 -0
- package/Shared/Shared.vcxitems.filters +1 -3
- package/codegen/NativePerformanceSpec.g.h +41 -35
- package/codegen/NativeReactNativeFeatureFlagsSpec.g.h +55 -49
- package/codegen/rnwcoreJSI-generated.cpp +434 -422
- package/codegen/rnwcoreJSI.h +18 -0
- package/index.js +6 -0
- package/index.windows.js +6 -0
- package/package.json +15 -14
- package/src/private/featureflags/ReactNativeFeatureFlags.js +6 -1
- package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +2 -1
- package/src/private/setup/{setUpPerformanceObserver.js → setUpPerformanceModern.js} +43 -18
- package/src/private/specs_DEPRECATED/components/SwitchNativeComponent.js +1 -0
- package/src/private/specs_DEPRECATED/modules/NativeTiming.js +1 -0
- package/src/private/webapis/performance/EventTiming.js +34 -15
- package/src/private/webapis/performance/LongTasks.js +35 -2
- package/src/private/webapis/performance/Performance.js +49 -13
- package/src/private/webapis/performance/PerformanceEntry.js +21 -8
- package/src/private/webapis/performance/PerformanceObserver.js +30 -1
- package/src/private/webapis/performance/ReactNativeStartupTiming.js +3 -24
- package/src/private/webapis/performance/ResourceTiming.js +29 -18
- package/src/private/webapis/performance/UserTiming.js +33 -28
- package/src/private/webapis/performance/internals/RawPerformanceEntry.js +3 -4
- package/src/private/webapis/performance/specs/NativePerformance.js +2 -0
|
@@ -107,6 +107,10 @@ void ParagraphComponentView::updateProps(
|
|
|
107
107
|
m_requireRedraw = true;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
if (oldViewProps.selectionColor != newViewProps.selectionColor) {
|
|
111
|
+
m_requireRedraw = true;
|
|
112
|
+
}
|
|
113
|
+
|
|
110
114
|
Super::updateProps(props, oldProps);
|
|
111
115
|
}
|
|
112
116
|
|
|
@@ -167,6 +171,26 @@ void ParagraphComponentView::updateTextAlignment(
|
|
|
167
171
|
m_textLayout = nullptr;
|
|
168
172
|
}
|
|
169
173
|
|
|
174
|
+
facebook::react::Tag ParagraphComponentView::hitTest(
|
|
175
|
+
facebook::react::Point pt,
|
|
176
|
+
facebook::react::Point &localPt,
|
|
177
|
+
bool ignorePointerEvents) const noexcept {
|
|
178
|
+
facebook::react::Point ptLocal{pt.x - m_layoutMetrics.frame.origin.x, pt.y - m_layoutMetrics.frame.origin.y};
|
|
179
|
+
const auto &props = paragraphProps();
|
|
180
|
+
const auto &vProps = *viewProps();
|
|
181
|
+
|
|
182
|
+
if (props.isSelectable && ptLocal.x >= 0 && ptLocal.x <= m_layoutMetrics.frame.size.width && ptLocal.y >= 0 &&
|
|
183
|
+
ptLocal.y <= m_layoutMetrics.frame.size.height) {
|
|
184
|
+
// claims if pointer events are enabled for this component
|
|
185
|
+
if (ignorePointerEvents || vProps.pointerEvents == facebook::react::PointerEventsMode::Auto ||
|
|
186
|
+
vProps.pointerEvents == facebook::react::PointerEventsMode::BoxOnly) {
|
|
187
|
+
localPt = ptLocal;
|
|
188
|
+
return Tag();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return Super::hitTest(pt, localPt, ignorePointerEvents);
|
|
192
|
+
}
|
|
193
|
+
|
|
170
194
|
bool ParagraphComponentView::IsTextSelectableAtPoint(facebook::react::Point pt) noexcept {
|
|
171
195
|
// paragraph-level selectable prop is enabled
|
|
172
196
|
const auto &props = paragraphProps();
|
|
@@ -454,9 +478,14 @@ void ParagraphComponentView::DrawSelectionHighlight(
|
|
|
454
478
|
return;
|
|
455
479
|
}
|
|
456
480
|
|
|
457
|
-
// TODO: use prop selectionColor if provided
|
|
458
481
|
winrt::com_ptr<ID2D1SolidColorBrush> selectionBrush;
|
|
459
|
-
|
|
482
|
+
D2D1_COLOR_F selectionColor;
|
|
483
|
+
const auto &props = paragraphProps();
|
|
484
|
+
if (props.selectionColor) {
|
|
485
|
+
selectionColor = theme()->D2DColor(**props.selectionColor);
|
|
486
|
+
} else {
|
|
487
|
+
selectionColor = theme()->D2DPlatformColor("Highlight@40");
|
|
488
|
+
}
|
|
460
489
|
hr = renderTarget.CreateSolidColorBrush(selectionColor, selectionBrush.put());
|
|
461
490
|
|
|
462
491
|
if (FAILED(hr)) {
|
|
@@ -519,6 +548,7 @@ void ParagraphComponentView::ClearSelection() noexcept {
|
|
|
519
548
|
m_selectionStart = std::nullopt;
|
|
520
549
|
m_selectionEnd = std::nullopt;
|
|
521
550
|
m_isSelecting = false;
|
|
551
|
+
m_isWordSelecting = false;
|
|
522
552
|
if (hadSelection) {
|
|
523
553
|
// Clears selection highlight
|
|
524
554
|
DrawText();
|
|
@@ -534,7 +564,8 @@ void ParagraphComponentView::OnPointerPressed(
|
|
|
534
564
|
return;
|
|
535
565
|
}
|
|
536
566
|
|
|
537
|
-
|
|
567
|
+
// Use Tag() to get coordinates in component's local space
|
|
568
|
+
auto pp = args.GetCurrentPoint(static_cast<int32_t>(Tag()));
|
|
538
569
|
|
|
539
570
|
// Ignores right-click
|
|
540
571
|
if (pp.Properties().PointerUpdateKind() ==
|
|
@@ -545,8 +576,8 @@ void ParagraphComponentView::OnPointerPressed(
|
|
|
545
576
|
|
|
546
577
|
auto position = pp.Position();
|
|
547
578
|
|
|
548
|
-
|
|
549
|
-
|
|
579
|
+
// GetCurrentPoint(Tag()) returns position relative to component origin
|
|
580
|
+
facebook::react::Point localPt{position.X, position.Y};
|
|
550
581
|
|
|
551
582
|
std::optional<int32_t> charPosition = GetTextPositionAtPoint(localPt);
|
|
552
583
|
|
|
@@ -568,7 +599,13 @@ void ParagraphComponentView::OnPointerPressed(
|
|
|
568
599
|
|
|
569
600
|
if (isDoubleClick) {
|
|
570
601
|
SelectWordAtPosition(*charPosition);
|
|
571
|
-
|
|
602
|
+
if (m_selectionStart && m_selectionEnd) {
|
|
603
|
+
m_isWordSelecting = true;
|
|
604
|
+
m_wordAnchorStart = *m_selectionStart;
|
|
605
|
+
m_wordAnchorEnd = *m_selectionEnd;
|
|
606
|
+
m_isSelecting = true;
|
|
607
|
+
CapturePointer(args.Pointer());
|
|
608
|
+
}
|
|
572
609
|
} else {
|
|
573
610
|
// Single-click: start drag selection
|
|
574
611
|
m_selectionStart = charPosition;
|
|
@@ -610,17 +647,35 @@ void ParagraphComponentView::OnPointerMoved(
|
|
|
610
647
|
facebook::react::Point localPt{position.X, position.Y};
|
|
611
648
|
std::optional<int32_t> charPosition = GetClampedTextPosition(localPt);
|
|
612
649
|
|
|
613
|
-
if (charPosition
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
650
|
+
if (charPosition) {
|
|
651
|
+
if (m_isWordSelecting) {
|
|
652
|
+
// Extend selection by whole words
|
|
653
|
+
auto [wordStart, wordEnd] = GetWordBoundariesAtPosition(*charPosition);
|
|
654
|
+
|
|
655
|
+
if (*charPosition < m_wordAnchorStart) {
|
|
656
|
+
m_selectionStart = wordStart;
|
|
657
|
+
m_selectionEnd = m_wordAnchorEnd;
|
|
658
|
+
} else if (*charPosition >= m_wordAnchorEnd) {
|
|
659
|
+
m_selectionStart = m_wordAnchorStart;
|
|
660
|
+
m_selectionEnd = wordEnd;
|
|
661
|
+
} else {
|
|
662
|
+
m_selectionStart = m_wordAnchorStart;
|
|
663
|
+
m_selectionEnd = m_wordAnchorEnd;
|
|
664
|
+
}
|
|
665
|
+
DrawText();
|
|
666
|
+
args.Handled(true);
|
|
667
|
+
} else if (charPosition != m_selectionEnd) {
|
|
668
|
+
m_selectionEnd = charPosition;
|
|
669
|
+
DrawText();
|
|
670
|
+
args.Handled(true);
|
|
671
|
+
}
|
|
617
672
|
}
|
|
618
673
|
}
|
|
619
674
|
|
|
620
675
|
void ParagraphComponentView::OnPointerReleased(
|
|
621
676
|
const winrt::Microsoft::ReactNative::Composition::Input::PointerRoutedEventArgs &args) noexcept {
|
|
622
677
|
// Check for right-click to show context menu
|
|
623
|
-
auto pp = args.GetCurrentPoint(
|
|
678
|
+
auto pp = args.GetCurrentPoint(static_cast<int32_t>(Tag()));
|
|
624
679
|
if (pp.Properties().PointerUpdateKind() ==
|
|
625
680
|
winrt::Microsoft::ReactNative::Composition::Input::PointerUpdateKind::RightButtonReleased) {
|
|
626
681
|
const auto &props = paragraphProps();
|
|
@@ -637,6 +692,7 @@ void ParagraphComponentView::OnPointerReleased(
|
|
|
637
692
|
}
|
|
638
693
|
|
|
639
694
|
m_isSelecting = false;
|
|
695
|
+
m_isWordSelecting = false;
|
|
640
696
|
|
|
641
697
|
ReleasePointerCapture(args.Pointer());
|
|
642
698
|
|
|
@@ -661,6 +717,7 @@ void ParagraphComponentView::OnPointerCaptureLost() noexcept {
|
|
|
661
717
|
// Pointer capture was lost stop any active selection drag
|
|
662
718
|
if (m_isSelecting) {
|
|
663
719
|
m_isSelecting = false;
|
|
720
|
+
m_isWordSelecting = false;
|
|
664
721
|
|
|
665
722
|
if (!m_selectionStart || !m_selectionEnd || *m_selectionStart == *m_selectionEnd) {
|
|
666
723
|
m_selectionStart = std::nullopt;
|
|
@@ -711,12 +768,17 @@ void ParagraphComponentView::CopySelectionToClipboard() noexcept {
|
|
|
711
768
|
winrt::Windows::ApplicationModel::DataTransfer::Clipboard::SetContent(dataPackage);
|
|
712
769
|
}
|
|
713
770
|
|
|
714
|
-
|
|
771
|
+
std::pair<int32_t, int32_t> ParagraphComponentView::GetWordBoundariesAtPosition(int32_t charPosition) noexcept {
|
|
715
772
|
const std::wstring utf16Text{facebook::react::WindowsTextLayoutManager::GetTransformedText(m_attributedStringBox)};
|
|
716
773
|
const int32_t textLength = static_cast<int32_t>(utf16Text.length());
|
|
717
774
|
|
|
718
|
-
if (utf16Text.empty() || charPosition < 0
|
|
719
|
-
return;
|
|
775
|
+
if (utf16Text.empty() || charPosition < 0) {
|
|
776
|
+
return {0, 0};
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
charPosition = std::min(charPosition, textLength - 1);
|
|
780
|
+
if (charPosition < 0) {
|
|
781
|
+
return {0, 0};
|
|
720
782
|
}
|
|
721
783
|
|
|
722
784
|
int32_t wordStart = charPosition;
|
|
@@ -749,6 +811,12 @@ void ParagraphComponentView::SelectWordAtPosition(int32_t charPosition) noexcept
|
|
|
749
811
|
}
|
|
750
812
|
}
|
|
751
813
|
|
|
814
|
+
return {wordStart, wordEnd};
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
void ParagraphComponentView::SelectWordAtPosition(int32_t charPosition) noexcept {
|
|
818
|
+
auto [wordStart, wordEnd] = GetWordBoundariesAtPosition(charPosition);
|
|
819
|
+
|
|
752
820
|
if (wordEnd > wordStart) {
|
|
753
821
|
SetSelection(wordStart, wordEnd);
|
|
754
822
|
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
|
|
|
@@ -90,16 +95,13 @@ struct ParagraphComponentView : ParagraphComponentViewT<ParagraphComponentView,
|
|
|
90
95
|
std::optional<int32_t> GetClampedTextPosition(facebook::react::Point pt) noexcept;
|
|
91
96
|
std::string GetSelectedText() const noexcept;
|
|
92
97
|
|
|
93
|
-
// Copies currently selected text to the system clipboard
|
|
94
98
|
void CopySelectionToClipboard() noexcept;
|
|
95
99
|
|
|
96
|
-
// Selects the word at the given character position
|
|
97
100
|
void SelectWordAtPosition(int32_t charPosition) noexcept;
|
|
101
|
+
std::pair<int32_t, int32_t> GetWordBoundariesAtPosition(int32_t charPosition) noexcept;
|
|
98
102
|
|
|
99
|
-
// Shows a context menu with Copy/Select All options on right-click
|
|
100
103
|
void ShowContextMenu() noexcept;
|
|
101
104
|
|
|
102
|
-
// m_selectionStart <= m_selectionEnd
|
|
103
105
|
void SetSelection(int32_t start, int32_t end) noexcept;
|
|
104
106
|
|
|
105
107
|
winrt::com_ptr<::IDWriteTextLayout> m_textLayout;
|
|
@@ -113,6 +115,11 @@ struct ParagraphComponentView : ParagraphComponentViewT<ParagraphComponentView,
|
|
|
113
115
|
std::optional<int32_t> m_selectionEnd;
|
|
114
116
|
bool m_isSelecting{false};
|
|
115
117
|
|
|
118
|
+
// Double click + drag selection
|
|
119
|
+
bool m_isWordSelecting{false};
|
|
120
|
+
int32_t m_wordAnchorStart{0};
|
|
121
|
+
int32_t m_wordAnchorEnd{0};
|
|
122
|
+
|
|
116
123
|
// Double-click detection
|
|
117
124
|
std::chrono::steady_clock::time_point m_lastClickTime{};
|
|
118
125
|
std::optional<int32_t> m_lastClickPosition;
|
package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp
CHANGED
|
@@ -186,6 +186,7 @@ struct CompTextHost : public winrt::implements<CompTextHost, ITextHost> {
|
|
|
186
186
|
|
|
187
187
|
auto pt = m_outer->getClientOffset();
|
|
188
188
|
m_outer->m_caretVisual.Position({x - pt.x, y - pt.y});
|
|
189
|
+
m_outer->m_caretPosition = {x, y};
|
|
189
190
|
return true;
|
|
190
191
|
}
|
|
191
192
|
|
|
@@ -696,17 +697,10 @@ void WindowsTextInputComponentView::OnPointerPressed(
|
|
|
696
697
|
}
|
|
697
698
|
|
|
698
699
|
if (m_textServices && msg) {
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
args.Handled(true);
|
|
704
|
-
} else {
|
|
705
|
-
LRESULT lresult;
|
|
706
|
-
DrawBlock db(*this);
|
|
707
|
-
auto hr = m_textServices->TxSendMessage(msg, static_cast<WPARAM>(wParam), static_cast<LPARAM>(lParam), &lresult);
|
|
708
|
-
args.Handled(hr != S_FALSE);
|
|
709
|
-
}
|
|
700
|
+
LRESULT lresult;
|
|
701
|
+
DrawBlock db(*this);
|
|
702
|
+
auto hr = m_textServices->TxSendMessage(msg, static_cast<WPARAM>(wParam), static_cast<LPARAM>(lParam), &lresult);
|
|
703
|
+
args.Handled(hr != S_FALSE);
|
|
710
704
|
}
|
|
711
705
|
|
|
712
706
|
// Emits the OnPressIn event
|
|
@@ -768,10 +762,18 @@ void WindowsTextInputComponentView::OnPointerReleased(
|
|
|
768
762
|
}
|
|
769
763
|
|
|
770
764
|
if (m_textServices && msg) {
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
765
|
+
// Show context menu on right button release (standard Windows behavior)
|
|
766
|
+
if (msg == WM_RBUTTONUP && !windowsTextInputProps().contextMenuHidden) {
|
|
767
|
+
ShowContextMenu(LocalToScreen(position));
|
|
768
|
+
args.Handled(true);
|
|
769
|
+
} else if (msg == WM_RBUTTONUP) {
|
|
770
|
+
// Context menu is hidden - don't mark as handled, let app add custom behavior
|
|
771
|
+
} else {
|
|
772
|
+
LRESULT lresult;
|
|
773
|
+
DrawBlock db(*this);
|
|
774
|
+
auto hr = m_textServices->TxSendMessage(msg, static_cast<WPARAM>(wParam), static_cast<LPARAM>(lParam), &lresult);
|
|
775
|
+
args.Handled(hr != S_FALSE);
|
|
776
|
+
}
|
|
775
777
|
}
|
|
776
778
|
|
|
777
779
|
// Emits the OnPressOut event
|
|
@@ -1508,18 +1510,26 @@ void WindowsTextInputComponentView::UpdateCharFormat() noexcept {
|
|
|
1508
1510
|
cfNew.wWeight =
|
|
1509
1511
|
props.textAttributes.fontWeight ? static_cast<WORD>(*props.textAttributes.fontWeight) : DWRITE_FONT_WEIGHT_NORMAL;
|
|
1510
1512
|
|
|
1511
|
-
// set font style
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
//
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1513
|
+
// set font style (italic)
|
|
1514
|
+
cfNew.dwMask |= CFM_ITALIC;
|
|
1515
|
+
if (props.textAttributes.fontStyle == facebook::react::FontStyle::Italic ||
|
|
1516
|
+
props.textAttributes.fontStyle == facebook::react::FontStyle::Oblique) {
|
|
1517
|
+
cfNew.dwEffects |= CFE_ITALIC;
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
// set text decoration (underline and strikethrough)
|
|
1521
|
+
cfNew.dwMask |= (CFM_UNDERLINE | CFM_STRIKEOUT);
|
|
1522
|
+
if (props.textAttributes.textDecorationLineType.has_value()) {
|
|
1523
|
+
auto decorationType = *props.textAttributes.textDecorationLineType;
|
|
1524
|
+
if (decorationType == facebook::react::TextDecorationLineType::Underline ||
|
|
1525
|
+
decorationType == facebook::react::TextDecorationLineType::UnderlineStrikethrough) {
|
|
1526
|
+
cfNew.dwEffects |= CFE_UNDERLINE;
|
|
1527
|
+
}
|
|
1528
|
+
if (decorationType == facebook::react::TextDecorationLineType::Strikethrough ||
|
|
1529
|
+
decorationType == facebook::react::TextDecorationLineType::UnderlineStrikethrough) {
|
|
1530
|
+
cfNew.dwEffects |= CFE_STRIKEOUT;
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1523
1533
|
|
|
1524
1534
|
// set font family
|
|
1525
1535
|
if (!props.textAttributes.fontFamily.empty()) {
|
|
@@ -1871,6 +1881,21 @@ void WindowsTextInputComponentView::updateSpellCheck(bool enable) noexcept {
|
|
|
1871
1881
|
m_textServices->TxSendMessage(EM_SETLANGOPTIONS, IMF_SPELLCHECKING, enable ? newLangOptions : 0, &lresult));
|
|
1872
1882
|
}
|
|
1873
1883
|
|
|
1884
|
+
void WindowsTextInputComponentView::OnContextMenuKey(
|
|
1885
|
+
const winrt::Microsoft::ReactNative::Composition::Input::ContextMenuKeyEventArgs &args) noexcept {
|
|
1886
|
+
// Handle context menu key event (SHIFT+F10 or Context Menu key)
|
|
1887
|
+
if (!windowsTextInputProps().contextMenuHidden) {
|
|
1888
|
+
// m_caretPosition is stored from TxSetCaretPos in RichEdit client rect space (physical pixels).
|
|
1889
|
+
// LocalToScreen expects logical (DIP) coordinates, so divide by pointScaleFactor.
|
|
1890
|
+
auto screenPt = LocalToScreen(winrt::Windows::Foundation::Point{
|
|
1891
|
+
static_cast<float>(m_caretPosition.x) / m_layoutMetrics.pointScaleFactor,
|
|
1892
|
+
static_cast<float>(m_caretPosition.y) / m_layoutMetrics.pointScaleFactor});
|
|
1893
|
+
ShowContextMenu(screenPt);
|
|
1894
|
+
args.Handled(true);
|
|
1895
|
+
}
|
|
1896
|
+
// If contextMenuHidden, don't mark as handled - let app handle it
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1874
1899
|
void WindowsTextInputComponentView::ShowContextMenu(const winrt::Windows::Foundation::Point &position) noexcept {
|
|
1875
1900
|
HMENU menu = CreatePopupMenu();
|
|
1876
1901
|
if (!menu)
|
|
@@ -1890,13 +1915,16 @@ void WindowsTextInputComponentView::ShowContextMenu(const winrt::Windows::Founda
|
|
|
1890
1915
|
AppendMenuW(menu, MF_STRING | (canPaste ? 0 : MF_GRAYED), 3, L"Paste");
|
|
1891
1916
|
AppendMenuW(menu, MF_STRING | (!isEmpty && !isReadOnly ? 0 : MF_GRAYED), 4, L"Select All");
|
|
1892
1917
|
|
|
1893
|
-
POINT cursorPos;
|
|
1894
|
-
GetCursorPos(&cursorPos);
|
|
1895
|
-
|
|
1896
1918
|
HWND hwnd = GetActiveWindow();
|
|
1897
1919
|
|
|
1898
1920
|
int cmd = TrackPopupMenu(
|
|
1899
|
-
menu,
|
|
1921
|
+
menu,
|
|
1922
|
+
TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD | TPM_NONOTIFY,
|
|
1923
|
+
static_cast<int>(position.X),
|
|
1924
|
+
static_cast<int>(position.Y),
|
|
1925
|
+
0,
|
|
1926
|
+
hwnd,
|
|
1927
|
+
NULL);
|
|
1900
1928
|
|
|
1901
1929
|
if (cmd == 1) { // Cut
|
|
1902
1930
|
m_textServices->TxSendMessage(WM_CUT, 0, 0, &res);
|
|
@@ -67,6 +67,8 @@ struct WindowsTextInputComponentView
|
|
|
67
67
|
void OnKeyUp(const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept override;
|
|
68
68
|
void OnCharacterReceived(const winrt::Microsoft::ReactNative::Composition::Input::CharacterReceivedRoutedEventArgs
|
|
69
69
|
&args) noexcept override;
|
|
70
|
+
void OnContextMenuKey(
|
|
71
|
+
const winrt::Microsoft::ReactNative::Composition::Input::ContextMenuKeyEventArgs &args) noexcept override;
|
|
70
72
|
void onMounted() noexcept override;
|
|
71
73
|
|
|
72
74
|
std::optional<std::string> getAccessiblityValue() noexcept override;
|
|
@@ -146,6 +148,7 @@ struct WindowsTextInputComponentView
|
|
|
146
148
|
DWORD m_propBitsMask{0};
|
|
147
149
|
DWORD m_propBits{0};
|
|
148
150
|
HCURSOR m_hcursor{nullptr};
|
|
151
|
+
POINT m_caretPosition{0, 0};
|
|
149
152
|
std::chrono::steady_clock::time_point m_lastClickTime{};
|
|
150
153
|
std::vector<facebook::react::CompWindowsTextInputSubmitKeyEventsStruct> m_submitKeyEvents;
|
|
151
154
|
};
|
|
@@ -24,15 +24,28 @@ using namespace Windows::Storage::Streams;
|
|
|
24
24
|
|
|
25
25
|
namespace Microsoft::ReactNative {
|
|
26
26
|
|
|
27
|
+
static const char *ERROR_INVALID_URI = "E_INVALID_URI";
|
|
28
|
+
static const char *ERROR_GET_SIZE_FAILURE = "E_GET_SIZE_FAILURE";
|
|
29
|
+
|
|
27
30
|
winrt::fire_and_forget GetImageSizeAsync(
|
|
28
31
|
const winrt::Microsoft::ReactNative::IReactPropertyBag &properties,
|
|
29
32
|
std::string uriString,
|
|
30
33
|
winrt::Microsoft::ReactNative::JSValue &&headers,
|
|
31
34
|
Mso::Functor<void(int32_t width, int32_t height)> successCallback,
|
|
32
|
-
Mso::Functor<void()> errorCallback) {
|
|
35
|
+
Mso::Functor<void(const char *errorCode, std::string errorMessage)> errorCallback) {
|
|
33
36
|
bool succeeded{false};
|
|
37
|
+
const char *errorCode = ERROR_GET_SIZE_FAILURE;
|
|
38
|
+
std::string errorMessage;
|
|
34
39
|
|
|
35
40
|
try {
|
|
41
|
+
// Validate URI is not empty
|
|
42
|
+
if (uriString.empty()) {
|
|
43
|
+
errorCode = ERROR_INVALID_URI;
|
|
44
|
+
errorMessage = "Cannot get the size of an image for an empty URI";
|
|
45
|
+
errorCallback(errorCode, errorMessage);
|
|
46
|
+
co_return;
|
|
47
|
+
}
|
|
48
|
+
|
|
36
49
|
ReactImageSource source;
|
|
37
50
|
source.uri = uriString;
|
|
38
51
|
if (!headers.IsNull()) {
|
|
@@ -45,28 +58,38 @@ winrt::fire_and_forget GetImageSizeAsync(
|
|
|
45
58
|
winrt::hstring scheme{uri.SchemeName()};
|
|
46
59
|
bool needsDownload = (scheme == L"http") || (scheme == L"https");
|
|
47
60
|
bool inlineData = scheme == L"data";
|
|
61
|
+
bool isLocalFile = (scheme == L"file") || (scheme == L"ms-appx") || (scheme == L"ms-appdata");
|
|
48
62
|
|
|
49
63
|
winrt::IRandomAccessStream memoryStream;
|
|
50
|
-
if (needsDownload) {
|
|
64
|
+
if (needsDownload || isLocalFile) {
|
|
51
65
|
memoryStream = co_await GetImageStreamAsync(properties, source);
|
|
52
66
|
} else if (inlineData) {
|
|
53
67
|
memoryStream = co_await GetImageInlineDataAsync(source);
|
|
54
68
|
}
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
auto
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
69
|
+
|
|
70
|
+
if (memoryStream) {
|
|
71
|
+
auto result = wicBitmapSourceFromStream(memoryStream);
|
|
72
|
+
if (!std::get<std::shared_ptr<facebook::react::ImageErrorInfo>>(result)) {
|
|
73
|
+
auto imagingFactory = std::get<winrt::com_ptr<IWICImagingFactory>>(result);
|
|
74
|
+
auto wicBmpSource = std::get<winrt::com_ptr<IWICBitmapSource>>(result);
|
|
75
|
+
UINT width, height;
|
|
76
|
+
if (SUCCEEDED(wicBmpSource->GetSize(&width, &height))) {
|
|
77
|
+
successCallback(width, height);
|
|
78
|
+
succeeded = true;
|
|
79
|
+
}
|
|
63
80
|
}
|
|
64
81
|
}
|
|
65
|
-
} catch (winrt::hresult_error const &) {
|
|
82
|
+
} catch (winrt::hresult_error const &e) {
|
|
83
|
+
errorMessage = "Failed to get image size: " + Microsoft::Common::Unicode::Utf16ToUtf8(std::wstring(e.message())) +
|
|
84
|
+
" for URI: " + uriString;
|
|
66
85
|
}
|
|
67
86
|
|
|
68
|
-
if (!succeeded)
|
|
69
|
-
|
|
87
|
+
if (!succeeded) {
|
|
88
|
+
if (errorMessage.empty()) {
|
|
89
|
+
errorMessage = "Failed to get image size for URI: " + uriString;
|
|
90
|
+
}
|
|
91
|
+
errorCallback(errorCode, errorMessage);
|
|
92
|
+
}
|
|
70
93
|
|
|
71
94
|
co_return;
|
|
72
95
|
}
|
|
@@ -85,7 +108,9 @@ void ImageLoader::getSize(std::string uri, React::ReactPromise<std::vector<doubl
|
|
|
85
108
|
[result](double width, double height) noexcept {
|
|
86
109
|
result.Resolve(std::vector<double>{width, height});
|
|
87
110
|
},
|
|
88
|
-
[result]() noexcept {
|
|
111
|
+
[result](const char *errorCode, std::string errorMessage) noexcept {
|
|
112
|
+
result.Reject(React::ReactError{errorCode, errorMessage});
|
|
113
|
+
});
|
|
89
114
|
});
|
|
90
115
|
}
|
|
91
116
|
|
|
@@ -105,7 +130,9 @@ void ImageLoader::getSizeWithHeaders(
|
|
|
105
130
|
[result](double width, double height) noexcept {
|
|
106
131
|
result.Resolve(Microsoft::ReactNativeSpecs::ImageLoaderIOSSpec_getSizeWithHeaders_returnType{width, height});
|
|
107
132
|
},
|
|
108
|
-
[result]() noexcept {
|
|
133
|
+
[result](const char *errorCode, std::string errorMessage) noexcept {
|
|
134
|
+
result.Reject(React::ReactError{errorCode, errorMessage});
|
|
135
|
+
});
|
|
109
136
|
});
|
|
110
137
|
}
|
|
111
138
|
|
|
@@ -201,6 +201,11 @@ class HighResTimeStamp {
|
|
|
201
201
|
return HighResTimeStamp(chronoNow());
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
+
static HighResDuration unsafeOriginFromUnixTimeStamp() noexcept {
|
|
205
|
+
static auto origin = computeUnsafeOriginFromUnixTimeStamp();
|
|
206
|
+
return origin;
|
|
207
|
+
}
|
|
208
|
+
|
|
204
209
|
static constexpr HighResTimeStamp min() noexcept {
|
|
205
210
|
return HighResTimeStamp(std::chrono::steady_clock::time_point::min());
|
|
206
211
|
}
|
|
@@ -285,6 +290,13 @@ class HighResTimeStamp {
|
|
|
285
290
|
|
|
286
291
|
std::chrono::steady_clock::time_point chronoTimePoint_;
|
|
287
292
|
|
|
293
|
+
static HighResDuration computeUnsafeOriginFromUnixTimeStamp() noexcept {
|
|
294
|
+
auto systemNow = std::chrono::system_clock::now();
|
|
295
|
+
auto steadyNow = std::chrono::steady_clock::now();
|
|
296
|
+
return HighResDuration(
|
|
297
|
+
systemNow.time_since_epoch() - steadyNow.time_since_epoch());
|
|
298
|
+
}
|
|
299
|
+
|
|
288
300
|
#ifdef REACT_NATIVE_DEBUG
|
|
289
301
|
static std::function<std::chrono::steady_clock::time_point()>&
|
|
290
302
|
getTimeStampProvider() {
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
-->
|
|
11
11
|
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
12
12
|
<PropertyGroup>
|
|
13
|
-
<ReactNativeWindowsVersion>0.82.0-preview.
|
|
13
|
+
<ReactNativeWindowsVersion>0.82.0-preview.10</ReactNativeWindowsVersion>
|
|
14
14
|
<ReactNativeWindowsMajor>0</ReactNativeWindowsMajor>
|
|
15
15
|
<ReactNativeWindowsMinor>82</ReactNativeWindowsMinor>
|
|
16
16
|
<ReactNativeWindowsPatch>0</ReactNativeWindowsPatch>
|
|
17
17
|
<ReactNativeWindowsCanary>false</ReactNativeWindowsCanary>
|
|
18
|
-
<ReactNativeWindowsCommitId>
|
|
18
|
+
<ReactNativeWindowsCommitId>8dab2200781d9264a8a3ad08005d3a04b44e7c18</ReactNativeWindowsCommitId>
|
|
19
19
|
</PropertyGroup>
|
|
20
20
|
</Project>
|
|
@@ -24,8 +24,7 @@
|
|
|
24
24
|
4701; <!-- potentially uninitialized local variable used -->
|
|
25
25
|
4703; <!-- potentially uninitialized local pointer variable used -->
|
|
26
26
|
4789; <!-- destination of memory copy too small -->
|
|
27
|
-
4995
|
|
28
|
-
4996 <!-- deprecated function (including std::) -->
|
|
27
|
+
4995 <!-- function marked as pragma deprecated -->
|
|
29
28
|
</SDLMandatoryWarnings>
|
|
30
29
|
|
|
31
30
|
<!-- SDL RECOMMENDED WARNINGS (Strongly recommended to fix) -->
|