1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
import { action, makeObservable, observable } from 'mobx';
import * as React from 'react';
import './AntimodeMenu.scss';
import { observer } from 'mobx-react';
import JsxParser from 'react-jsx-parser';
/**
* This is an abstract class that serves as the base for a PDF-style or Marquee-style
* menu. To use this class, look at PDFMenu.tsx or MarqueeOptionsMenu.tsx for an example.
*/
export abstract class ObservableReactComponent<T> extends React.Component<T, object> {
@observable _props: React.PropsWithChildren<T>;
constructor(props: React.PropsWithChildren<T>) {
super(props);
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) => 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])
.forEach(action(pkey => {
(this._props as {[key:string]: unknown})[pkey] = (this.props as {[key:string]: unknown})[pkey];
})); // prettier-ignore
}
}
class ObserverJsxParser1 extends JsxParser {
constructor(props: object) {
super(props);
observer(this as typeof JsxParser);
}
}
export const ObserverJsxParser = ObserverJsxParser1 as typeof JsxParser;
|