From bb0c93a94231d0af1a74f93e634c8b49dd04ee78 Mon Sep 17 00:00:00 2001
From: Hugo Bernier <hugoabernier@live.ca>
Date: Tue, 2 Apr 2019 22:09:19 -0400
Subject: [PATCH] Calculates richtext toolbar top. Fixes #265.

---
 package-lock.json                          | 28 +++++++++++----
 src/controls/richText/RichText.module.scss |  2 +-
 src/controls/richText/RichText.tsx         | 41 ++++++++++++++--------
 src/controls/richText/RichText.types.ts    |  2 ++
 4 files changed, 50 insertions(+), 23 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 73616509b..287ad6c21 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6711,12 +6711,14 @@
         "balanced-match": {
           "version": "1.0.0",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "brace-expansion": {
           "version": "1.1.11",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "balanced-match": "^1.0.0",
             "concat-map": "0.0.1"
@@ -6731,17 +6733,20 @@
         "code-point-at": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "concat-map": {
           "version": "0.0.1",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "console-control-strings": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "core-util-is": {
           "version": "1.0.2",
@@ -6858,7 +6863,8 @@
         "inherits": {
           "version": "2.0.3",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "ini": {
           "version": "1.3.5",
@@ -6870,6 +6876,7 @@
           "version": "1.0.0",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "number-is-nan": "^1.0.0"
           }
@@ -6884,6 +6891,7 @@
           "version": "3.0.4",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "brace-expansion": "^1.1.7"
           }
@@ -6891,12 +6899,14 @@
         "minimist": {
           "version": "0.0.8",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "minipass": {
           "version": "2.3.5",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "safe-buffer": "^5.1.2",
             "yallist": "^3.0.0"
@@ -6915,6 +6925,7 @@
           "version": "0.5.1",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "minimist": "0.0.8"
           }
@@ -6995,7 +7006,8 @@
         "number-is-nan": {
           "version": "1.0.1",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "object-assign": {
           "version": "4.1.1",
@@ -7007,6 +7019,7 @@
           "version": "1.4.0",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "wrappy": "1"
           }
@@ -7128,6 +7141,7 @@
           "version": "1.0.2",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "code-point-at": "^1.0.0",
             "is-fullwidth-code-point": "^1.0.0",
diff --git a/src/controls/richText/RichText.module.scss b/src/controls/richText/RichText.module.scss
index d2f0ab497..43509a801 100644
--- a/src/controls/richText/RichText.module.scss
+++ b/src/controls/richText/RichText.module.scss
@@ -230,7 +230,7 @@
   }
 
   .ql-active .ql-toolbar {
-    display: block;
+    display: inline-flex;
     position: absolute;
     top: -28px;
     opacity: 1;
diff --git a/src/controls/richText/RichText.tsx b/src/controls/richText/RichText.tsx
index ac4017afb..b64614e22 100644
--- a/src/controls/richText/RichText.tsx
+++ b/src/controls/richText/RichText.tsx
@@ -17,6 +17,8 @@ import { Icon } from 'office-ui-fabric-react/lib/Icon';
 import { elementContains } from 'office-ui-fabric-react/lib/Utilities';
 import * as telemetry from '../../common/telemetry';
 
+
+const TOOLBARPADDING: number = 28;
 /**
  * Creates a rich text editing control that mimics the out-of-the-box
  * SharePoint Rich Text control.
@@ -26,10 +28,10 @@ import * as telemetry from '../../common/telemetry';
  * - Tables aren't supported yet. I'll gladly add table formatting support if users request it.
  */
 export class RichText extends React.Component<IRichTextProps, IRichTextState> {
-  private quillElem: ReactQuill = undefined;
-  private wrapperRef = undefined;
-  private propertyPaneRef: RichTextPropertyPane = undefined;
-  private toolbarId = undefined;
+  private _quillElem: ReactQuill = undefined;
+  private _wrapperRef: HTMLDivElement = undefined;
+  private _propertyPaneRef: RichTextPropertyPane = undefined;
+  private _toolbarId = undefined;
 
   private ddStyleOpts = [{
     key: 0,
@@ -114,11 +116,12 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> {
       insertUrl: undefined,
       insertUrlText: undefined,
       selectedText: undefined,
-      selectedUrl: undefined
+      selectedUrl: undefined,
+      wrapperTop: 0
     };
 
     // Get a unique toolbar id
-    this.toolbarId = "toolbar_" + Guid.newGuid().toString();
+    this._toolbarId = "toolbar_" + Guid.newGuid().toString();
   }
 
   /**
@@ -130,6 +133,14 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> {
       document.addEventListener('click', this.handleClickOutside);
       document.addEventListener('focus', this.handleClickOutside);
     }
+
+    const clientRect: ClientRect = this._wrapperRef.getBoundingClientRect();
+    const parentClientRect: ClientRect = this._wrapperRef.parentElement.getBoundingClientRect();
+    const toolbarTop: number = clientRect.top - parentClientRect.top - TOOLBARPADDING;
+
+    this.setState({
+      wrapperTop: toolbarTop
+    });
   }
 
   /**
@@ -168,7 +179,7 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> {
    */
   public getEditor = (): Quill => {
     try {
-      return this.quillElem!.getEditor();
+      return this._quillElem!.getEditor();
     } catch (error) {
       return undefined;
     }
@@ -385,7 +396,7 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> {
     // Get a unique id for the toolbar
     const modules = {
       toolbar: {
-        container: "#" + this.toolbarId,
+        container: "#" + this._toolbarId,
         handlers: [
           "link" // disable the link handler so we can add our own
         ]
@@ -428,8 +439,8 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> {
     Quill.register(SizeClass, true);
 
     return (
-      <div ref={(ref) => this.wrapperRef = ref} className={`${styles.richtext && this.state.editing ? 'ql-active' : undefined} ${this.props.className}`}>
-        <div id={this.toolbarId}>
+      <div ref={(ref) => this._wrapperRef = ref} className={`${styles.richtext && this.state.editing ? 'ql-active' : undefined} ${this.props.className}`}>
+        <div id={this._toolbarId} style={{top:this.state.wrapperTop}}>
           {
             showStyles && (
               <Dropdown className={`${styles.headerDropDown} ${styles.toolbarDropDown}`}
@@ -706,8 +717,8 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> {
           formats: formats
         });
 
-        if (this.propertyPaneRef && this.state.morePaneVisible) {
-          this.propertyPaneRef.onChangeSelection(range, oldRange, source);
+        if (this._propertyPaneRef && this.state.morePaneVisible) {
+          this._propertyPaneRef.onChangeSelection(range, oldRange, source);
         }
       }
     } catch (error) {
@@ -761,7 +772,7 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> {
    * Keeps track of whether we clicked outside the element
    */
   private handleClickOutside = (event) => {
-    let outside: boolean = !elementContains(this.wrapperRef, event.target);
+    let outside: boolean = !elementContains(this._wrapperRef, event.target);
 
     // Did we click outside?
     if (outside) {
@@ -785,13 +796,13 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> {
    * Links to the quill reference
    */
   private linkQuill = (e: any) => {
-    this.quillElem = e;
+    this._quillElem = e;
   }
 
   /**
    * Links to the property pane element
    */
   private linkPropertyPane = (e: any) => {
-    this.propertyPaneRef = e;
+    this._propertyPaneRef = e;
   }
 }
diff --git a/src/controls/richText/RichText.types.ts b/src/controls/richText/RichText.types.ts
index 11a34cccb..2cff70581 100644
--- a/src/controls/richText/RichText.types.ts
+++ b/src/controls/richText/RichText.types.ts
@@ -135,4 +135,6 @@ export interface IRichTextState {
 
   /** The text */
   text: string;
+
+  wrapperTop: number;
 }