gilbarbara / react-floater

Advanced tooltips for React
https://codesandbox.io/s/github/gilbarbara/react-floater/tree/main/demo
MIT License
212 stars 36 forks source link

decouple Floater and Popper using some kind of pub-sub #45

Closed gitowiec closed 5 years ago

gitowiec commented 5 years ago

This code

initPopper(target = this.target) {
    const { positionWrapper } = this.state;
    const { disableFlip, getPopper, hideArrow, offset, placement, wrapperOptions } = this.props;
    const flipBehavior = placement === 'top' || placement === 'bottom' ? 'flip' : [
      'right',
      'bottom-end',
      'top-end',
      'left',
      'top-start',
      'bottom-start',
    ];

    /* istanbul ignore else */
    if (placement === 'center') {
      this.setState({ status: STATUS.IDLE });
    }
    else if (target && this.floaterRef) {
      new Popper(target, this.floaterRef, {
        placement,
        modifiers: {
          arrow: {
            enabled: !hideArrow,
            element: this.arrowRef,
            ...this.options.arrow,
          },
          computeStyle: this.options.computeStyle,
          flip: {
            enabled: !disableFlip,
            behavior: flipBehavior,
            ...this.options.flip,
          },
          keepTogether: this.options.keepTogether,
          hide: this.options.hide,
          inner: this.options.inner,
          offset: {
            offset: `0, ${offset}px`,
            ...this.options.offset,
          },
          preventOverflow: this.options.preventOverflow,
          shift: this.options.shift,
        },
        onCreate: (data) => {
          this.popper = data;

          getPopper(data, 'floater');

          this.setState({
            currentPlacement: data.placement,
            status: STATUS.IDLE,
          });

          if (placement !== data.placement) {
            setTimeout(() => {
              data.instance.update();
            }, 1);
          }
        },
        onUpdate: (data) => {
          this.popper = data;
          const { currentPlacement } = this.state;

          if (data.placement !== currentPlacement) {
            this.setState({ currentPlacement: data.placement });
          }
        },
      });
    }

    if (positionWrapper) {
      const wrapperOffset = !is.undefined(wrapperOptions.offset) ? wrapperOptions.offset : 0;

      new Popper(this.target, this.wrapperRef, {
        placement: wrapperOptions.placement || placement,
        modifiers: {
          arrow: {
            enabled: false,
          },
          offset: {
            offset: `0, ${wrapperOffset}px`,
          },
          flip: {
            enabled: false,
          },
        },
        onCreate: (data) => {
          this.wrapperPopper = data;
          this.setState({ statusWrapper: STATUS.IDLE });

          getPopper(data, 'wrapper');

          if (placement !== data.placement) {
            setTimeout(() => {
              data.instance.update();
            }, 1);
          }
        },
      });
    }
  }

particulary calling this.setState inside "lifecycle" of Popper gives this error: https://github.com/gilbarbara/react-joyride/issues/373 The error seems to creep out if Floater is already unmounted and Popper wants to set its state... voila! :D

gilbarbara commented 5 years ago

PR welcome