-
Notifications
You must be signed in to change notification settings - Fork 294
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
Incorrect scroll direction on web with inverted
prop
#1351
Comments
inverted
propinverted
prop
I was able to hotpatch this one by disabling
but it would be great to include this upstream. Will do some more investigation |
After more testing, I found that although the first few items render with the above I'd love to help fix this if someone could point me in a relative direction! 😄 |
This is hard because there is no way to detect scroll direction on mac |
Maybe there is now a fix for safari devices: |
I patched this and created a .patch file with diff --git a/node_modules/@shopify/flash-list/dist/FlashList.js b/node_modules/@shopify/flash-list/dist/FlashList.js
index 4f33d6b..9e83a46 100644
--- a/node_modules/@shopify/flash-list/dist/FlashList.js
+++ b/node_modules/@shopify/flash-list/dist/FlashList.js
@@ -86,9 +86,7 @@ var FlashList = /** @class */ (function (_super) {
return (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement(PureComponentWrapper_1.PureComponentWrapper, { enabled: _this.isListLoaded || children.length > 0 || _this.isEmptyList, contentStyle: _this.props.contentContainerStyle, horizontal: _this.props.horizontal, header: _this.props.ListHeaderComponent, extraData: _this.state.extraData, headerStyle: _this.props.ListHeaderComponentStyle, inverted: _this.props.inverted, renderer: _this.header }),
react_1.default.createElement(AutoLayoutView_1.default, tslib_1.__assign({}, props, { onBlankAreaEvent: _this.props.onBlankArea, onLayout: _this.updateDistanceFromWindow, disableAutoLayout: _this.props.disableAutoLayout }), children),
- _this.isEmptyList
- ? _this.getValidComponent(_this.props.ListEmptyComponent)
- : null,
+ _this.isEmptyList ? (react_1.default.createElement(react_native_1.View, { style: _this.getTransform() }, _this.getValidComponent(_this.props.ListEmptyComponent))) : null,
react_1.default.createElement(PureComponentWrapper_1.PureComponentWrapper, { enabled: _this.isListLoaded || children.length > 0 || _this.isEmptyList, contentStyle: _this.props.contentContainerStyle, horizontal: _this.props.horizontal, header: _this.props.ListFooterComponent, extraData: _this.state.extraData, headerStyle: _this.props.ListFooterComponentStyle, inverted: _this.props.inverted, renderer: _this.footer }),
_this.getComponentForHeightMeasurement()));
};
@@ -359,6 +357,12 @@ var FlashList = /** @class */ (function (_super) {
if (((_a = this.props.data) === null || _a === void 0 ? void 0 : _a.length) === 0) {
this.raiseOnLoadEventIfNeeded();
}
+ if (react_native_1.Platform.OS === 'web' && this.props.inverted && this.rlvRef) {
+ var scrollElement = react_native_1.findNodeHandle(this.rlvRef);
+ if (scrollElement && scrollElement instanceof HTMLElement) {
+ PlatformHelper_1.PlatformConfig.setupInvertedWheelHandler(scrollElement);
+ }
+ }
};
FlashList.prototype.componentWillUnmount = function () {
this.viewabilityManager.dispose();
@@ -367,6 +371,12 @@ var FlashList = /** @class */ (function (_super) {
if (this.itemSizeWarningTimeoutId !== undefined) {
clearTimeout(this.itemSizeWarningTimeoutId);
}
+ if (react_native_1.Platform.OS === 'web' && this.props.inverted && this.rlvRef) {
+ var scrollElement = react_native_1.findNodeHandle(this.rlvRef);
+ if (scrollElement && scrollElement instanceof HTMLElement) {
+ PlatformHelper_1.PlatformConfig.teardownInvertedWheelHandler(scrollElement);
+ }
+ }
};
FlashList.prototype.render = function () {
this.isEmptyList = this.state.dataProvider.getSize() === 0;
diff --git a/node_modules/@shopify/flash-list/dist/native/config/PlatformHelper.web.js b/node_modules/@shopify/flash-list/dist/native/config/PlatformHelper.web.js
index 482e092..d235f7d 100644
--- a/node_modules/@shopify/flash-list/dist/native/config/PlatformHelper.web.js
+++ b/node_modules/@shopify/flash-list/dist/native/config/PlatformHelper.web.js
@@ -3,14 +3,56 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.getFooterContainer = exports.getItemAnimator = exports.getCellContainerPlatformStyles = exports.PlatformConfig = void 0;
var react_native_1 = require("react-native");
var DefaultJSItemAnimator_1 = require("recyclerlistview/dist/reactnative/platform/reactnative/itemanimators/defaultjsanimator/DefaultJSItemAnimator");
+var invertedWheelEventHandler = function(e) {
+ var node = e.currentTarget;
+
+ // For inverted lists, we want to scroll in the opposite direction
+ // So when deltaY is positive (scroll down), we want to scroll up
+ var deltaY = -e.deltaY;
+ var deltaX = -e.deltaX;
+
+ // Scroll by the inverted delta
+ node.scrollBy({
+ top: deltaY,
+ left: deltaX,
+ behavior: 'auto'
+ });
+
+ // Prevent the default scroll
+ e.preventDefault();
+};
var PlatformConfig = {
defaultDrawDistance: 2000,
- invertedTransformStyle: { transform: [{ scaleY: -1 }] },
- invertedTransformStyleHorizontal: { transform: [{ scaleX: -1 }] },
+ invertedTransformStyle: {
+ transform: [{ scaleY: -1 }],
+ transformOrigin: "center",
+ '& > div': {
+ transform: 'scaleY(-1)'
+ }
+ },
+ invertedTransformStyleHorizontal: {
+ transform: [{ scaleX: -1 }],
+ transformOrigin: "center",
+ '& > div': {
+ transform: 'scaleX(-1)'
+ }
+ },
+ setupInvertedWheelHandler: function(node) {
+ if (node) {
+ node.addEventListener('wheel', invertedWheelEventHandler, { passive: false });
+ }
+ },
+ teardownInvertedWheelHandler: function(node) {
+ if (node) {
+ node.removeEventListener('wheel', invertedWheelEventHandler);
+ }
+ }
};
exports.PlatformConfig = PlatformConfig;
var getCellContainerPlatformStyles = function (inverted, parentProps) {
- var transformValue = "translate(".concat(parentProps.x, "px,").concat(parentProps.y, "px)").concat(inverted ? " ".concat(parentProps.isHorizontal ? "scaleX" : "scaleY", "(-1)") : "");
+ var transformValue = "translate(".concat(parentProps.x, "px,").concat(parentProps.y, "px)").concat(
+ inverted ? " ".concat(parentProps.isHorizontal ? "scaleX" : "scaleY", "(-1)") : ""
+ );
return { transform: transformValue, WebkitTransform: transformValue };
};
exports.getCellContainerPlatformStyles = getCellContainerPlatformStyles;
diff --git a/node_modules/@shopify/flash-list/src/FlashList.tsx b/node_modules/@shopify/flash-list/src/FlashList.tsx
index fa851f0..a0aa784 100644
--- a/node_modules/@shopify/flash-list/src/FlashList.tsx
+++ b/node_modules/@shopify/flash-list/src/FlashList.tsx
@@ -6,6 +6,8 @@ import {
NativeSyntheticEvent,
StyleSheet,
NativeScrollEvent,
+ Platform,
+ findNodeHandle,
} from "react-native";
import {
BaseItemAnimator,
@@ -287,6 +289,12 @@ class FlashList<T> extends React.PureComponent<
if (this.props.data?.length === 0) {
this.raiseOnLoadEventIfNeeded();
}
+ if (Platform.OS === 'web' && this.props.inverted && this.rlvRef) {
+ const scrollElement = findNodeHandle(this.rlvRef) as unknown as HTMLElement;
+ if (scrollElement) {
+ PlatformConfig.setupInvertedWheelHandler(scrollElement);
+ }
+ }
}
componentWillUnmount() {
@@ -296,6 +304,12 @@ class FlashList<T> extends React.PureComponent<
if (this.itemSizeWarningTimeoutId !== undefined) {
clearTimeout(this.itemSizeWarningTimeoutId);
}
+ if (Platform.OS === 'web' && this.props.inverted && this.rlvRef) {
+ const scrollElement = findNodeHandle(this.rlvRef) as unknown as HTMLElement;
+ if (scrollElement) {
+ PlatformConfig.teardownInvertedWheelHandler(scrollElement);
+ }
+ }
}
render() {
@@ -479,9 +493,11 @@ class FlashList<T> extends React.PureComponent<
>
{children}
</AutoLayoutView>
- {this.isEmptyList
- ? this.getValidComponent(this.props.ListEmptyComponent)
- : null}
+ {this.isEmptyList ? (
+ <View style={this.getTransform()}>
+ {this.getValidComponent(this.props.ListEmptyComponent)}
+ </View>
+ ) : null}
<PureComponentWrapper
enabled={this.isListLoaded || children.length > 0 || this.isEmptyList}
contentStyle={this.props.contentContainerStyle}
@@ -574,7 +590,6 @@ class FlashList<T> extends React.PureComponent<
paddingLeft: this.contentStyle.paddingLeft,
}}
/>
-
<View
style={[this.props.ListHeaderComponentStyle, this.getTransform()]}
>
diff --git a/node_modules/@shopify/flash-list/src/native/config/PlatformHelper.ts b/node_modules/@shopify/flash-list/src/native/config/PlatformHelper.ts
index b5a46b8..a0dc086 100644
--- a/node_modules/@shopify/flash-list/src/native/config/PlatformHelper.ts
+++ b/node_modules/@shopify/flash-list/src/native/config/PlatformHelper.ts
@@ -5,6 +5,12 @@ const PlatformConfig = {
defaultDrawDistance: 250,
invertedTransformStyle: { transform: [{ scaleY: -1 }] },
invertedTransformStyleHorizontal: { transform: [{ scaleX: -1 }] },
+ setupInvertedWheelHandler: (node: HTMLElement) => {
+ //no-op
+ },
+ teardownInvertedWheelHandler: (node: HTMLElement) => {
+ //no-op
+ }
};
const getCellContainerPlatformStyles = (
inverted: boolean,
diff --git a/node_modules/@shopify/flash-list/src/native/config/PlatformHelper.web.ts b/node_modules/@shopify/flash-list/src/native/config/PlatformHelper.web.ts
index 950fd02..7b4b666 100644
--- a/node_modules/@shopify/flash-list/src/native/config/PlatformHelper.web.ts
+++ b/node_modules/@shopify/flash-list/src/native/config/PlatformHelper.web.ts
@@ -3,11 +3,53 @@ import { View } from "react-native";
import { BaseItemAnimator } from "recyclerlistview";
import { DefaultJSItemAnimator } from "recyclerlistview/dist/reactnative/platform/reactnative/itemanimators/defaultjsanimator/DefaultJSItemAnimator";
+const invertedWheelEventHandler = (e: WheelEvent) => {
+ const node = e.currentTarget as HTMLElement;
+
+ // For inverted lists, we want to scroll in the opposite direction
+ // So when deltaY is positive (scroll down), we want to scroll up
+ const deltaY = -e.deltaY;
+ const deltaX = -e.deltaX;
+
+ // Scroll by the inverted delta
+ node.scrollBy({
+ top: deltaY,
+ left: deltaX,
+ behavior: 'auto'
+ });
+
+ // Prevent the default scroll
+ e.preventDefault();
+};
+
const PlatformConfig = {
defaultDrawDistance: 2000,
- invertedTransformStyle: { transform: [{ scaleY: -1 }] },
- invertedTransformStyleHorizontal: { transform: [{ scaleX: -1 }] },
+ invertedTransformStyle: {
+ transform: [{ scaleY: -1 }],
+ transformOrigin: "center",
+ '& > div': {
+ transform: 'scaleY(-1)'
+ }
+ },
+ invertedTransformStyleHorizontal: {
+ transform: [{ scaleX: -1 }],
+ transformOrigin: "center",
+ '& > div': {
+ transform: 'scaleX(-1)'
+ }
+ },
+ setupInvertedWheelHandler: (node: HTMLElement) => {
+ if (node) {
+ node.addEventListener('wheel', invertedWheelEventHandler, { passive: false });
+ }
+ },
+ teardownInvertedWheelHandler: (node: HTMLElement) => {
+ if (node) {
+ node.removeEventListener('wheel', invertedWheelEventHandler);
+ }
+ }
};
+
const getCellContainerPlatformStyles = (
inverted: boolean,
parentProps: { x: number; y: number; isHorizontal?: boolean } |
Current behavior
The scroll direction is reverted. When using the scroll wheel going down moves the content up (were on every other webpage it goes down) and when using the scroll wheel going up moves the content down.
Expected behavior
The scroll direction is the same as other scroll bars on the web
I found a fix for generic divs https://codepen.io/anon/pen/pdrLEZ from https://stackoverflow.com/questions/18614301/keep-overflow-div-scrolled-to-bottom-unless-user-scrolls-up#comment80511192_44051405 but am having trouble refactoring
flash-list
to use itTo Reproduce
See example at https://codesandbox.io/p/sandbox/silly-taussig-gr5zfd
Platform:
Environment
1.7.1
I saw #558 but created a new ticket with a reproduction
The text was updated successfully, but these errors were encountered: