Slate.js - Balloon Toolbar Wrong Positioning

1.1k Views Asked by At

I'm trying to build an editor on slate.js

Copied most of the code from Slate official examples.

https://github.com/ianstormtaylor/slate/blob/master/examples/hovering-menu/index.js

Whenever i select a text, everything works perfectly. Positioning is smooth and works like a charm. But gets positioning wrong after select/deselect marking action.


Here is example gif. https://i.stack.imgur.com/OWvMU.gif

Thing i changed menu classnames and HOC hovering menu.

import React, { Component } from 'react';

function withHoverMenu (Menu) {
  return class extends React.Component {
    componentDidMount = () => {
      this.updateMenu()
    }
    componentDidUpdate = () => {
      this.updateMenu()
    }
    updateMenu = () => {
      const { value } = this.props
      const menu = this.menu
      if (!menu) return

      if (value.isBlurred || value.isEmpty) {
        menu.removeAttribute('style')
        return
      }

      const selection = window.getSelection()
      const range = selection.getRangeAt(0)
      const rect = range.getBoundingClientRect()
      console.log(rect)
      menu.style.opacity = 1
      menu.style.top = `${rect.top + window.scrollY - menu.offsetHeight}px`
      menu.style.left = `${rect.left + window.scrollX - menu.offsetWidth / 2 + rect.width / 2}px`
    }
    menuRef = (menu) => {
      this.menu = menu
    }
    render () {
      return <Menu className="slate-rte-balloon" menuRef={this.menuRef} {...this.props} />
    }
  }
}

export default withHoverMenu;

Editor part is slightly different but nothing much.

import Menu from './menu';
import withHoverMenu from './menu-balloon';

const HoveredMenu = withHoverMenu(Menu)

class SlateRTE extends Component {
  state = {
    value: Value.fromJSON(initialValue)
  }
  onChange = ({ value }) => {
    this.setState({ value })
  }
  render() {
    return (
      <div className="slate-rte">
        <HoveredMenu value={this.state.value} onChange={this.onChange} />
        <Editor placeholder="Enter some text..." renderMark={this.renderMark} value={this.state.value} onChange={this.onChange} />
      </div>
    );
  }
  renderMark = (props) => {
    const { children, mark } = props
    switch (mark.type) {
      case 'bold': return <strong>{children}</strong>
      case 'code': return <code>{children}</code>
      case 'italic': return <em>{children}</em>
      case 'underlined': return <u>{children}</u>
    }
  }
}
0

There are 0 best solutions below