Skip to content

Commit d648eba

Browse files
[Fabric] Implementation of scrollEvent Handling and scrollEnabled,OnScroll prop for TextInput (#14946)
* [Fabric] Implementation of scrollEvent Handling and OnScroll prop for TextInput * Yarn Change * Removed the unwanted change * Review Changes * Changed Change file * Added another check to trigger scrollEvent * Lint Fixes * Review Changes * Removed event emission for keyup and keydown added tests * Update snapshot
1 parent e946b7c commit d648eba

File tree

8 files changed

+87
-2
lines changed

8 files changed

+87
-2
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "prerelease",
3+
"comment": "[Fabric] Implementation of scrollEvent Handling and scrollEnabled,OnScroll prop for TextInput",
4+
"packageName": "react-native-windows",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

packages/@react-native-windows/tester/src/js/examples/TextInput/TextInputExample.windows.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,13 @@ const examples: Array<RNTesterModuleExample> = [
486486
<ExampleTextInput
487487
autoCorrect={true}
488488
multiline={true}
489+
onScroll={event => {
490+
console.log(
491+
`onScroll event: ${JSON.stringify(
492+
event.nativeEvent.contentOffset,
493+
)}`,
494+
);
495+
}}
489496
style={[
490497
styles.multiline,
491498
{color: 'blue'},

packages/e2e-test-app-fabric/test/__snapshots__/snapshotPages.test.js.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80443,6 +80443,7 @@ exports[`snapshotAllPages TextInput 32`] = `
8044380443
<TextInput
8044480444
autoCorrect={true}
8044580445
multiline={true}
80446+
onScroll={[Function]}
8044680447
style={
8044780448
[
8044880449
{

packages/playground/Samples/textinput.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,22 @@ export default class Bootstrap extends React.Component<{}, any> {
302302
}
303303
autoFocus={false}
304304
/>
305+
<TextInput
306+
style={[
307+
styles.input,
308+
{height: 50, borderColor: '#bd1cddff', borderWidth: 2},
309+
]}
310+
multiline={true}
311+
placeholder="onScroll..."
312+
scrollEnabled={true}
313+
onScroll={event => {
314+
Alert.alert(
315+
`onScroll event: ${JSON.stringify(
316+
event.nativeEvent.contentOffset,
317+
)}`,
318+
);
319+
}}
320+
/>
305321

306322
<KeyboardAvoidingView
307323
style={styles.container}

vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,29 @@ void WindowsTextInputComponentView::OnPointerMoved(
811811
DVASPECT_CONTENT, -1, nullptr, nullptr, nullptr, nullptr, nullptr, ptContainer.x, ptContainer.y);
812812
}
813813

814+
void WindowsTextInputComponentView::OnPointerWheelChanged(
815+
const winrt::Microsoft::ReactNative::Composition::Input::PointerRoutedEventArgs &args) noexcept {
816+
if (windowsTextInputProps().scrollEnabled && windowsTextInputProps().multiline) {
817+
auto pointerPointProperties = args.GetCurrentPoint(-1).Properties();
818+
819+
auto delta = static_cast<float>(pointerPointProperties.MouseWheelDelta());
820+
821+
if (m_textServices && !pointerPointProperties.IsHorizontalMouseWheel()) {
822+
// Vertical scrolling
823+
if (delta > 0) {
824+
m_textServices->TxSendMessage(WM_VSCROLL, SB_LINEUP, 0, nullptr);
825+
} else {
826+
m_textServices->TxSendMessage(WM_VSCROLL, SB_LINEDOWN, 0, nullptr);
827+
}
828+
args.Handled(true);
829+
}
830+
// Emit the onScroll event
831+
EmitOnScrollEvent();
832+
833+
// We don't support horizontal scrolling yet cause it is not implemented in Android/IOS
834+
}
835+
Super::OnPointerWheelChanged(args);
836+
}
814837
void WindowsTextInputComponentView::OnKeyDown(
815838
const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept {
816839
// Do not forward tab keys into the TextInput, since we want that to do the tab loop instead. This aligns with WinUI
@@ -836,7 +859,6 @@ void WindowsTextInputComponentView::OnKeyDown(
836859
args.Handled(true);
837860
}
838861
}
839-
840862
Super::OnKeyDown(args);
841863
}
842864

@@ -866,7 +888,6 @@ void WindowsTextInputComponentView::OnKeyUp(
866888
args.Handled(true);
867889
}
868890
}
869-
870891
Super::OnKeyUp(args);
871892
}
872893

@@ -1327,6 +1348,22 @@ void WindowsTextInputComponentView::OnTextUpdated() noexcept {
13271348
}
13281349
}
13291350

1351+
void WindowsTextInputComponentView::EmitOnScrollEvent() noexcept {
1352+
if (!windowsTextInputProps().scrollEnabled || !m_eventEmitter || m_comingFromJS || !m_textServices) {
1353+
return;
1354+
}
1355+
LONG hMin, hMax, hPos, hPage;
1356+
LONG vMin, vMax, vPos, vPage;
1357+
BOOL hEnabled, vEnabled;
1358+
winrt::check_hresult(m_textServices->TxGetHScroll(&hMin, &hMax, &hPos, &hPage, &hEnabled));
1359+
winrt::check_hresult(m_textServices->TxGetVScroll(&vMin, &vMax, &vPos, &vPage, &vEnabled));
1360+
facebook::react::Point offset;
1361+
offset.x = static_cast<float>(hPos);
1362+
offset.y = static_cast<float>(vPos);
1363+
auto emitter = std::static_pointer_cast<const facebook::react::WindowsTextInputEventEmitter>(m_eventEmitter);
1364+
emitter->onScroll(offset);
1365+
}
1366+
13301367
void WindowsTextInputComponentView::OnSelectionChanged(LONG start, LONG end) noexcept {
13311368
if (m_eventEmitter && !m_comingFromState /* && !m_comingFromJS ?? */) {
13321369
auto emitter = std::static_pointer_cast<const facebook::react::WindowsTextInputEventEmitter>(m_eventEmitter);

vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ struct WindowsTextInputComponentView
6060
const winrt::Microsoft::ReactNative::Composition::Input::PointerRoutedEventArgs &args) noexcept override;
6161
void OnPointerMoved(
6262
const winrt::Microsoft::ReactNative::Composition::Input::PointerRoutedEventArgs &args) noexcept override;
63+
void OnPointerWheelChanged(
64+
const winrt::Microsoft::ReactNative::Composition::Input::PointerRoutedEventArgs &args) noexcept override;
6365

6466
void OnKeyDown(const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept override;
6567
void OnKeyUp(const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept override;
@@ -97,6 +99,7 @@ struct WindowsTextInputComponentView
9799
void UpdateParaFormat() noexcept;
98100
void UpdateText(const std::string &str) noexcept;
99101
void OnTextUpdated() noexcept;
102+
void EmitOnScrollEvent() noexcept;
100103
void OnSelectionChanged(LONG start, LONG end) noexcept;
101104
std::pair<float, float> GetContentSize() const noexcept;
102105
std::string GetTextFromRichEdit() const noexcept;

vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputEventEmitter.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,17 @@ void WindowsTextInputEventEmitter::onPressOut(GestureResponderEvent event) const
109109
});
110110
}
111111

112+
void WindowsTextInputEventEmitter::onScroll(facebook::react::Point offset) const {
113+
dispatchEvent("textInputScroll", [offset = std::move(offset)](jsi::Runtime &runtime) {
114+
auto payload = jsi::Object(runtime);
115+
{
116+
auto contentOffsetObj = jsi::Object(runtime);
117+
contentOffsetObj.setProperty(runtime, "x", offset.x);
118+
contentOffsetObj.setProperty(runtime, "y", offset.y);
119+
payload.setProperty(runtime, "contentOffset", contentOffsetObj);
120+
}
121+
return payload;
122+
});
123+
}
124+
112125
} // namespace facebook::react

vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputEventEmitter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class WindowsTextInputEventEmitter : public ViewEventEmitter {
5555
void onPressIn(GestureResponderEvent event) const override;
5656
void onEndEditing(OnEndEditing value) const;
5757
void onPressOut(GestureResponderEvent event) const override;
58+
void onScroll(facebook::react::Point offset) const;
5859
};
5960

6061
} // namespace facebook::react

0 commit comments

Comments
 (0)