import _defineProperty from "@babel/runtime/helpers/defineProperty";
import ReactNodeView from '../react-node-view';

/**
 * A ReactNodeView that handles React components sensitive
 * to selection changes.
 *
 * If the selection changes, it will attempt to re-render the
 * React component. Otherwise it does nothing.
 *
 * You can subclass `viewShouldUpdate` to include other
 * props that your component might want to consider before
 * entering the React lifecycle. These are usually props you
 * compare in `shouldComponentUpdate`.
 *
 * An example:
 *
 * ```
 * viewShouldUpdate(nextNode) {
 *   if (nextNode.attrs !== this.node.attrs) {
 *     return true;
 *   }
 *
 *   return super.viewShouldUpdate(nextNode);
 * }```
 */

export class SelectionBasedNodeView extends ReactNodeView {
  constructor(node, view, getPos, portalProviderAPI, eventDispatcher, reactComponentProps,
  // Ignored via go/ees005
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  reactComponent, viewShouldUpdate, shouldRenderImmediatelyInPortal) {
    super(node, view, getPos, portalProviderAPI, eventDispatcher, reactComponentProps, reactComponent, viewShouldUpdate, shouldRenderImmediatelyInPortal);
    _defineProperty(this, "isSelectedNode", false);
    _defineProperty(this, "isNodeInsideSelection", (from, to, pos, posEnd) => {
      ({
        pos,
        posEnd
      } = this.getPositionsWithDefault(pos, posEnd));
      if (typeof pos !== 'number' || typeof posEnd !== 'number') {
        return false;
      }
      return from <= pos && to >= posEnd;
    });
    _defineProperty(this, "isSelectionInsideNode", (from, to, pos, posEnd) => {
      ({
        pos,
        posEnd
      } = this.getPositionsWithDefault(pos, posEnd));
      if (typeof pos !== 'number' || typeof posEnd !== 'number') {
        return false;
      }
      return pos < from && to < posEnd;
    });
    _defineProperty(this, "insideSelection", () => {
      const {
        selection: {
          from,
          to
        }
      } = this.view.state;
      return this.isSelectedNode || this.isSelectionInsideNode(from, to);
    });
    _defineProperty(this, "nodeInsideSelection", () => {
      const {
        selection
      } = this.view.state;
      const {
        from,
        to
      } = selection;
      return this.isSelectedNode || this.isNodeInsideSelection(from, to);
    });
    this.updatePos();
  }

  /**
   * Update current node's start and end positions.
   *
   * Prefer `this.pos` rather than getPos(), because calling getPos is
   * expensive, unless you know you're definitely going to render.
   */
  updatePos() {
    if (typeof this.getPos === 'boolean') {
      return;
    }
    const pos = this.getPos();
    if (typeof pos === 'number') {
      this.pos = pos;
      this.posEnd = pos + this.node.nodeSize;
    }
  }
  getPositionsWithDefault(pos, posEnd) {
    return {
      pos: typeof pos !== 'number' ? this.pos : pos,
      posEnd: typeof posEnd !== 'number' ? this.posEnd : posEnd
    };
  }
  selectNode() {
    this.isSelectedNode = true;
    this.update(this.node, this.decorations);
  }
  deselectNode() {
    this.isSelectedNode = false;
    this.update(this.node, this.decorations);
  }
}