aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/ObservableReactComponent.tsx
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2025-05-05 12:37:09 -0400
committerbobzel <zzzman@gmail.com>2025-05-05 12:37:09 -0400
commit3a733aa0fd24517e83649824dec0fc8bcc0bde43 (patch)
treeac01848cdab3b83582c0b7ab6f3d2b1c8187a24f /src/client/views/ObservableReactComponent.tsx
parente058d227ccbce47c86b0fa558adb01dfccaf4d60 (diff)
parentd4659e2bd3ddb947683948083232c26fb1227f39 (diff)
Merge branch 'master' into joanne-tutorialagent
Diffstat (limited to 'src/client/views/ObservableReactComponent.tsx')
-rw-r--r--src/client/views/ObservableReactComponent.tsx27
1 files changed, 27 insertions, 0 deletions
diff --git a/src/client/views/ObservableReactComponent.tsx b/src/client/views/ObservableReactComponent.tsx
index bb7a07f0e..2290516dc 100644
--- a/src/client/views/ObservableReactComponent.tsx
+++ b/src/client/views/ObservableReactComponent.tsx
@@ -15,6 +15,33 @@ export abstract class ObservableReactComponent<T> extends React.Component<T, obj
this._props = props;
makeObservable(this);
}
+ __passiveWheel: HTMLElement | null = null;
+ _isContentActive: () => boolean | undefined = () => false;
+
+ /**
+ * default method to stop wheel events from bubbling up to parent components.
+ * @param e
+ */
+ onPassiveWheel = (e: WheelEvent) => {
+ if (this._isContentActive?.()) e.stopPropagation();
+ };
+
+ /**
+ * This fixes the problem where a component uses wheel events to scroll, but is nested inside another component that
+ * can also scroll. In that case, the wheel event will bubble up to the parent component and cause it to scroll in addition.
+ * This is based on the native HTML5 behavior where wheel events are passive by default, meaning that they do not prevent the default action of scrolling.
+ * This method should be called from a ref={} property on or above the component that uses wheel events to scroll.
+ * @param ele HTMLELement containing the component that will scroll
+ * @param isContentActive function determining if the component is active and should handle the wheel event.
+ * @param onPassiveWheel an optional function to call to handle the wheel event (and block its propagation. If omitted, the event won't propagate.
+ */
+ fixWheelEvents = (ele: HTMLElement | null, isContentActive: () => boolean | undefined, onPassiveWheel?: (e: WheelEvent) => void) => {
+ this._isContentActive = isContentActive;
+ this.__passiveWheel?.removeEventListener('wheel', onPassiveWheel ?? this.onPassiveWheel);
+ this.__passiveWheel = ele;
+ ele?.addEventListener('wheel', onPassiveWheel ?? this.onPassiveWheel, { passive: false });
+ };
+
componentDidUpdate(prevProps: Readonly<T>): void {
Object.keys(prevProps)
.filter(pkey => (prevProps as {[key:string]: unknown})[pkey] !== (this.props as {[key:string]: unknown})[pkey])