Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

VirtualizedList: incorrect direction when inverted and keyboard scrolling #2233

Closed
staltz opened this issue Feb 23, 2022 · 9 comments
Closed
Labels
bug: react-native Bug associated with upstream React Native vendor code project:react-native-web Issue associated with react-native-web resolution: wontfix

Comments

@staltz
Copy link
Contributor

staltz commented Feb 23, 2022

All the same symptoms as issue #995, except this time keyboard buttons such as ⬆️ would scroll down, ⬇️ would scroll up, as well as PageUp would scroll one page down, and PageDown would scroll one page up.

@necolas
Copy link
Owner

necolas commented Feb 24, 2022

Yeah. The scale:-1 inversion hack used by VirtualizedList just isn't the way to go

@necolas necolas added the bug: react-native Bug associated with upstream React Native vendor code label Feb 24, 2022
@necolas
Copy link
Owner

necolas commented Feb 25, 2022

This PR by @azimgd removes the transform and fixes another issue: copy-paste text order #2151

@necolas
Copy link
Owner

necolas commented Feb 25, 2022

@DavidRieman is also working on fixing visualization #2236.

Perhaps the 3 of you can work together to get VirtualizedList working for your needs? And if there are examples and unit tests to include in this repo that would also be a great help to limit regressions

@DavidRieman
Copy link
Contributor

DavidRieman commented Feb 25, 2022

Ok I've added commentary to #2236. I don't know if the scroll direction issues you are talking about are react-native-web only, or if they reproduce in react-native with a device with keyboard (like iPad with Magic Keyboard or a Samsung DeX device or whatever with a keyboard paired) - but if it's RNW-only issue it would be good to test out whether it continues to be a problem from my code. I'll report back when things are committed and pushed, so you would be able to test that against DavidRieman/react-native-web main branch at that time.

@DavidRieman
Copy link
Contributor

Ok the https://github.com/davidrieman/react-native-web/ main branch now has testable upgraded VirtualizedList including SectionList and FlatList too.

@staltz
Copy link
Contributor Author

staltz commented Mar 1, 2022

if they reproduce in react-native with a device with keyboard (like iPad with Magic Keyboard or a Samsung DeX device or whatever with a keyboard paired)

I tested on an iPad, and it seems like iOS doesn't support scrolling with the keyboard arrows.

@staltz
Copy link
Contributor Author

staltz commented Mar 1, 2022

To anyone out there looking for a desperate quick fix to this issue, I ended up solving it with a couple hacks, see this commit: staltz/manyverse@4e0cfd6

The gist is that you should:

  1. Make sure to force focus on one child in the inverted list, e.g. UIManager.focus(viewRef.current)
  2. Patch react-native-web to listen to keydown events and mimic scroll behavior (see below)
CLICK HERE TO SEE THE PATCH FILE
diff --git a/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js b/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js
index b15746f..73fad96 100644
--- a/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js
+++ b/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js
@@ -650,6 +650,8 @@ var VirtualizedList = /*#__PURE__*/function (_React$PureComponent) {
             // we will trust the initialScrollIndex suggestion.
             if (!_this.props.initialScrollIndex || _this._scrollMetrics.offset) {
               newState = computeWindowedRenderLimits(_this.props, state, _this._getFrameMetricsApprox, _this._scrollMetrics);
+              // See https://github.com/necolas/react-native-web/issues/1579
+              newState.first = 0;
             }
           }
         } else {
@@ -868,7 +870,66 @@ var VirtualizedList = /*#__PURE__*/function (_React$PureComponent) {
     var _this2 = this;
 
     if (this._scrollRef && this._scrollRef.getScrollableNode) {
-      this._scrollRef.getScrollableNode().addEventListener('wheel', this.invertedWheelEventHandler);
+      const node = this._scrollRef.getScrollableNode();
+      node.addEventListener('wheel', this.invertedWheelEventHandler);
+      let lastKeyDown = 0;
+      node.addEventListener('keydown', (ev) => {
+        const DELTA = 40;
+        const PAGE = node.clientHeight * 0.9;
+        const TOTAL = node.scrollHeight;
+        const behavior = (Date.now() - lastKeyDown) > 60 ? 'smooth' : 'instant';
+        lastKeyDown = Date.now();
+        if (ev.code === 'ArrowDown') {
+          node.scroll({
+            top: node.scrollTop + (this.props.inverted ? -DELTA : +DELTA),
+            left: 0,
+            behavior
+          });
+        } else if (ev.code === 'ArrowUp') {
+          node.scroll({
+            top: node.scrollTop + (this.props.inverted ? +DELTA : -DELTA),
+            left: 0,
+            behavior
+          });
+        } else if (ev.code === 'PageDown') {
+          node.scroll({
+            top: node.scrollTop + (this.props.inverted ? -PAGE : +PAGE),
+            left: 0,
+            behavior
+          });
+        } else if (ev.code === 'PageUp') {
+          node.scroll({
+            top: node.scrollTop + (this.props.inverted ? +PAGE : -PAGE),
+            left: 0,
+            behavior
+          });
+        } else if (ev.code === 'Space' && !ev.shiftKey) {
+          node.scroll({
+            top: node.scrollTop + (this.props.inverted ? -PAGE : +PAGE),
+            left: 0,
+            behavior
+          });
+        } else if (ev.code === 'Space' && ev.shiftKey) {
+          node.scroll({
+            top: node.scrollTop + (this.props.inverted ? +PAGE : -PAGE),
+            left: 0,
+            behavior
+          });
+        } else if (ev.code === 'End') {
+          node.scroll({
+            top: this.props.inverted ? 0 : TOTAL,
+            left: 0,
+            behavior: 'smooth'
+          });
+        } else if (ev.code === 'Home') {
+          node.scroll({
+            top: this.props.inverted ? TOTAL : 0,
+            left: 0,
+            behavior: 'smooth'
+          });
+        }
+        ev.preventDefault();
+      });
     } else {
       setTimeout(function () {
         return _this2.setupWebWheelHandler();

@shrehatiwari
Copy link

May I solve this VirtualizedList issue stating incorrect direction when inverted and keyboard scrolling ?

@necolas
Copy link
Owner

necolas commented Mar 27, 2023

Closing this as there's an issue in RN to move Animated, VirtualizedList, and FlatList to packages that get published to npm facebook/react-native#35263.

This is the issue that is implicitly tracking problems with using transforms for inversion facebook/react-native#30383

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug: react-native Bug associated with upstream React Native vendor code project:react-native-web Issue associated with react-native-web resolution: wontfix
Projects
None yet
Development

No branches or pull requests

4 participants