Pārlūkot izejas kodu

Render `Dropdown` list to document's body

This way the list is not cut off if it doesn't fit in the parent
container, i.e.: is inside a scrollable container.
Sergiu Miclea 8 gadi atpakaļ
vecāks
revīzija
267e19194a
3 mainītis faili ar 49 papildinājumiem un 4 dzēšanām
  1. 1 0
      package.json
  2. 22 4
      src/components/molecules/Dropdown/Dropdown.jsx
  3. 26 0
      yarn.lock

+ 1 - 0
package.json

@@ -61,6 +61,7 @@
     "babel-register": "^6.26.0",
     "copyfiles": "^1.2.0",
     "cross-env": "^5.0.5",
+    "document-offset": "^1.0.4",
     "express": "^4.16.1",
     "file-loader": "^1.1.5",
     "fs": "^0.0.1-security",

+ 22 - 4
src/components/molecules/Dropdown/Dropdown.jsx

@@ -15,6 +15,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import PropTypes from 'prop-types'
 import styled from 'styled-components'
+import ReactDOM from 'react-dom'
+import offset from 'document-offset'
 
 import { DropdownButton } from 'components'
 
@@ -37,7 +39,6 @@ const getWidth = props => {
 }
 const List = styled.div`
   position: absolute;
-  top: 45px;
   background: white;
   cursor: pointer;
   width: ${props => getWidth(props)}px;
@@ -118,6 +119,10 @@ class Dropdown extends React.Component {
     window.addEventListener('mousedown', this.handlePageClick, false)
   }
 
+  componentDidUpdate() {
+    this.updateListPosition()
+  }
+
   componentWillUnmount() {
     window.removeEventListener('mousedown', this.handlePageClick, false)
   }
@@ -132,6 +137,18 @@ class Dropdown extends React.Component {
     return (item[labelField] !== null && item[labelField] !== undefined && item[labelField].toString()) || item.toString()
   }
 
+  updateListPosition() {
+    if (!this.state.showDropdownList || !this.listRef || !this.buttonRef) {
+      return
+    }
+
+    let buttonHeight = this.buttonRef.offsetHeight
+    let tipHeight = 8
+    let buttonOffset = offset(this.buttonRef)
+    this.listRef.style.top = `${buttonOffset.top + buttonHeight + tipHeight}px`
+    this.listRef.style.left = `${buttonOffset.left}px`
+  }
+
   handlePageClick() {
     if (!this.itemMouseDown) {
       this.setState({ showDropdownList: false })
@@ -172,8 +189,8 @@ class Dropdown extends React.Component {
     }
 
     let selectedLabel = this.getLabel(this.props.selectedItem)
-    let list = (
-      <List {...this.props}>
+    let list = ReactDOM.createPortal((
+      <List {...this.props} innerRef={ref => { this.listRef = ref }}>
         <Tip primary={this.state.firstItemHover} />
         <ListItems>
           {this.props.items.map((item, i) => {
@@ -195,7 +212,7 @@ class Dropdown extends React.Component {
           })}
         </ListItems>
       </List>
-    )
+    ), document.body)
 
     return list
   }
@@ -217,6 +234,7 @@ class Dropdown extends React.Component {
       >
         <DropdownButton
           {...this.props}
+          innerRef={ref => { this.buttonRef = ref }}
           onMouseDown={() => { this.itemMouseDown = true }}
           onMouseUp={() => { this.itemMouseDown = false }}
           value={buttonValue()}

+ 26 - 0
yarn.lock

@@ -2520,6 +2520,14 @@ doctrine@^2.0.0:
     esutils "^2.0.2"
     isarray "^1.0.0"
 
+document-offset@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/document-offset/-/document-offset-1.0.4.tgz#7345b819cdfef2bb45c63ce13056416063b70085"
+  dependencies:
+    dom-support "*"
+    get-document "1.0.0"
+    within-element "0.1.0"
+
 dom-converter@~0.1:
   version "0.1.4"
   resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.1.4.tgz#a45ef5727b890c9bffe6d7c876e7b19cb0e17f3b"
@@ -2537,6 +2545,12 @@ dom-serializer@0, dom-serializer@~0.1.0:
     domelementtype "~1.1.1"
     entities "~1.1.1"
 
+dom-support@*:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/dom-support/-/dom-support-0.0.2.tgz#0e129764ffa5e203d8ab5839e2e92dc2ae14ef7c"
+  dependencies:
+    domready "*"
+
 dom-walk@^0.1.0:
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018"
@@ -2565,6 +2579,10 @@ domhandler@^2.3.0:
   dependencies:
     domelementtype "1"
 
+domready@*:
+  version "1.0.8"
+  resolved "https://registry.yarnpkg.com/domready/-/domready-1.0.8.tgz#91f252e597b65af77e745ae24dd0185d5e26d58c"
+
 domutils@1.1:
   version "1.1.6"
   resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485"
@@ -3405,6 +3423,10 @@ get-caller-file@^1.0.1:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
 
+get-document@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/get-document/-/get-document-1.0.0.tgz#4821bce66f1c24cb0331602be6cb6b12c4f01c4b"
+
 get-stream@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
@@ -7481,6 +7503,10 @@ window-size@0.1.0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
 
+within-element@0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/within-element/-/within-element-0.1.0.tgz#b610be314fb588bf21d7bd733906e437f30e2b95"
+
 wordwrap@0.0.2:
   version "0.0.2"
   resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"