Skip to content
Snippets Groups Projects
TextHighlightingTool.js 4 KiB
Newer Older
import React, { useMemo, useState, useRef, useContext } from 'react';
chris's avatar
chris committed
import { isEmpty } from 'lodash';
import { useTranslation } from 'react-i18next';
import styled from 'styled-components';
chris's avatar
chris committed
import { grid, override } from '@pubsweet/ui-toolkit';
chris's avatar
chris committed
import {
  WaxContext,
  useOnClickOutside,
  MenuButton,
} from 'wax-prosemirror-core';

const Wrapper = styled.div`
  font-size: 0;
  position: relative;
  z-index: 2;
`;

const DropWrapper = styled.div`
chris's avatar
chris committed
  background: white;
  margin-top: ${grid(1)};
  position: absolute;
  top: 32px;
  width: max-content;
chris's avatar
chris committed

  ${override('Wax.HighlightToolWrapper')}
`;
const TextHighlightComponent = styled.div`
chris's avatar
chris committed
  background: white;
  border: 1px solid gray;
  display: flex;
  flex-direction: column;
`;
const Highlighter = styled.div`
chris's avatar
chris committed
  border: 1px solid gray;
  cursor: pointer;
  display: inline-grid;
chris's avatar
chris committed
  margin: 5px;
chris's avatar
chris committed
  min-width: 25px;
`;

const TextHighlightingTool = ({ view: { dispatch, state }, item }) => {
  const { icon, title, select } = item;
  const [isOpen, setIsOpen] = useState(false);
chris's avatar
chris committed
  const { t, i18n } = useTranslation();
chris's avatar
chris committed

chris's avatar
chris committed
  const highlightDropDownOptions = [
chris's avatar
chris committed
    { name: 'yellow', value: '#F3E95C' },
    { name: 'blue', value: '#7DE5DB' },
    { name: 'green', value: '#C0EB96' },
    { name: 'pink', value: '#F2C4D1' },
    { name: 'orange', value: '#FFB56B' },
    { name: 'red', value: '#FF8080' },
chris's avatar
chris committed
    { name: 'remove highlight', value: 'transparent' },
  ];

chris's avatar
chris committed
  const {
    activeViewId,
    activeView,
    pmViews: { main },
  } = useContext(WaxContext);

  const isEditable = main.props.editable(editable => {
chris's avatar
chris committed
    return editable;
  });

  useOnClickOutside(ref, () => setIsOpen(false));

  const renderList = () => {
    const lists = [];

chris's avatar
chris committed
    Object.keys(highlightDropDownOptions).forEach(key => {
chris's avatar
chris committed
        <Highlighter
chris's avatar
chris committed
          data-style={highlightDropDownOptions[key].value}
          key={uuidv4()}
chris's avatar
chris committed
          onMouseDown={e =>
            handleMouseDown(e, highlightDropDownOptions[key].value)
          }
          style={{ backgroundColor: highlightDropDownOptions[key].value }}
chris's avatar
chris committed
          title={highlightDropDownOptions[key].name}
chris's avatar
chris committed
        />,
chris's avatar
chris committed

chris's avatar
chris committed
  const handleMouseDown = (e, color) => {
chris's avatar
chris committed
    item.run(activeView.state, activeView.dispatch, color);
    if (color !== 'transparent') localStorage.setItem('lastBgColor', color);
chris's avatar
chris committed
  };
chris's avatar
chris committed

chris's avatar
chris committed
  const handleDblClk = () => {
chris's avatar
chris committed
    const color = localStorage.getItem('lastBgColor')
      ? localStorage.getItem('lastBgColor')
      : highlightDropDownOptions[0].value;

chris's avatar
chris committed
    item.run(state, dispatch, color);
chris's avatar
chris committed
  };
chris's avatar
chris committed
  let isDisabled = !select(state, activeViewId, activeView);
  if (!isEditable) isDisabled = true;
chris's avatar
chris committed
  const line = document.getElementById('trait');
  if (line)
    line.style.fill =
      localStorage.getItem('lastBgColor') !== null
        ? localStorage.getItem('lastBgColor')
        : highlightDropDownOptions[0].name;

  const MenuButtonComponent = useMemo(
    () => (
chris's avatar
chris committed
      <Wrapper onDoubleClick={handleDblClk} ref={ref}>
chris's avatar
chris committed
        <div disabled={isDisabled}>
chris's avatar
chris committed
          <MenuButton
            active={isOpen}
            disabled={isDisabled}
            iconName={icon}
            onMouseDown={() => {
              setIsOpen(!isOpen);
            }}
chris's avatar
chris committed
            title={
              !isEmpty(i18n) && i18n.exists(`Wax.Various.${title}`)
                ? t(`Wax.Various.${title}`)
                : title
            }
chris's avatar
chris committed
          />
chris's avatar
chris committed
            <TextHighlightComponent
chris's avatar
chris committed
              }}
chris's avatar
chris committed
              item={item}
              key={uuidv4()}
              view={(dispatch, state)}
chris's avatar
chris committed
            >
              {renderList()}
            </TextHighlightComponent>
chris's avatar
chris committed
    [isOpen, isDisabled, t(`Wax.Various.${title}`)],
  );

  return MenuButtonComponent;
};

export default TextHighlightingTool;