client/src/components/SlateEditor/CategoryButton.js
changeset 173 0e6703cd0968
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/components/SlateEditor/CategoryButton.js	Fri Nov 16 11:19:13 2018 +0100
@@ -0,0 +1,82 @@
+import React from 'react';
+import * as R from 'ramda';
+import { PortalWithState } from 'react-portal';
+import CategoriesTooltip from './CategoriesTooltip';
+import { defaultAnnotationsCategories } from '../../constants';
+
+/**
+ * Render a category toolbar button.
+ *
+ * @param {String} type
+ * @param {String} icon
+ * @return {Element}
+ */
+export default class CategoryButton extends React.Component {
+
+  constructor(props) {
+    super(props);
+
+    this.hoveringMenuRef = React.createRef();
+  }
+
+  get hoveringMenu() {
+    if(this.hoveringMenuRef) {
+      return this.hoveringMenuRef.current;
+    }
+    return null;
+  }
+
+  updateMenu = () => {
+
+    const hoveringMenu = this.hoveringMenu;
+
+    if (!hoveringMenu) return
+
+    const selection = window.getSelection()
+
+    if (selection.isCollapsed) {
+      return
+    }
+
+    const range = selection.getRangeAt(0)
+    const rect = range.getBoundingClientRect()
+
+    hoveringMenu.style.opacity = 1
+    hoveringMenu.style.top = `${rect.top + rect.height + window.scrollY + hoveringMenu.offsetHeight}px`
+    hoveringMenu.style.left = `${rect.left + window.scrollX - hoveringMenu.offsetWidth / 2 + rect.width / 2}px`
+  }
+
+  render = () => {
+    const isActive = this.props.isActive;
+    const onClickCategoryButton = this.props.onClickCategoryButton;
+    const onCategoryClick = this.props.onCategoryClick;
+    const annotationCategories = this.props.annotationCategories;
+
+    const markActivation = "button sticky-top" + ((!isActive)?" text-primary":" text-dark");
+
+    return (
+      <PortalWithState
+        // closeOnOutsideClick
+        closeOnEsc
+        onOpen={this.updateMenu}
+      >
+        {({ openPortal, closePortal, isOpen, portal }) => {
+          const onMouseDown = R.partial(onClickCategoryButton, [openPortal, closePortal, isOpen]);
+          const onCategoryClickHandler = R.partial(onCategoryClick, [closePortal,]);
+          return (
+            <React.Fragment>
+              <span className={markActivation} onMouseDown={onMouseDown} data-active={isActive}>
+                <span className="material-icons">label</span>
+              </span>
+              {portal(
+                <div className="hovering-menu" ref={this.hoveringMenuRef}>
+                  <CategoriesTooltip categories={annotationCategories || defaultAnnotationsCategories} onCategoryClick={onCategoryClickHandler} />
+                </div>
+              )}
+            </React.Fragment>
+          )}
+        }
+      </PortalWithState>
+    )
+  }
+}