Skip to content
Snippets Groups Projects
CommentBubbleComponent.js 2.13 KiB
Newer Older
chris's avatar
chris committed
/* eslint react/prop-types: 0 */
import React, { useLayoutEffect, useContext } from 'react';
import { WaxContext } from 'wax-prosemirror-core';
chris's avatar
chris committed
import CommentBubble from './CommentBubble';
chris's avatar
chris committed
import { CommentDecorationPluginKey } from '../../../plugins/CommentDecorationPlugin';
chris's avatar
chris committed

chris's avatar
chris committed
const CommentBubbleComponent = ({ setPosition, position, group }) => {
  const {
    activeView,
    activeViewId,
    options: { comments },
  } = useContext(WaxContext);

  const { state, dispatch } = activeView;
chris's avatar
chris committed

  useLayoutEffect(() => {
    const WaxSurface = activeView.dom.getBoundingClientRect();
    const { selection } = activeView.state;
    const { from, to } = selection;
    const start = activeView.coordsAtPos(from);
    const end = activeView.coordsAtPos(to);
    const difference = end.top - start.top;
chris's avatar
chris committed
    const left = WaxSurface.width - 20;
chris's avatar
chris committed
    const top = end.top - WaxSurface.top - difference / 2 - 5;
    setPosition({ ...position, left, top });
  }, [position.left]);
  const createComment = event => {
chris's avatar
chris committed
    event.preventDefault();
chris's avatar
chris committed
    const { selection } = state;
chris's avatar
chris committed

chris's avatar
chris committed
    dispatch(
chris's avatar
chris committed
      state.tr.setMeta(CommentDecorationPluginKey, {
chris's avatar
chris committed
        type: 'addComment',
chris's avatar
chris committed
        from: selection.from,
        to: selection.to,
        data: {
chris's avatar
chris committed
          type: 'comment',
          conversation: [],
chris's avatar
chris committed
          title: '',
chris's avatar
chris committed
          viewId: activeViewId,
chris's avatar
chris committed
      }),
    );
chris's avatar
chris committed
    dispatch(state.tr);
chris's avatar
chris committed
  const isCommentAllowed = () => {
    let allowed = true;
    state.doc.nodesBetween(
      state.selection.$from.pos,
      state.selection.$to.pos,
chris's avatar
chris committed
      node => {
chris's avatar
chris committed
        if (
          node.type.name === 'math_display' ||
chris's avatar
chris committed
          node.type.name === 'math_inline' ||
          node.type.name === 'image'
chris's avatar
chris committed
        ) {
          allowed = false;
        }
      },
    );
chris's avatar
chris committed

      comments.find(
        comm =>
          comm.from === state.selection.from && comm.to === state.selection.to,
      )
    ) {
      allowed = false;
chris's avatar
chris committed
    return allowed;
chris's avatar
chris committed
  };

  return (
chris's avatar
chris committed
    isCommentAllowed() && (
chris's avatar
chris committed
      <CommentBubble
        onClick={event => {
chris's avatar
chris committed
          createComment(event);
        }}
chris's avatar
chris committed
      />
chris's avatar
chris committed
    )
chris's avatar
chris committed

export default CommentBubbleComponent;