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 extends React.Component { @observable _props: React.PropsWithChildren; constructor(props: React.PropsWithChildren) { 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) => { 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): 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;