├── .gitignore ├── _config.yml ├── .editorconfig ├── docs ├── demo.module.js ├── demo.css └── index.html ├── bower.json ├── LICENSE ├── README.md ├── package.json ├── src ├── vue-popper.scss └── VuePopper.vue └── dist ├── vue-popper.css ├── vue-popper.js └── vue-popper+popperjs.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root=true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | indent_style = space 7 | indent_size = 2 8 | 9 | [*.{js, scss, css, vue}] 10 | charset = utf-8 11 | spaces = 2 12 | 13 | [*.json] 14 | indent_size = 4 15 | -------------------------------------------------------------------------------- /docs/demo.module.js: -------------------------------------------------------------------------------- 1 | const 2 | Vue = require('vue'), 3 | VuePopper = require('../dist/vue-popper'); 4 | 5 | new Vue({ 6 | el: '#app', 7 | 8 | components: { 9 | 'popper': VuePopper 10 | }, 11 | 12 | data: { 13 | showPopper1: true, 14 | showPopper2: false, 15 | showPopper3: false, 16 | showPopper4: false 17 | }, 18 | 19 | methods: { 20 | hideSecondPopover() { 21 | this.showSecondPopover = false; 22 | } 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-popper-component", 3 | "homepage": "https://github.com/antongorodezkiy/vue-popper-component", 4 | "authors": [ 5 | "antongorodezkiy " 6 | ], 7 | "version": "0.1.0", 8 | "dependencies": { 9 | "vue": "1.*", 10 | "popper.js": "1.*" 11 | }, 12 | "description": "Vue.js component for Popper.js", 13 | "main": "dist/vue-popper.js", 14 | "keywords": [ 15 | "vue", 16 | "popperjs", 17 | "component" 18 | ], 19 | "license": "MIT" 20 | } 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Eduardo K 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | vue-popper-component 2 | ============== 3 | 4 | Simple Vue.js component for [Popper.js](https://popper.js.org/) plugin. 5 | 6 | ### Demos: 7 | 8 | https://antongorodezkiy.github.io/vue-popper-component/ 9 | 10 | ### Dependencies: 11 | 12 | - Vue 1.* 13 | - Popper.js 1.* 14 | 15 | ### Usage: 16 | 17 | ```javascript 18 | const 19 | Vue = require('vue'), 20 | VuePopper = require('vue-popper-component'); 21 | 22 | new Vue({ 23 | el: '#app', 24 | 25 | components: { 26 | 'popper': VuePopper 27 | }, 28 | 29 | data: { 30 | showPopperParentVar: true 31 | } 32 | }); 33 | ``` 34 | 35 | ```html 36 | 41 | 42 | 43 | ? 44 | 45 | 46 | 47 | ``` 48 | 49 | ### Usage with html in slots: 50 | 51 | ```html 52 | 57 | 58 |
59 | 60 |
61 | 62 |
63 |

us on github!

64 | Close this popover from the content! 65 |
66 | 67 | 70 |
71 | ``` 72 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-popper-component", 3 | "version": "0.1.0", 4 | "description": "Vue.js component for Popper.js", 5 | "main": "dist/vue-popper+popperjs.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build-sass": "node-sass src/vue-popper.scss dist/vue-popper.css", 9 | "build-vue": "NODE_ENV=production browserify --standalone VuePopper -e src/VuePopper.vue -o dist/vue-popper+popperjs.js && browserify --standalone VuePopper --external popper.js -e src/VuePopper.vue -o dist/vue-popper.js", 10 | "build": "NODE_ENV=production npm run build-vue && npm run build-sass", 11 | "docs": "NODE_ENV=production browserify -e docs/demo.module.js -o docs/demo.js && cp dist/vue-popper.css docs/demo.css" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/antongorodezkiy/vue-popper-component.git" 16 | }, 17 | "keywords": [ 18 | "vue", 19 | "popperjs", 20 | "component" 21 | ], 22 | "author": "antongorodezkiy", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/antongorodezkiy/vue-popper-component/issues" 26 | }, 27 | "homepage": "https://github.com/antongorodezkiy/vue-popper-component#readme", 28 | "dependencies": { 29 | "popper.js": "1.*", 30 | "vue": "1.*" 31 | }, 32 | "devDependencies": { 33 | "babel-cli": "^6.18.0", 34 | "babel-core": "^6.22.1", 35 | "babel-plugin-transform-runtime": "^6.22.0", 36 | "babel-preset-es2015": "^6.18.0", 37 | "babel-runtime": "^6.22.0", 38 | "babelify": "^7.3.0", 39 | "browserify": "^13.3.0", 40 | "node-sass": "^4.2.0", 41 | "vueify": "8.*" 42 | }, 43 | "browserify": { 44 | "transform": [ 45 | [ 46 | "vueify", 47 | "babelify", 48 | { 49 | "presets": [ 50 | "es2015" 51 | ] 52 | } 53 | ] 54 | ] 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/vue-popper.scss: -------------------------------------------------------------------------------- 1 | $popper-background-color: gold !default; 2 | 3 | .vue-popper-component { 4 | background: $popper-background-color; 5 | color: black; 6 | width: 320px; 7 | padding: 10px; 8 | -webkit-border-radius: 3px; 9 | -moz-border-radius: 3px; 10 | border-radius: 3px; 11 | z-index: 1100; 12 | -webkit-box-shadow: 1px 1px 0px rgba(0, 0, 0, 0.1); 13 | -moz-box-shadow: 1px 1px 0px rgba(0, 0, 0, 0.1); 14 | box-shadow: 1px 1px 0px rgba(0, 0, 0, 0.1); 15 | 16 | .popper-close { 17 | position: absolute; 18 | top: 2px; 19 | right: 4px; 20 | color: black; 21 | background: transparent; 22 | border: none; 23 | 24 | &:active, 25 | &:focus { 26 | outline: none; 27 | } 28 | } 29 | 30 | .popper__arrow { 31 | width: 0; 32 | height: 0; 33 | border-style: solid; 34 | position: absolute; 35 | margin: 5px; 36 | } 37 | 38 | &[x-placement^="top"] { 39 | margin-bottom: 5px; 40 | 41 | .popper__arrow { 42 | border-width: 5px 5px 0 5px; 43 | border-color: $popper-background-color transparent transparent transparent; 44 | bottom: -5px; 45 | left: calc(50% - 5px); 46 | margin-top: 0; 47 | margin-bottom: 0; 48 | } 49 | } 50 | 51 | &[x-placement^="bottom"] { 52 | margin-top: 5px; 53 | 54 | .popper__arrow { 55 | border-width: 0 5px 5px 5px; 56 | border-color: transparent transparent $popper-background-color transparent; 57 | top: -5px; 58 | left: calc(50% - 5px); 59 | margin-top: 0; 60 | margin-bottom: 0; 61 | } 62 | } 63 | 64 | &[x-placement^="right"] { 65 | margin-left: 5px; 66 | 67 | .popper__arrow { 68 | border-width: 5px 5px 5px 0; 69 | border-color: transparent $popper-background-color transparent transparent; 70 | left: -5px; 71 | top: calc(50% - 5px); 72 | margin-left: 0; 73 | margin-right: 0; 74 | } 75 | } 76 | 77 | &[x-placement^="left"] { 78 | margin-right: 5px; 79 | 80 | .popper__arrow { 81 | border-width: 5px 0 5px 5px; 82 | border-color: transparent transparent transparent $popper-background-color; 83 | right: -5px; 84 | top: calc(50% - 5px); 85 | margin-left: 0; 86 | margin-right: 0; 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /docs/demo.css: -------------------------------------------------------------------------------- 1 | .vue-popper-component { 2 | background: gold; 3 | color: black; 4 | width: 320px; 5 | padding: 10px; 6 | -webkit-border-radius: 3px; 7 | -moz-border-radius: 3px; 8 | border-radius: 3px; 9 | z-index: 1100; 10 | -webkit-box-shadow: 1px 1px 0px rgba(0, 0, 0, 0.1); 11 | -moz-box-shadow: 1px 1px 0px rgba(0, 0, 0, 0.1); 12 | box-shadow: 1px 1px 0px rgba(0, 0, 0, 0.1); } 13 | .vue-popper-component .popper-close { 14 | position: absolute; 15 | top: 2px; 16 | right: 4px; 17 | color: black; 18 | background: transparent; 19 | border: none; } 20 | .vue-popper-component .popper-close:active, .vue-popper-component .popper-close:focus { 21 | outline: none; } 22 | .vue-popper-component .popper__arrow { 23 | width: 0; 24 | height: 0; 25 | border-style: solid; 26 | position: absolute; 27 | margin: 5px; } 28 | .vue-popper-component[x-placement^="top"] { 29 | margin-bottom: 5px; } 30 | .vue-popper-component[x-placement^="top"] .popper__arrow { 31 | border-width: 5px 5px 0 5px; 32 | border-color: gold transparent transparent transparent; 33 | bottom: -5px; 34 | left: calc(50% - 5px); 35 | margin-top: 0; 36 | margin-bottom: 0; } 37 | .vue-popper-component[x-placement^="bottom"] { 38 | margin-top: 5px; } 39 | .vue-popper-component[x-placement^="bottom"] .popper__arrow { 40 | border-width: 0 5px 5px 5px; 41 | border-color: transparent transparent gold transparent; 42 | top: -5px; 43 | left: calc(50% - 5px); 44 | margin-top: 0; 45 | margin-bottom: 0; } 46 | .vue-popper-component[x-placement^="right"] { 47 | margin-left: 5px; } 48 | .vue-popper-component[x-placement^="right"] .popper__arrow { 49 | border-width: 5px 5px 5px 0; 50 | border-color: transparent gold transparent transparent; 51 | left: -5px; 52 | top: calc(50% - 5px); 53 | margin-left: 0; 54 | margin-right: 0; } 55 | .vue-popper-component[x-placement^="left"] { 56 | margin-right: 5px; } 57 | .vue-popper-component[x-placement^="left"] .popper__arrow { 58 | border-width: 5px 0 5px 5px; 59 | border-color: transparent transparent transparent gold; 60 | right: -5px; 61 | top: calc(50% - 5px); 62 | margin-left: 0; 63 | margin-right: 0; } 64 | -------------------------------------------------------------------------------- /dist/vue-popper.css: -------------------------------------------------------------------------------- 1 | .vue-popper-component { 2 | background: gold; 3 | color: black; 4 | width: 320px; 5 | padding: 10px; 6 | -webkit-border-radius: 3px; 7 | -moz-border-radius: 3px; 8 | border-radius: 3px; 9 | z-index: 1100; 10 | -webkit-box-shadow: 1px 1px 0px rgba(0, 0, 0, 0.1); 11 | -moz-box-shadow: 1px 1px 0px rgba(0, 0, 0, 0.1); 12 | box-shadow: 1px 1px 0px rgba(0, 0, 0, 0.1); } 13 | .vue-popper-component .popper-close { 14 | position: absolute; 15 | top: 2px; 16 | right: 4px; 17 | color: black; 18 | background: transparent; 19 | border: none; } 20 | .vue-popper-component .popper-close:active, .vue-popper-component .popper-close:focus { 21 | outline: none; } 22 | .vue-popper-component .popper__arrow { 23 | width: 0; 24 | height: 0; 25 | border-style: solid; 26 | position: absolute; 27 | margin: 5px; } 28 | .vue-popper-component[x-placement^="top"] { 29 | margin-bottom: 5px; } 30 | .vue-popper-component[x-placement^="top"] .popper__arrow { 31 | border-width: 5px 5px 0 5px; 32 | border-color: gold transparent transparent transparent; 33 | bottom: -5px; 34 | left: calc(50% - 5px); 35 | margin-top: 0; 36 | margin-bottom: 0; } 37 | .vue-popper-component[x-placement^="bottom"] { 38 | margin-top: 5px; } 39 | .vue-popper-component[x-placement^="bottom"] .popper__arrow { 40 | border-width: 0 5px 5px 5px; 41 | border-color: transparent transparent gold transparent; 42 | top: -5px; 43 | left: calc(50% - 5px); 44 | margin-top: 0; 45 | margin-bottom: 0; } 46 | .vue-popper-component[x-placement^="right"] { 47 | margin-left: 5px; } 48 | .vue-popper-component[x-placement^="right"] .popper__arrow { 49 | border-width: 5px 5px 5px 0; 50 | border-color: transparent gold transparent transparent; 51 | left: -5px; 52 | top: calc(50% - 5px); 53 | margin-left: 0; 54 | margin-right: 0; } 55 | .vue-popper-component[x-placement^="left"] { 56 | margin-right: 5px; } 57 | .vue-popper-component[x-placement^="left"] .popper__arrow { 58 | border-width: 5px 0 5px 5px; 59 | border-color: transparent transparent transparent gold; 60 | right: -5px; 61 | top: calc(50% - 5px); 62 | margin-left: 0; 63 | margin-right: 0; } 64 | -------------------------------------------------------------------------------- /src/VuePopper.vue: -------------------------------------------------------------------------------- 1 | 89 | 90 | 109 | -------------------------------------------------------------------------------- /dist/vue-popper.js: -------------------------------------------------------------------------------- 1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.VuePopper = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o{{ content }}
" 90 | 91 | },{"popper.js":"popper.js"}]},{},[1])(1) 92 | }); -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Demo 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Fork me on GitHub 17 | 18 |
19 |
20 |
21 | 22 |
23 |

vue-popper-component 24 | 25 | Star 26 |

27 |

Simple Vue.js component for Popper.js plugin.

28 |

It's a demo!

29 |
30 | 31 | 32 | 33 | 34 |
35 |
36 |

37 | Popover with plain content and plain close-button 38 |

39 |
40 |
41 |




42 | 54 |
55 |
56 |
 57 |   
 58 |   <popper
 59 |     :show-popper.sync="showPopper1"
 60 |     content="Lorem ipsum dolor"
 61 |     placement="right"
 62 |     close-button="Close me!">
 63 |       <a @click.prevent="showPopper1 = !showPopper1" href="#">
 64 |         Click to open popover on the right
 65 |       </a>
 66 |   </popper>
 67 |   
 68 | 
69 |
70 |
71 | 72 |
73 | 74 | 75 | 76 | 77 | 78 |
79 |
80 |

81 | Popover with plain content and without close-button 82 |

83 |
84 |
85 |




86 | 97 |
98 |
99 |
100 |   
101 |   <popper
102 |     :show-popper.sync="showPopper2"
103 |     content="Lorem ipsum dolor"
104 |     placement="left"
105 |     close-button="">
106 |       <a @click.prevent="showPopper2 = !showPopper2" href="#">
107 |         Click to open popover on the left
108 |       </a>
109 |   </popper>
110 |   
111 | 
112 |
113 |
114 | 115 |
116 | 117 | 118 |
119 |
120 |

121 | Popover with plain content and html close-button in the slot 122 |

123 |
124 |
125 |




126 |
127 | 132 | 133 |
134 | 135 |
136 | 137 | 140 |
141 |
142 |
143 |
144 |
145 |   
146 |   <popper
147 |     :show-popper.sync="showPopper3"
148 |     content="Lorem ipsum dolor"
149 |     placement="top"
150 |     close-button="1">
151 |     
152 |       <div slot="close-button">
153 |         <i class="glyphicon glyphicon-remove"></i>
154 |       </div>
155 |     
156 |       <button class="btn btn-default" @click.prevent="showPopper3 = !showPopper3">
157 |         Click to open popover on the top
158 |       </button>
159 |   </popper>
160 |   
161 | 
162 |
163 |
164 | 165 |
166 | 167 | 168 | 169 | 170 | 171 |
172 |
173 |

174 | Popover with html content in the slot and html close-button in the slot 175 |

176 |
177 |
178 |




179 |
180 | 185 | 186 |
187 | 188 |
189 | 190 |
191 |

us on github!

192 | Close this popover from the content! 193 |
194 | 195 | 198 |
199 |
200 |
201 |
202 |
203 |
204 | 207 |
208 |
209 |
210 |
211 |   
212 |   <popper
213 |     :show-popper.sync="showPopper4"
214 |     content="Lorem ipsum dolor"
215 |     placement="top"
216 |     close-button="1">
217 |     
218 |       <div slot="close-button">
219 |         <i class="glyphicon glyphicon-remove"></i>
220 |       </div>
221 |       
222 |       <div slot="content">
223 |         <h2><a href="https://github.com/antongorodezkiy/vue-popper-component" target="_blank"><i class="glyphicon glyphicon-star"></i></a> <b>us</b> <i>on</i> <u>github</u>!</h2>
224 |         <a @click.prevent="showPopper4 = false" href="#">Close this popover from the content!</a>
225 |       </div>
226 |     
227 |       <button class="btn btn-default" @click.prevent="showPopper4 = !showPopper4">
228 |         Click to open popover on the bottom
229 |       </button>
230 |   </popper>
231 | 
232 |   <button class="btn btn-default" @click.prevent="showPopper4 = !showPopper4">
233 |     Trigger last popover from the outside
234 |   </button>
235 |   
236 | 
237 |
238 |
239 | 240 |
241 | 242 |
243 |
244 |
245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | -------------------------------------------------------------------------------- /dist/vue-popper+popperjs.js: -------------------------------------------------------------------------------- 1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.VuePopper = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 1 && arguments[1] !== undefined ? arguments[1] : 'top'; 256 | 257 | var upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft'; 258 | var nodeName = element.nodeName; 259 | 260 | if (nodeName === 'BODY' || nodeName === 'HTML') { 261 | var html = window.document.documentElement; 262 | var scrollingElement = window.document.scrollingElement || html; 263 | return scrollingElement[upperSide]; 264 | } 265 | 266 | return element[upperSide]; 267 | } 268 | 269 | /** 270 | * Given an element and one of its parents, return the offset 271 | * @method 272 | * @memberof Popper.Utils 273 | * @param {HTMLElement} element 274 | * @param {HTMLElement} parent 275 | * @return {Object} rect 276 | */ 277 | function getOffsetRectRelativeToCustomParent(element, parent) { 278 | var fixed = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; 279 | var transformed = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; 280 | 281 | var scrollParent = getScrollParent(parent); 282 | var elementRect = getBoundingClientRect(element); 283 | var parentRect = getBoundingClientRect(parent); 284 | 285 | var rect = { 286 | top: elementRect.top - parentRect.top, 287 | left: elementRect.left - parentRect.left, 288 | bottom: elementRect.top - parentRect.top + elementRect.height, 289 | right: elementRect.left - parentRect.left + elementRect.width, 290 | width: elementRect.width, 291 | height: elementRect.height 292 | }; 293 | 294 | if (fixed && !transformed) { 295 | var scrollTop = getScroll(scrollParent, 'top'); 296 | var scrollLeft = getScroll(scrollParent, 'left'); 297 | rect.top -= scrollTop; 298 | rect.bottom -= scrollTop; 299 | rect.left -= scrollLeft; 300 | rect.right -= scrollLeft; 301 | } 302 | // When a popper doesn't have any positioned or scrollable parents, `offsetParent.contains(scrollParent)` 303 | // will return a "false positive". This is happening because `getOffsetParent` returns `html` node, 304 | // and `scrollParent` is the `body` node. Hence the additional check. 305 | else if (getOffsetParent(element).contains(scrollParent) && scrollParent.nodeName !== 'BODY') { 306 | var _scrollTop = getScroll(parent, 'top'); 307 | var _scrollLeft = getScroll(parent, 'left'); 308 | rect.top += _scrollTop; 309 | rect.bottom += _scrollTop; 310 | rect.left += _scrollLeft; 311 | rect.right += _scrollLeft; 312 | } 313 | 314 | // subtract borderTopWidth and borderTopWidth from final result 315 | var styles = getStyleComputedProperty(parent); 316 | var borderTopWidth = Number(styles.borderTopWidth.split('px')[0]); 317 | var borderLeftWidth = Number(styles.borderLeftWidth.split('px')[0]); 318 | 319 | rect.top -= borderTopWidth; 320 | rect.bottom -= borderTopWidth; 321 | rect.left -= borderLeftWidth; 322 | rect.right -= borderLeftWidth; 323 | 324 | return rect; 325 | } 326 | 327 | function getTotalScroll(element) { 328 | var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'top'; 329 | 330 | var scrollParent = getScrollParent(element); 331 | var scroll = getScroll(scrollParent, side); 332 | 333 | if (['BODY', 'HTML'].indexOf(scrollParent.nodeName) === -1) { 334 | return scroll + getTotalScroll(getParentNode(scrollParent), side); 335 | } 336 | return scroll; 337 | } 338 | 339 | /** 340 | * Computed the boundaries limits and return them 341 | * @method 342 | * @memberof Popper.Utils 343 | * @param {Object} data - Object containing the property "offsets" generated by `_getOffsets` 344 | * @param {Number} padding - Boundaries padding 345 | * @param {Element} boundariesElement - Element used to define the boundaries 346 | * @returns {Object} Coordinates of the boundaries 347 | */ 348 | function getBoundaries(popper, padding, boundariesElement) { 349 | // NOTE: 1 DOM access here 350 | var boundaries = { top: 0, left: 0 }; 351 | var offsetParent = getOffsetParent(popper); 352 | 353 | // Handle viewport case 354 | if (boundariesElement === 'viewport') { 355 | var _getOffsetRect = getOffsetRect(offsetParent), 356 | left = _getOffsetRect.left, 357 | top = _getOffsetRect.top; 358 | 359 | var _window$document$docu = window.document.documentElement, 360 | width = _window$document$docu.clientWidth, 361 | height = _window$document$docu.clientHeight; 362 | 363 | 364 | if (getPosition(popper) === 'fixed') { 365 | boundaries.right = width; 366 | boundaries.bottom = height; 367 | } else { 368 | var scrollLeft = getTotalScroll(popper, 'left'); 369 | var scrollTop = getTotalScroll(popper, 'top'); 370 | 371 | boundaries = { 372 | top: 0 - top, 373 | right: width - left + scrollLeft, 374 | bottom: height - top + scrollTop, 375 | left: 0 - left 376 | }; 377 | } 378 | } 379 | // Handle other cases based on DOM element used as boundaries 380 | else { 381 | var boundariesNode = void 0; 382 | if (boundariesElement === 'scrollParent') { 383 | boundariesNode = getScrollParent(popper); 384 | } else if (boundariesElement === 'window') { 385 | boundariesNode = window.document.body; 386 | } else { 387 | boundariesNode = boundariesElement; 388 | } 389 | 390 | // In case of BODY, we need a different computation 391 | if (boundariesNode.nodeName === 'BODY') { 392 | var _getWindowSizes = getWindowSizes(), 393 | _height = _getWindowSizes.height, 394 | _width = _getWindowSizes.width; 395 | 396 | boundaries.right = _width; 397 | boundaries.bottom = _height; 398 | } 399 | // for all the other DOM elements, this one is good 400 | else { 401 | boundaries = getOffsetRectRelativeToCustomParent(boundariesNode, offsetParent, isFixed(popper)); 402 | } 403 | } 404 | 405 | // Add paddings 406 | boundaries.left += padding; 407 | boundaries.top += padding; 408 | boundaries.right -= padding; 409 | boundaries.bottom -= padding; 410 | 411 | return boundaries; 412 | } 413 | 414 | /** 415 | * Utility used to transform the `auto` placement to the placement with more 416 | * available space. 417 | * @method 418 | * @memberof Popper.Utils 419 | * @argument {Object} data - The data object generated by update method 420 | * @argument {Object} options - Modifiers configuration and options 421 | * @returns {Object} The data object, properly modified 422 | */ 423 | function computeAutoPlacement(placement, refRect, popper) { 424 | if (placement.indexOf('auto') === -1) { 425 | return placement; 426 | } 427 | 428 | var boundaries = getBoundaries(popper, 0, 'scrollParent'); 429 | 430 | var sides = { 431 | top: refRect.top - boundaries.top, 432 | right: boundaries.right - refRect.right, 433 | bottom: boundaries.bottom - refRect.bottom, 434 | left: refRect.left - boundaries.left 435 | }; 436 | 437 | var computedPlacement = Object.keys(sides).sort(function (a, b) { 438 | return sides[b] - sides[a]; 439 | })[0]; 440 | var variation = placement.split('-')[1]; 441 | 442 | return computedPlacement + (variation ? '-' + variation : ''); 443 | } 444 | 445 | var nativeHints = ['native code', '[object MutationObserverConstructor]' // for mobile safari iOS 9.0 446 | ]; 447 | 448 | /** 449 | * Determine if a function is implemented natively (as opposed to a polyfill). 450 | * @argument {Function | undefined} fn the function to check 451 | * @returns {boolean} 452 | */ 453 | var isNative = (function (fn) { 454 | return nativeHints.some(function (hint) { 455 | return (fn || '').toString().indexOf(hint) > -1; 456 | }); 457 | }); 458 | 459 | var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox']; 460 | var timeoutDuration = 0; 461 | for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) { 462 | if (navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) { 463 | timeoutDuration = 1; 464 | break; 465 | } 466 | } 467 | 468 | function microtaskDebounce(fn) { 469 | var scheduled = false; 470 | var i = 0; 471 | var elem = document.createElement('span'); 472 | 473 | // MutationObserver provides a mechanism for scheduling microtasks, which 474 | // are scheduled *before* the next task. This gives us a way to debounce 475 | // a function but ensure it's called *before* the next paint. 476 | var observer = new MutationObserver(function () { 477 | fn(); 478 | scheduled = false; 479 | }); 480 | 481 | observer.observe(elem, { attributes: true }); 482 | 483 | return function () { 484 | if (!scheduled) { 485 | scheduled = true; 486 | elem.setAttribute('x-index', i); 487 | i = i + 1; // don't use compund (+=) because it doesn't get optimized in V8 488 | } 489 | }; 490 | } 491 | 492 | function taskDebounce(fn) { 493 | var scheduled = false; 494 | return function () { 495 | if (!scheduled) { 496 | scheduled = true; 497 | setTimeout(function () { 498 | scheduled = false; 499 | fn(); 500 | }, timeoutDuration); 501 | } 502 | }; 503 | } 504 | 505 | // It's common for MutationObserver polyfills to be seen in the wild, however 506 | // these rely on Mutation Events which only occur when an element is connected 507 | // to the DOM. The algorithm used in this module does not use a connected element, 508 | // and so we must ensure that a *native* MutationObserver is available. 509 | var supportsNativeMutationObserver = isNative(window.MutationObserver); 510 | 511 | /** 512 | * Create a debounced version of a method, that's asynchronously deferred 513 | * but called in the minimum time possible. 514 | * 515 | * @method 516 | * @memberof Popper.Utils 517 | * @argument {Function} fn 518 | * @returns {Function} 519 | */ 520 | var debounce = supportsNativeMutationObserver ? microtaskDebounce : taskDebounce; 521 | 522 | /** 523 | * Mimics the `find` method of Array 524 | * @method 525 | * @memberof Popper.Utils 526 | * @argument {Array} arr 527 | * @argument prop 528 | * @argument value 529 | * @returns index or -1 530 | */ 531 | function findIndex$1(arr, check) { 532 | // use native find if supported 533 | if (Array.prototype.find) { 534 | return arr.find(check); 535 | } 536 | 537 | // use `filter` to obtain the same behavior of `find` 538 | return arr.filter(check)[0]; 539 | } 540 | 541 | /** 542 | * Return the index of the matching object 543 | * @method 544 | * @memberof Popper.Utils 545 | * @argument {Array} arr 546 | * @argument prop 547 | * @argument value 548 | * @returns index or -1 549 | */ 550 | function findIndex(arr, prop, value) { 551 | // use native findIndex if supported 552 | if (Array.prototype.findIndex) { 553 | return arr.findIndex(function (cur) { 554 | return cur[prop] === value; 555 | }); 556 | } 557 | 558 | // use `find` + `indexOf` if `findIndex` isn't supported 559 | var match = findIndex$1(arr, function (obj) { 560 | return obj[prop] === value; 561 | }); 562 | return arr.indexOf(match); 563 | } 564 | 565 | var classCallCheck = function (instance, Constructor) { 566 | if (!(instance instanceof Constructor)) { 567 | throw new TypeError("Cannot call a class as a function"); 568 | } 569 | }; 570 | 571 | var createClass = function () { 572 | function defineProperties(target, props) { 573 | for (var i = 0; i < props.length; i++) { 574 | var descriptor = props[i]; 575 | descriptor.enumerable = descriptor.enumerable || false; 576 | descriptor.configurable = true; 577 | if ("value" in descriptor) descriptor.writable = true; 578 | Object.defineProperty(target, descriptor.key, descriptor); 579 | } 580 | } 581 | 582 | return function (Constructor, protoProps, staticProps) { 583 | if (protoProps) defineProperties(Constructor.prototype, protoProps); 584 | if (staticProps) defineProperties(Constructor, staticProps); 585 | return Constructor; 586 | }; 587 | }(); 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | var _extends = Object.assign || function (target) { 596 | for (var i = 1; i < arguments.length; i++) { 597 | var source = arguments[i]; 598 | 599 | for (var key in source) { 600 | if (Object.prototype.hasOwnProperty.call(source, key)) { 601 | target[key] = source[key]; 602 | } 603 | } 604 | } 605 | 606 | return target; 607 | }; 608 | 609 | /** 610 | * Given the popper offsets, generate an output similar to getBoundingClientRect 611 | * @method 612 | * @memberof Popper.Utils 613 | * @argument {Object} popperOffsets 614 | * @returns {Object} ClientRect like output 615 | */ 616 | function getClientRect(popperOffsets) { 617 | return _extends({}, popperOffsets, { 618 | right: popperOffsets.left + popperOffsets.width, 619 | bottom: popperOffsets.top + popperOffsets.height 620 | }); 621 | } 622 | 623 | /** 624 | * Get the outer sizes of the given element (offset size + margins) 625 | * @method 626 | * @memberof Popper.Utils 627 | * @argument {Element} element 628 | * @returns {Object} object containing width and height properties 629 | */ 630 | function getOuterSizes(element) { 631 | var styles = window.getComputedStyle(element); 632 | var x = parseFloat(styles.marginTop) + parseFloat(styles.marginBottom); 633 | var y = parseFloat(styles.marginLeft) + parseFloat(styles.marginRight); 634 | var result = { 635 | width: element.offsetWidth + y, 636 | height: element.offsetHeight + x 637 | }; 638 | return result; 639 | } 640 | 641 | /** 642 | * Get the opposite placement of the given one/ 643 | * @method 644 | * @memberof Popper.Utils 645 | * @argument {String} placement 646 | * @returns {String} flipped placement 647 | */ 648 | function getOppositePlacement(placement) { 649 | var hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' }; 650 | return placement.replace(/left|right|bottom|top/g, function (matched) { 651 | return hash[matched]; 652 | }); 653 | } 654 | 655 | /** 656 | * Get offsets to the popper 657 | * @method 658 | * @memberof Popper.Utils 659 | * @param {Element} popper - the popper element 660 | * @param {Element} reference - the reference element (the popper will be relative to this) 661 | * @returns {Object} An object containing the offsets which will be applied to the popper 662 | */ 663 | function getPopperOffsets(state, popper, referenceOffsets, placement) { 664 | placement = placement.split('-')[0]; 665 | 666 | // Get popper node sizes 667 | var popperRect = getOuterSizes(popper); 668 | 669 | // Add position, width and height to our offsets object 670 | var popperOffsets = { 671 | position: state.position, 672 | width: popperRect.width, 673 | height: popperRect.height 674 | }; 675 | 676 | // depending by the popper placement we have to compute its offsets slightly differently 677 | var isHoriz = ['right', 'left'].indexOf(placement) !== -1; 678 | var mainSide = isHoriz ? 'top' : 'left'; 679 | var secondarySide = isHoriz ? 'left' : 'top'; 680 | var measurement = isHoriz ? 'height' : 'width'; 681 | var secondaryMeasurement = !isHoriz ? 'height' : 'width'; 682 | 683 | popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2; 684 | if (placement === secondarySide) { 685 | popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement]; 686 | } else { 687 | popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)]; 688 | } 689 | 690 | return popperOffsets; 691 | } 692 | 693 | /** 694 | * Get offsets to the reference element 695 | * @method 696 | * @memberof Popper.Utils 697 | * @param {Object} state 698 | * @param {Element} popper - the popper element 699 | * @param {Element} reference - the reference element (the popper will be relative to this) 700 | * @returns {Object} An object containing the offsets which will be applied to the popper 701 | */ 702 | function getReferenceOffsets(state, popper, reference) { 703 | var isParentFixed = state.position === 'fixed'; 704 | var isParentTransformed = state.isParentTransformed; 705 | var offsetParent = getOffsetParent(isParentFixed && isParentTransformed ? reference : popper); 706 | 707 | return getOffsetRectRelativeToCustomParent(reference, offsetParent, isParentFixed, isParentTransformed); 708 | } 709 | 710 | /** 711 | * Get the prefixed supported property name 712 | * @method 713 | * @memberof Popper.Utils 714 | * @argument {String} property (camelCase) 715 | * @returns {String} prefixed property (camelCase) 716 | */ 717 | function getSupportedPropertyName(property) { 718 | var prefixes = [false, 'ms', 'webkit', 'moz', 'o']; 719 | var upperProp = property.charAt(0).toUpperCase() + property.slice(1); 720 | 721 | for (var i = 0; i < prefixes.length - 1; i++) { 722 | var prefix = prefixes[i]; 723 | var toCheck = prefix ? '' + prefix + upperProp : property; 724 | if (typeof window.document.body.style[toCheck] !== 'undefined') { 725 | return toCheck; 726 | } 727 | } 728 | return null; 729 | } 730 | 731 | /** 732 | * Check if the given variable is a function 733 | * @method 734 | * @memberof Popper.Utils 735 | * @argument {Element} element - Element to check 736 | * @returns {Boolean} answer to: is a function? 737 | */ 738 | function isFunction(functionToCheck) { 739 | var getType = {}; 740 | return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; 741 | } 742 | 743 | /** 744 | * Helper used to know if the given modifier is enabled. 745 | * @method 746 | * @memberof Popper.Utils 747 | * @returns {Boolean} 748 | */ 749 | function isModifierEnabled(modifiers, modifierName) { 750 | return modifiers.some(function (_ref) { 751 | var name = _ref.name, 752 | enabled = _ref.enabled; 753 | return enabled && name === modifierName; 754 | }); 755 | } 756 | 757 | /** 758 | * Helper used to know if the given modifier depends from another one. 759 | * It checks if the needed modifier is listed and enabled. 760 | * @method 761 | * @memberof Popper.Utils 762 | * @returns {Boolean} 763 | */ 764 | function isModifierRequired(modifiers, requestingName, requestedName) { 765 | var requesting = findIndex$1(modifiers, function (_ref) { 766 | var name = _ref.name; 767 | return name === requestingName; 768 | }); 769 | 770 | return !!requesting && modifiers.some(function (modifier) { 771 | return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order; 772 | }); 773 | } 774 | 775 | /** 776 | * Tells if a given input is a number 777 | * @method 778 | * @memberof Popper.Utils 779 | * @param {*} input to check 780 | * @return {Boolean} 781 | */ 782 | function isNumeric(n) { 783 | return n !== '' && !isNaN(parseFloat(n)) && isFinite(n); 784 | } 785 | 786 | /** 787 | * Check if the given element has transforms applied to itself or a parent 788 | * @method 789 | * @memberof Popper.Utils 790 | * @param {Element} element 791 | * @return {Boolean} answer to "isTransformed?" 792 | */ 793 | function isTransformed(element) { 794 | if (element.nodeName === 'BODY') { 795 | return false; 796 | } 797 | if (getStyleComputedProperty(element, 'transform') !== 'none') { 798 | return true; 799 | } 800 | return getParentNode(element) ? isTransformed(getParentNode(element)) : element; 801 | } 802 | 803 | /** 804 | * Remove event listeners used to update the popper position 805 | * @method 806 | * @memberof Popper.Utils 807 | * @private 808 | */ 809 | function removeEventListeners(reference, state) { 810 | // NOTE: 1 DOM access here 811 | window.removeEventListener('resize', state.updateBound); 812 | if (state.scrollElement) { 813 | state.scrollElement.removeEventListener('scroll', state.updateBound); 814 | } 815 | state.updateBound = null; 816 | state.scrollElement = null; 817 | state.eventsEnabled = false; 818 | return state; 819 | } 820 | 821 | /** 822 | * Loop trough the list of modifiers and run them in order, each of them will then edit the data object 823 | * @method 824 | * @memberof Popper.Utils 825 | * @param {Object} data 826 | * @param {Array} modifiers 827 | * @param {Function} ends 828 | */ 829 | function runModifiers(modifiers, data, ends) { 830 | var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends)); 831 | 832 | modifiersToRun.forEach(function (modifier) { 833 | if (modifier.enabled && isFunction(modifier.function)) { 834 | data = modifier.function(data, modifier); 835 | } 836 | }); 837 | 838 | return data; 839 | } 840 | 841 | /** 842 | * Set the attributes to the given popper 843 | * @method 844 | * @memberof Popper.Utils 845 | * @argument {Element} element - Element to apply the attributes to 846 | * @argument {Object} styles - Object with a list of properties and values which will be applied to the element 847 | */ 848 | function setAttributes(element, attributes) { 849 | Object.keys(attributes).forEach(function (prop) { 850 | var value = attributes[prop]; 851 | if (value !== false) { 852 | element.setAttribute(prop, attributes[prop]); 853 | } else { 854 | element.removeAttribute(prop); 855 | } 856 | }); 857 | } 858 | 859 | /** 860 | * Set the style to the given popper 861 | * @method 862 | * @memberof Popper.Utils 863 | * @argument {Element} element - Element to apply the style to 864 | * @argument {Object} styles - Object with a list of properties and values which will be applied to the element 865 | */ 866 | function setStyles(element, styles) { 867 | Object.keys(styles).forEach(function (prop) { 868 | var unit = ''; 869 | // add unit if the value is numeric and is one of the following 870 | if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) { 871 | unit = 'px'; 872 | } 873 | element.style[prop] = styles[prop] + unit; 874 | }); 875 | } 876 | 877 | /** 878 | * Setup needed event listeners used to update the popper position 879 | * @method 880 | * @memberof Popper.Utils 881 | * @private 882 | */ 883 | function setupEventListeners(reference, options, state, updateBound) { 884 | // NOTE: 1 DOM access here 885 | state.updateBound = updateBound; 886 | window.addEventListener('resize', state.updateBound, { passive: true }); 887 | var target = getScrollParent(reference); 888 | if (target.nodeName === 'BODY') { 889 | target = window; 890 | } 891 | target.addEventListener('scroll', state.updateBound, { passive: true }); 892 | state.scrollElement = target; 893 | state.eventsEnabled = true; 894 | 895 | return state; 896 | } 897 | 898 | /** @namespace Popper.Utils */ 899 | var Utils = { 900 | computeAutoPlacement: computeAutoPlacement, 901 | debounce: debounce, 902 | findIndex: findIndex, 903 | getBoundaries: getBoundaries, 904 | getBoundingClientRect: getBoundingClientRect, 905 | getClientRect: getClientRect, 906 | getOffsetParent: getOffsetParent, 907 | getOffsetRect: getOffsetRect, 908 | getOffsetRectRelativeToCustomParent: getOffsetRectRelativeToCustomParent, 909 | getOuterSizes: getOuterSizes, 910 | getParentNode: getParentNode, 911 | getPopperOffsets: getPopperOffsets, 912 | getPosition: getPosition, 913 | getReferenceOffsets: getReferenceOffsets, 914 | getScroll: getScroll, 915 | getScrollParent: getScrollParent, 916 | getStyleComputedProperty: getStyleComputedProperty, 917 | getSupportedPropertyName: getSupportedPropertyName, 918 | getTotalScroll: getTotalScroll, 919 | getWindowSizes: getWindowSizes, 920 | isFixed: isFixed, 921 | isFunction: isFunction, 922 | isModifierEnabled: isModifierEnabled, 923 | isModifierRequired: isModifierRequired, 924 | isNative: isNative, 925 | isNumeric: isNumeric, 926 | isTransformed: isTransformed, 927 | removeEventListeners: removeEventListeners, 928 | runModifiers: runModifiers, 929 | setAttributes: setAttributes, 930 | setStyles: setStyles, 931 | setupEventListeners: setupEventListeners 932 | }; 933 | 934 | /** 935 | * Apply the computed styles to the popper element 936 | * @method 937 | * @memberof Modifiers 938 | * @argument {Object} data - The data object generated by `update` method 939 | * @argument {Object} data.styles - List of style properties - values to apply to popper element 940 | * @argument {Object} data.attributes - List of attribute properties - values to apply to popper element 941 | * @argument {Object} options - Modifiers configuration and options 942 | * @returns {Object} The same data object 943 | */ 944 | function applyStyle(data, options) { 945 | // apply the final offsets to the popper 946 | // NOTE: 1 DOM access here 947 | var styles = { 948 | position: data.offsets.popper.position 949 | }; 950 | 951 | var attributes = { 952 | 'x-placement': data.placement 953 | }; 954 | 955 | // round top and left to avoid blurry text 956 | var left = Math.round(data.offsets.popper.left); 957 | var top = Math.round(data.offsets.popper.top); 958 | 959 | // if gpuAcceleration is set to true and transform is supported, 960 | // we use `translate3d` to apply the position to the popper we 961 | // automatically use the supported prefixed version if needed 962 | var prefixedProperty = getSupportedPropertyName('transform'); 963 | if (options.gpuAcceleration && prefixedProperty) { 964 | styles[prefixedProperty] = 'translate3d(' + left + 'px, ' + top + 'px, 0)'; 965 | styles.top = 0; 966 | styles.left = 0; 967 | styles.willChange = 'transform'; 968 | } 969 | // othwerise, we use the standard `left` and `top` properties 970 | else { 971 | styles.left = left; 972 | styles.top = top; 973 | styles.willChange = 'top, left'; 974 | } 975 | 976 | // any property present in `data.styles` will be applied to the popper, 977 | // in this way we can make the 3rd party modifiers add custom styles to it 978 | // Be aware, modifiers could override the properties defined in the previous 979 | // lines of this modifier! 980 | setStyles(data.instance.popper, _extends({}, styles, data.styles)); 981 | 982 | // any property present in `data.attributes` will be applied to the popper, 983 | // they will be set as HTML attributes of the element 984 | setAttributes(data.instance.popper, _extends({}, attributes, data.attributes)); 985 | 986 | // if the arrow style has been computed, apply the arrow style 987 | if (data.offsets.arrow) { 988 | setStyles(data.arrowElement, data.offsets.arrow); 989 | } 990 | 991 | return data; 992 | } 993 | 994 | /** 995 | * Set the x-placement attribute before everything else because it could be used to add margins to the popper 996 | * margins needs to be calculated to get the correct popper offsets 997 | * @method 998 | * @memberof Popper.modifiers 999 | * @param {HTMLElement} reference - The reference element used to position the popper 1000 | * @param {HTMLElement} popper - The HTML element used as popper. 1001 | * @param {Object} options - Popper.js options 1002 | */ 1003 | function applyStyleOnLoad(reference, popper, options, modifierOptions, state) { 1004 | // compute reference element offsets 1005 | var referenceOffsets = getReferenceOffsets(state, popper, reference); 1006 | 1007 | // compute auto placement, store placement inside the data object, 1008 | // modifiers will be able to edit `placement` if needed 1009 | // and refer to originalPlacement to know the original value 1010 | options.placement = computeAutoPlacement(options.placement, referenceOffsets, popper); 1011 | 1012 | popper.setAttribute('x-placement', options.placement); 1013 | return options; 1014 | } 1015 | 1016 | /** 1017 | * Modifier used to move the arrowElements on the edge of the popper to make sure them are always between the popper and the reference element 1018 | * It will use the CSS outer size of the arrowElement element to know how many pixels of conjuction are needed 1019 | * @method 1020 | * @memberof Modifiers 1021 | * @argument {Object} data - The data object generated by update method 1022 | * @argument {Object} options - Modifiers configuration and options 1023 | * @returns {Object} The data object, properly modified 1024 | */ 1025 | function arrow(data, options) { 1026 | // arrow depends on keepTogether in order to work 1027 | if (!isModifierRequired(data.instance.modifiers, 'arrow', 'keepTogether')) { 1028 | console.warn('WARNING: `keepTogether` modifier is required by arrow modifier in order to work, be sure to include it before `arrow`!'); 1029 | return data; 1030 | } 1031 | 1032 | var arrowElement = options.element; 1033 | 1034 | // if arrowElement is a string, suppose it's a CSS selector 1035 | if (typeof arrowElement === 'string') { 1036 | arrowElement = data.instance.popper.querySelector(arrowElement); 1037 | 1038 | // if arrowElement is not found, don't run the modifier 1039 | if (!arrowElement) { 1040 | return data; 1041 | } 1042 | } else { 1043 | // if the arrowElement isn't a query selector we must check that the 1044 | // provided DOM node is child of its popper node 1045 | if (!data.instance.popper.contains(arrowElement)) { 1046 | console.warn('WARNING: `arrow.element` must be child of its popper element!'); 1047 | return data; 1048 | } 1049 | } 1050 | 1051 | var placement = data.placement.split('-')[0]; 1052 | var popper = getClientRect(data.offsets.popper); 1053 | var reference = data.offsets.reference; 1054 | var isVertical = ['left', 'right'].indexOf(placement) !== -1; 1055 | 1056 | var len = isVertical ? 'height' : 'width'; 1057 | var side = isVertical ? 'top' : 'left'; 1058 | var altSide = isVertical ? 'left' : 'top'; 1059 | var opSide = isVertical ? 'bottom' : 'right'; 1060 | var arrowElementSize = getOuterSizes(arrowElement)[len]; 1061 | 1062 | // 1063 | // extends keepTogether behavior making sure the popper and its reference have enough pixels in conjuction 1064 | // 1065 | 1066 | // top/left side 1067 | if (reference[opSide] - arrowElementSize < popper[side]) { 1068 | data.offsets.popper[side] -= popper[side] - (reference[opSide] - arrowElementSize); 1069 | } 1070 | // bottom/right side 1071 | if (reference[side] + arrowElementSize > popper[opSide]) { 1072 | data.offsets.popper[side] += reference[side] + arrowElementSize - popper[opSide]; 1073 | } 1074 | 1075 | // compute center of the popper 1076 | var center = reference[side] + reference[len] / 2 - arrowElementSize / 2; 1077 | 1078 | // Compute the sideValue using the updated popper offsets 1079 | var sideValue = center - getClientRect(data.offsets.popper)[side]; 1080 | 1081 | // prevent arrowElement from being placed not contiguously to its popper 1082 | sideValue = Math.max(Math.min(popper[len] - arrowElementSize, sideValue), 0); 1083 | 1084 | data.arrowElement = arrowElement; 1085 | data.offsets.arrow = {}; 1086 | data.offsets.arrow[side] = sideValue; 1087 | data.offsets.arrow[altSide] = ''; // make sure to unset any eventual altSide value from the DOM node 1088 | 1089 | return data; 1090 | } 1091 | 1092 | /** 1093 | * Get the opposite placement variation of the given one/ 1094 | * @method 1095 | * @memberof Popper.Utils 1096 | * @argument {String} placement variation 1097 | * @returns {String} flipped placement variation 1098 | */ 1099 | function getOppositeVariation(variation) { 1100 | if (variation === 'end') { 1101 | return 'start'; 1102 | } else if (variation === 'start') { 1103 | return 'end'; 1104 | } 1105 | return variation; 1106 | } 1107 | 1108 | /** 1109 | * Modifier used to flip the placement of the popper when the latter is starting overlapping its reference element. 1110 | * Requires the `preventOverflow` modifier before it in order to work. 1111 | * **NOTE:** data.instance modifier will run all its previous modifiers everytime it tries to flip the popper! 1112 | * @method 1113 | * @memberof Modifiers 1114 | * @argument {Object} data - The data object generated by update method 1115 | * @argument {Object} options - Modifiers configuration and options 1116 | * @returns {Object} The data object, properly modified 1117 | */ 1118 | function flip(data, options) { 1119 | // if `inner` modifier is enabled, we can't use the `flip` modifier 1120 | if (isModifierEnabled(data.instance.modifiers, 'inner')) { 1121 | return data; 1122 | } 1123 | 1124 | if (data.flipped && data.placement === data.originalPlacement) { 1125 | // seems like flip is trying to loop, probably there's not enough space on any of the flippable sides 1126 | return data; 1127 | } 1128 | 1129 | var boundaries = getBoundaries(data.instance.popper, options.padding, options.boundariesElement); 1130 | 1131 | var placement = data.placement.split('-')[0]; 1132 | var placementOpposite = getOppositePlacement(placement); 1133 | var variation = data.placement.split('-')[1] || ''; 1134 | 1135 | var flipOrder = []; 1136 | 1137 | if (options.behavior === 'flip') { 1138 | flipOrder = [placement, placementOpposite]; 1139 | } else { 1140 | flipOrder = options.behavior; 1141 | } 1142 | 1143 | flipOrder.forEach(function (step, index) { 1144 | if (placement !== step || flipOrder.length === index + 1) { 1145 | return data; 1146 | } 1147 | 1148 | placement = data.placement.split('-')[0]; 1149 | placementOpposite = getOppositePlacement(placement); 1150 | 1151 | var popperOffsets = getClientRect(data.offsets.popper); 1152 | var refOffsets = data.offsets.reference; 1153 | 1154 | // using Math.floor because the reference offsets may contain decimals we are not going to consider here 1155 | var overlapsRef = placement === 'left' && Math.floor(popperOffsets.right) > Math.floor(refOffsets.left) || placement === 'right' && Math.floor(popperOffsets.left) < Math.floor(refOffsets.right) || placement === 'top' && Math.floor(popperOffsets.bottom) > Math.floor(refOffsets.top) || placement === 'bottom' && Math.floor(popperOffsets.top) < Math.floor(refOffsets.bottom); 1156 | 1157 | var overflowsBoundaries = placement === 'left' && Math.floor(popperOffsets.left) < Math.floor(boundaries.left) || placement === 'right' && Math.floor(popperOffsets.right) > Math.floor(boundaries.right) || placement === 'top' && Math.floor(popperOffsets.top) < Math.floor(boundaries.top) || placement === 'bottom' && Math.floor(popperOffsets.bottom) > Math.floor(boundaries.bottom); 1158 | 1159 | // flip the variation if required 1160 | var isVertical = ['top', 'bottom'].indexOf(placement) !== -1; 1161 | var flippedVariation = !!options.flipVariations && (isVertical && variation === 'start' && Math.floor(popperOffsets.left) < Math.floor(boundaries.left) || isVertical && variation === 'end' && Math.floor(popperOffsets.right) > Math.floor(boundaries.right) || !isVertical && variation === 'start' && Math.floor(popperOffsets.top) < Math.floor(boundaries.top) || !isVertical && variation === 'end' && Math.floor(popperOffsets.bottom) > Math.floor(boundaries.bottom)); 1162 | 1163 | if (overlapsRef || overflowsBoundaries || flippedVariation) { 1164 | // this boolean to detect any flip loop 1165 | data.flipped = true; 1166 | 1167 | if (overlapsRef || overflowsBoundaries) { 1168 | placement = flipOrder[index + 1]; 1169 | } 1170 | 1171 | if (flippedVariation) { 1172 | variation = getOppositeVariation(variation); 1173 | } 1174 | 1175 | data.placement = placement + (variation ? '-' + variation : ''); 1176 | data.offsets.popper = getPopperOffsets(data.instance.state, data.instance.popper, data.offsets.reference, data.placement); 1177 | 1178 | data = runModifiers(data.instance.modifiers, data, 'flip'); 1179 | } 1180 | }); 1181 | return data; 1182 | } 1183 | 1184 | /** 1185 | * Modifier used to make sure the popper is always near its reference element 1186 | * It cares only about the first axis, you can still have poppers with margin 1187 | * between the popper and its reference element. 1188 | * @method 1189 | * @memberof Modifiers 1190 | * @argument {Object} data - The data object generated by update method 1191 | * @argument {Object} options - Modifiers configuration and options 1192 | * @returns {Object} The data object, properly modified 1193 | */ 1194 | function keepTogether(data) { 1195 | var popper = getClientRect(data.offsets.popper); 1196 | var reference = data.offsets.reference; 1197 | var placement = data.placement.split('-')[0]; 1198 | var floor = Math.floor; 1199 | 1200 | if (['top', 'bottom'].indexOf(placement) !== -1) { 1201 | if (popper.right < floor(reference.left)) { 1202 | data.offsets.popper.left = floor(reference.left) - popper.width; 1203 | } 1204 | if (popper.left > floor(reference.right)) { 1205 | data.offsets.popper.left = floor(reference.right); 1206 | } 1207 | } else { 1208 | if (popper.bottom < floor(reference.top)) { 1209 | data.offsets.popper.top = floor(reference.top) - popper.height; 1210 | } 1211 | if (popper.top > floor(reference.bottom)) { 1212 | data.offsets.popper.top = floor(reference.bottom); 1213 | } 1214 | } 1215 | 1216 | return data; 1217 | } 1218 | 1219 | /** 1220 | * Modifier used to add an offset to the popper, useful if you more granularity positioning your popper. 1221 | * The offsets will shift the popper on the side of its reference element. 1222 | * @method 1223 | * @memberof Modifiers 1224 | * @argument {Object} data - The data object generated by update method 1225 | * @argument {Object} options - Modifiers configuration and options 1226 | * @argument {Number|String} options.offset=0 1227 | * Basic usage allows a number used to nudge the popper by the given amount of pixels. 1228 | * You can pass a percentage value as string (eg. `20%`) to nudge by the given percentage (relative to reference element size) 1229 | * Other supported units are `vh` and `vw` (relative to viewport) 1230 | * Additionally, you can pass a pair of values (eg. `10 20` or `2vh 20%`) to nudge the popper 1231 | * on both axis. 1232 | * A note about percentage values, if you want to refer a percentage to the popper size instead of the reference element size, 1233 | * use `%p` instead of `%` (eg: `20%p`). To make it clearer, you can replace `%` with `%r` and use eg.`10%p 25%r`. 1234 | * > **Heads up!** The order of the axis is relative to the popper placement: `bottom` or `top` are `X,Y`, the other are `Y,X` 1235 | * @returns {Object} The data object, properly modified 1236 | */ 1237 | function offset(data, options) { 1238 | var placement = data.placement; 1239 | var popper = data.offsets.popper; 1240 | 1241 | var offsets = void 0; 1242 | if (isNumeric(options.offset)) { 1243 | offsets = [options.offset, 0]; 1244 | } else { 1245 | // split the offset in case we are providing a pair of offsets separated 1246 | // by a blank space 1247 | offsets = options.offset.split(' '); 1248 | 1249 | // itherate through each offset to compute them in case they are percentages 1250 | offsets = offsets.map(function (offset, index) { 1251 | // separate value from unit 1252 | var split = offset.match(/(\d*\.?\d*)(.*)/); 1253 | var value = +split[1]; 1254 | var unit = split[2]; 1255 | 1256 | // use height if placement is left or right and index is 0 otherwise use width 1257 | // in this way the first offset will use an axis and the second one 1258 | // will use the other one 1259 | var useHeight = placement.indexOf('right') !== -1 || placement.indexOf('left') !== -1; 1260 | 1261 | if (index === 1) { 1262 | useHeight = !useHeight; 1263 | } 1264 | 1265 | var measurement = useHeight ? 'height' : 'width'; 1266 | 1267 | // if is a percentage, we calculate the value of it using as base the 1268 | // sizes of the reference element 1269 | if (unit === '%' || unit === '%r') { 1270 | var referenceRect = getClientRect(data.offsets.reference); 1271 | var len = referenceRect[measurement]; 1272 | return len / 100 * value; 1273 | } 1274 | // if is a percentage relative to the popper, we calculate the value of it using 1275 | // as base the sizes of the popper 1276 | else if (unit === '%p') { 1277 | var popperRect = getClientRect(data.offsets.popper); 1278 | var _len = popperRect[measurement]; 1279 | return _len / 100 * value; 1280 | } 1281 | // if is a vh or vw, we calculate the size based on the viewport 1282 | else if (unit === 'vh' || unit === 'vw') { 1283 | var size = void 0; 1284 | if (unit === 'vh') { 1285 | size = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); 1286 | } else { 1287 | size = Math.max(document.documentElement.clientWidth, window.innerWidth || 0); 1288 | } 1289 | return size / 100 * value; 1290 | } 1291 | // if is an explicit pixel unit, we get rid of the unit and keep the value 1292 | else if (unit === 'px') { 1293 | return +value; 1294 | } 1295 | // if is an implicit unit, it's px, and we return just the value 1296 | else { 1297 | return +offset; 1298 | } 1299 | }); 1300 | } 1301 | 1302 | if (data.placement.indexOf('left') !== -1) { 1303 | popper.top += offsets[0]; 1304 | popper.left -= offsets[1] || 0; 1305 | } else if (data.placement.indexOf('right') !== -1) { 1306 | popper.top += offsets[0]; 1307 | popper.left += offsets[1] || 0; 1308 | } else if (data.placement.indexOf('top') !== -1) { 1309 | popper.left += offsets[0]; 1310 | popper.top -= offsets[1] || 0; 1311 | } else if (data.placement.indexOf('bottom') !== -1) { 1312 | popper.left += offsets[0]; 1313 | popper.top += offsets[1] || 0; 1314 | } 1315 | return data; 1316 | } 1317 | 1318 | /** 1319 | * Modifier used to prevent the popper from being positioned outside the boundary. 1320 | * 1321 | * An scenario exists where the reference itself is not within the boundaries. We can 1322 | * say it has "escaped the boundaries" — or just "escaped". In this case we need to 1323 | * decide whether the popper should either: 1324 | * 1325 | * - detach from the reference and remain "trapped" in the boundaries, or 1326 | * - if it should be ignore the boundary and "escape with the reference" 1327 | * 1328 | * When `escapeWithReference` is `true`, and reference is completely outside the 1329 | * boundaries, the popper will overflow (or completely leave) the boundaries in order 1330 | * to remain attached to the edge of the reference. 1331 | * 1332 | * @method 1333 | * @memberof Modifiers 1334 | * @argument {Object} data - The data object generated by `update` method 1335 | * @argument {Object} options - Modifiers configuration and options 1336 | * @returns {Object} The data object, properly modified 1337 | */ 1338 | function preventOverflow(data, options) { 1339 | var boundariesElement = options.boundariesElement || getOffsetParent(data.instance.popper); 1340 | var boundaries = getBoundaries(data.instance.popper, options.padding, boundariesElement); 1341 | options.boundaries = boundaries; 1342 | 1343 | var order = options.priority; 1344 | var popper = getClientRect(data.offsets.popper); 1345 | 1346 | var check = { 1347 | left: function left() { 1348 | var left = popper.left; 1349 | if (popper.left < boundaries.left && !shouldOverflowBoundary(data, options, 'left')) { 1350 | left = Math.max(popper.left, boundaries.left); 1351 | } 1352 | return { left: left }; 1353 | }, 1354 | right: function right() { 1355 | var left = popper.left; 1356 | if (popper.right > boundaries.right && !shouldOverflowBoundary(data, options, 'right')) { 1357 | left = Math.min(popper.left, boundaries.right - popper.width); 1358 | } 1359 | return { left: left }; 1360 | }, 1361 | top: function top() { 1362 | var top = popper.top; 1363 | if (popper.top < boundaries.top && !shouldOverflowBoundary(data, options, 'top')) { 1364 | top = Math.max(popper.top, boundaries.top); 1365 | } 1366 | return { top: top }; 1367 | }, 1368 | bottom: function bottom() { 1369 | var top = popper.top; 1370 | if (popper.bottom > boundaries.bottom && !shouldOverflowBoundary(data, options, 'bottom')) { 1371 | top = Math.min(popper.top, boundaries.bottom - popper.height); 1372 | } 1373 | return { top: top }; 1374 | } 1375 | }; 1376 | 1377 | order.forEach(function (direction) { 1378 | popper = _extends({}, popper, check[direction]()); 1379 | }); 1380 | 1381 | data.offsets.popper = popper; 1382 | 1383 | return data; 1384 | } 1385 | 1386 | /** 1387 | * Determine if the popper should overflow a boundary edge to stay together with the reference. 1388 | */ 1389 | function shouldOverflowBoundary(data, options, overflowDirection) { 1390 | if (!options.escapeWithReference) { 1391 | return false; 1392 | } 1393 | 1394 | if (data.flipped && isSameAxis(data.originalPlacement, overflowDirection)) { 1395 | return true; 1396 | } 1397 | 1398 | if (!isSameAxis(data.originalPlacement, overflowDirection)) { 1399 | return true; 1400 | } 1401 | 1402 | return true; 1403 | } 1404 | 1405 | /** 1406 | * Determine if two placement values are on the same axis. 1407 | */ 1408 | function isSameAxis(a, b) { 1409 | // placement syntax: 1410 | // 1411 | // ( "top" | "right" | "bottom" | "left" ) ( "-start" | "" | "-end" ) 1412 | // |------------- Direction -------------| 1413 | // 1414 | var aDirection = a.split('-')[0]; 1415 | var bDirection = b.split('-')[0]; 1416 | 1417 | return aDirection === bDirection || aDirection === getOppositePlacement(b); 1418 | } 1419 | 1420 | /** 1421 | * Modifier used to shift the popper on the start or end of its reference element side 1422 | * @method 1423 | * @memberof Modifiers 1424 | * @argument {Object} data - The data object generated by `update` method 1425 | * @argument {Object} options - Modifiers configuration and options 1426 | * @returns {Object} The data object, properly modified 1427 | */ 1428 | function shift(data) { 1429 | var placement = data.placement; 1430 | var basePlacement = placement.split('-')[0]; 1431 | var shiftvariation = placement.split('-')[1]; 1432 | 1433 | // if shift shiftvariation is specified, run the modifier 1434 | if (shiftvariation) { 1435 | var reference = data.offsets.reference; 1436 | var popper = getClientRect(data.offsets.popper); 1437 | 1438 | var shiftOffsets = { 1439 | y: { 1440 | start: { top: reference.top }, 1441 | end: { top: reference.top + reference.height - popper.height } 1442 | }, 1443 | x: { 1444 | start: { left: reference.left }, 1445 | end: { left: reference.left + reference.width - popper.width } 1446 | } 1447 | }; 1448 | 1449 | var axis = ['bottom', 'top'].indexOf(basePlacement) !== -1 ? 'x' : 'y'; 1450 | 1451 | data.offsets.popper = _extends({}, popper, shiftOffsets[axis][shiftvariation]); 1452 | } 1453 | 1454 | return data; 1455 | } 1456 | 1457 | /** 1458 | * Modifier used to hide the popper when its reference element is outside of the 1459 | * popper boundaries. It will set an x-hidden attribute which can be used to hide 1460 | * the popper when its reference is out of boundaries. 1461 | * @method 1462 | * @memberof Modifiers 1463 | * @argument {Object} data - The data object generated by update method 1464 | * @argument {Object} options - Modifiers configuration and options 1465 | * @returns {Object} The data object, properly modified 1466 | */ 1467 | function hide(data) { 1468 | if (!isModifierRequired(data.instance.modifiers, 'hide', 'preventOverflow')) { 1469 | console.warn('WARNING: preventOverflow modifier is required by hide modifier in order to work, be sure to include it before hide!'); 1470 | return data; 1471 | } 1472 | 1473 | var refRect = data.offsets.reference; 1474 | var bound = findIndex$1(data.instance.modifiers, function (modifier) { 1475 | return modifier.name === 'preventOverflow'; 1476 | }).boundaries; 1477 | 1478 | if (refRect.bottom < bound.top || refRect.left > bound.right || refRect.top > bound.bottom || refRect.right < bound.left) { 1479 | // Avoid unnecessary DOM access if visibility hasn't changed 1480 | if (data.hide === true) { 1481 | return data; 1482 | } 1483 | 1484 | data.hide = true; 1485 | data.attributes['x-out-of-boundaries'] = ''; 1486 | } else { 1487 | // Avoid unnecessary DOM access if visibility hasn't changed 1488 | if (data.hide === false) { 1489 | return data; 1490 | } 1491 | 1492 | data.hide = false; 1493 | data.attributes['x-out-of-boundaries'] = false; 1494 | } 1495 | 1496 | return data; 1497 | } 1498 | 1499 | /** 1500 | * Modifier used to make the popper flow toward the inner of the reference element. 1501 | * By default, when this modifier is disabled, the popper will be placed outside 1502 | * the reference element. 1503 | * @method 1504 | * @memberof Modifiers 1505 | * @argument {Object} data - The data object generated by `update` method 1506 | * @argument {Object} options - Modifiers configuration and options 1507 | * @returns {Object} The data object, properly modified 1508 | */ 1509 | function inner(data) { 1510 | var placement = data.placement; 1511 | var basePlacement = placement.split('-')[0]; 1512 | var popper = getClientRect(data.offsets.popper); 1513 | var reference = getClientRect(data.offsets.reference); 1514 | var isHoriz = ['left', 'right'].indexOf(basePlacement) !== -1; 1515 | 1516 | var subtractLength = ['top', 'left'].indexOf(basePlacement) === -1; 1517 | 1518 | popper[isHoriz ? 'left' : 'top'] = reference[placement] - (subtractLength ? popper[isHoriz ? 'width' : 'height'] : 0); 1519 | 1520 | data.placement = getOppositePlacement(placement); 1521 | data.offsets.popper = getClientRect(popper); 1522 | 1523 | return data; 1524 | } 1525 | 1526 | /** 1527 | * Modifiers are plugins used to alter the behavior of your poppers. 1528 | * Popper.js uses a set of 7 modifiers to provide all the basic functionalities 1529 | * needed by the library. 1530 | * 1531 | * Each modifier is an object containing several properties listed below. 1532 | * @namespace Modifiers 1533 | * @param {Object} modifier - Modifier descriptor 1534 | * @param {Integer} modifier.order 1535 | * The `order` property defines the execution order of the modifiers. 1536 | * The built-in modifiers have orders with a gap of 100 units in between, 1537 | * this allows you to inject additional modifiers between the existing ones 1538 | * without having to redefine the order of all of them. 1539 | * The modifiers are executed starting from the one with the lowest order. 1540 | * @param {Boolean} modifier.enabled - When `true`, the modifier will be used. 1541 | * @param {Modifiers~modifier} modifier.function - Modifier function. 1542 | * @param {Modifiers~onLoad} modifier.onLoad - Function executed on popper initalization 1543 | * @return {Object} data - Each modifier must return the modified `data` object. 1544 | */ 1545 | var modifiers = { 1546 | shift: { 1547 | order: 100, 1548 | enabled: true, 1549 | function: shift 1550 | }, 1551 | offset: { 1552 | order: 200, 1553 | enabled: true, 1554 | function: offset, 1555 | // nudges popper from its origin by the given amount of pixels (can be negative) 1556 | offset: 0 1557 | }, 1558 | preventOverflow: { 1559 | order: 300, 1560 | enabled: true, 1561 | function: preventOverflow, 1562 | // popper will try to prevent overflow following these priorities 1563 | // by default, then, it could overflow on the left and on top of the boundariesElement 1564 | priority: ['left', 'right', 'top', 'bottom'], 1565 | // amount of pixel used to define a minimum distance between the boundaries and the popper 1566 | // this makes sure the popper has always a little padding between the edges of its container 1567 | padding: 5, 1568 | boundariesElement: 'scrollParent' 1569 | }, 1570 | keepTogether: { 1571 | order: 400, 1572 | enabled: true, 1573 | function: keepTogether 1574 | }, 1575 | arrow: { 1576 | order: 500, 1577 | enabled: true, 1578 | function: arrow, 1579 | // selector or node used as arrow 1580 | element: '[x-arrow]' 1581 | }, 1582 | flip: { 1583 | order: 600, 1584 | enabled: true, 1585 | function: flip, 1586 | // the behavior used to change the popper's placement 1587 | behavior: 'flip', 1588 | // the popper will flip if it hits the edges of the boundariesElement - padding 1589 | padding: 5, 1590 | boundariesElement: 'viewport' 1591 | }, 1592 | inner: { 1593 | order: 700, 1594 | enabled: false, 1595 | function: inner 1596 | }, 1597 | hide: { 1598 | order: 800, 1599 | enabled: true, 1600 | function: hide 1601 | }, 1602 | applyStyle: { 1603 | order: 900, 1604 | enabled: true, 1605 | // if true, it uses the CSS 3d transformation to position the popper 1606 | gpuAcceleration: true, 1607 | function: applyStyle, 1608 | onLoad: applyStyleOnLoad 1609 | } 1610 | }; 1611 | 1612 | /** 1613 | * Modifiers can edit the `data` object to change the beheavior of the popper. 1614 | * This object contains all the informations used by Popper.js to compute the 1615 | * popper position. 1616 | * The modifier can edit the data as needed, and then `return` it as result. 1617 | * 1618 | * @callback Modifiers~modifier 1619 | * @param {dataObject} data 1620 | * @return {dataObject} modified data 1621 | */ 1622 | 1623 | /** 1624 | * The `dataObject` is an object containing all the informations used by Popper.js 1625 | * this object get passed to modifiers and to the `onCreate` and `onUpdate` callbacks. 1626 | * @name dataObject 1627 | * @property {Object} data.instance The Popper.js instance 1628 | * @property {String} data.placement Placement applied to popper 1629 | * @property {String} data.originalPlacement Placement originally defined on init 1630 | * @property {Boolean} data.flipped True if popper has been flipped by flip modifier 1631 | * @property {Boolean} data.hide True if the reference element is out of boundaries, useful to know when to hide the popper. 1632 | * @property {HTMLElement} data.arrowElement Node used as arrow by arrow modifier 1633 | * @property {Object} data.styles Any CSS property defined here will be applied to the popper, it expects the JavaScript nomenclature (eg. `marginBottom`) 1634 | * @property {Object} data.boundaries Offsets of the popper boundaries 1635 | * @property {Object} data.offsets The measurements of popper, reference and arrow elements. 1636 | * @property {Object} data.offsets.popper `top`, `left`, `width`, `height` values 1637 | * @property {Object} data.offsets.reference `top`, `left`, `width`, `height` values 1638 | * @property {Object} data.offsets.arro] `top` and `left` offsets, only one of them will be different from 0 1639 | */ 1640 | 1641 | // Utils 1642 | // Modifiers 1643 | // default options 1644 | var DEFAULTS = { 1645 | // placement of the popper 1646 | placement: 'bottom', 1647 | 1648 | // whether events (resize, scroll) are initially enabled 1649 | eventsEnabled: true, 1650 | 1651 | /** 1652 | * Callback called when the popper is created. 1653 | * By default, is set to no-op. 1654 | * Access Popper.js instance with `data.instance`. 1655 | * @callback createCallback 1656 | * @static 1657 | * @param {dataObject} data 1658 | */ 1659 | onCreate: function onCreate() {}, 1660 | 1661 | /** 1662 | * Callback called when the popper is updated, this callback is not called 1663 | * on the initialization/creation of the popper, but only on subsequent 1664 | * updates. 1665 | * By default, is set to no-op. 1666 | * Access Popper.js instance with `data.instance`. 1667 | * @callback updateCallback 1668 | * @static 1669 | * @param {dataObject} data 1670 | */ 1671 | onUpdate: function onUpdate() {}, 1672 | 1673 | // list of functions used to modify the offsets before they are applied to the popper 1674 | modifiers: modifiers 1675 | }; 1676 | 1677 | /** 1678 | * Create a new Popper.js instance 1679 | * @class Popper 1680 | * @param {HTMLElement} reference - The reference element used to position the popper 1681 | * @param {HTMLElement} popper - The HTML element used as popper. 1682 | * @param {Object} options 1683 | * @param {String} options.placement=bottom 1684 | * Placement of the popper accepted values: `top(-start, -end), right(-start, -end), bottom(-start, -right), 1685 | * left(-start, -end)` 1686 | * 1687 | * @param {Boolean} options.eventsEnabled=true 1688 | * Whether events (resize, scroll) are initially enabled 1689 | * @param {Boolean} options.gpuAcceleration=true 1690 | * When this property is set to true, the popper position will be applied using CSS3 translate3d, allowing the 1691 | * browser to use the GPU to accelerate the rendering. 1692 | * If set to false, the popper will be placed using `top` and `left` properties, not using the GPU. 1693 | * 1694 | * @param {Boolean} options.removeOnDestroy=false 1695 | * Set to true if you want to automatically remove the popper when you call the `destroy` method. 1696 | * 1697 | * @param {Object} options.modifiers 1698 | * List of functions used to modify the data before they are applied to the popper (see source code for default values) 1699 | * 1700 | * @param {Object} options.modifiers.arrow - Arrow modifier configuration 1701 | * @param {String|HTMLElement} options.modifiers.arrow.element='[x-arrow]' 1702 | * The DOM Node used as arrow for the popper, or a CSS selector used to get the DOM node. It must be child of 1703 | * its parent Popper. Popper.js will apply to the given element the style required to align the arrow with its 1704 | * reference element. 1705 | * By default, it will look for a child node of the popper with the `x-arrow` attribute. 1706 | * 1707 | * @param {Object} options.modifiers.offset - Offset modifier configuration 1708 | * @param {Number} options.modifiers.offset.offset=0 1709 | * Amount of pixels the popper will be shifted (can be negative). 1710 | * 1711 | * @param {Object} options.modifiers.preventOverflow - PreventOverflow modifier configuration 1712 | * @param {Array} [options.modifiers.preventOverflow.priority=['left', 'right', 'top', 'bottom']] 1713 | * Priority used when Popper.js tries to avoid overflows from the boundaries, they will be checked in order, 1714 | * this means that the last one will never overflow 1715 | * @param {String|HTMLElement} options.modifiers.preventOverflow.boundariesElement='scrollParent' 1716 | * Boundaries used by the modifier, can be `scrollParent`, `window`, `viewport` or any DOM element. 1717 | * @param {Number} options.modifiers.preventOverflow.padding=5 1718 | * Amount of pixel used to define a minimum distance between the boundaries and the popper 1719 | * this makes sure the popper has always a little padding between the edges of its container. 1720 | * 1721 | * @param {Object} options.modifiers.flip - Flip modifier configuration 1722 | * @param {String|Array} options.modifiers.flip.behavior='flip' 1723 | * The behavior used by the `flip` modifier to change the placement of the popper when the latter is trying to 1724 | * overlap its reference element. Defining `flip` as value, the placement will be flipped on 1725 | * its axis (`right - left`, `top - bottom`). 1726 | * You can even pass an array of placements (eg: `['right', 'left', 'top']` ) to manually specify 1727 | * how alter the placement when a flip is needed. (eg. in the above example, it would first flip from right to left, 1728 | * then, if even in its new placement, the popper is overlapping its reference element, it will be moved to top) 1729 | * @param {String|HTMLElement} options.modifiers.flip.boundariesElement='viewport' 1730 | * The element which will define the boundaries of the popper position, the popper will never be placed outside 1731 | * of the defined boundaries (except if `keepTogether` is enabled) 1732 | * 1733 | * @param {Object} options.modifiers.inner - Inner modifier configuration 1734 | * @param {Number} options.modifiers.innner.enabled=false 1735 | * Set to `true` to make the popper flow toward the inner of the reference element. 1736 | * 1737 | * @param {Number} options.modifiers.flip.padding=5 1738 | * Amount of pixel used to define a minimum distance between the boundaries and the popper 1739 | * this makes sure the popper has always a little padding between the edges of its container. 1740 | * 1741 | * @param {createCallback} options.onCreate - onCreate callback 1742 | * Function called after the Popper has been instantiated. 1743 | * 1744 | * @param {updateCallback} options.onUpdate - onUpdate callback 1745 | * Function called on subsequent updates of Popper. 1746 | * 1747 | * @return {Object} instance - The generated Popper.js instance 1748 | */ 1749 | 1750 | var Popper = function () { 1751 | function Popper(reference, popper) { 1752 | var _this = this; 1753 | 1754 | var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; 1755 | classCallCheck(this, Popper); 1756 | 1757 | this.scheduleUpdate = function () { 1758 | return requestAnimationFrame(_this.update); 1759 | }; 1760 | 1761 | // make update() debounced, so that it only runs at most once-per-tick 1762 | this.update = debounce(this.update.bind(this)); 1763 | 1764 | // with {} we create a new object with the options inside it 1765 | this.options = _extends({}, Popper.Defaults, options); 1766 | 1767 | // init state 1768 | this.state = { 1769 | isDestroyed: false, 1770 | isCreated: false 1771 | }; 1772 | 1773 | // get reference and popper elements (allow jQuery wrappers) 1774 | this.reference = reference.jquery ? reference[0] : reference; 1775 | this.popper = popper.jquery ? popper[0] : popper; 1776 | 1777 | // refactoring modifiers' list (Object => Array) 1778 | this.modifiers = Object.keys(Popper.Defaults.modifiers).map(function (name) { 1779 | return _extends({ name: name }, Popper.Defaults.modifiers[name]); 1780 | }); 1781 | 1782 | // assign default values to modifiers, making sure to override them with 1783 | // the ones defined by user 1784 | this.modifiers = this.modifiers.map(function (defaultConfig) { 1785 | var userConfig = options.modifiers && options.modifiers[defaultConfig.name] || {}; 1786 | return _extends({}, defaultConfig, userConfig); 1787 | }); 1788 | 1789 | // add custom modifiers to the modifiers list 1790 | if (options.modifiers) { 1791 | this.options.modifiers = _extends({}, Popper.Defaults.modifiers, options.modifiers); 1792 | Object.keys(options.modifiers).forEach(function (name) { 1793 | // take in account only custom modifiers 1794 | if (Popper.Defaults.modifiers[name] === undefined) { 1795 | var modifier = options.modifiers[name]; 1796 | modifier.name = name; 1797 | _this.modifiers.push(modifier); 1798 | } 1799 | }); 1800 | } 1801 | 1802 | // get the popper position type 1803 | this.state.position = getPosition(this.reference); 1804 | 1805 | // sort the modifiers by order 1806 | this.modifiers = this.modifiers.sort(function (a, b) { 1807 | return a.order - b.order; 1808 | }); 1809 | 1810 | // modifiers have the ability to execute arbitrary code when Popper.js get inited 1811 | // such code is executed in the same order of its modifier 1812 | // they could add new properties to their options configuration 1813 | // BE AWARE: don't add options to `options.modifiers.name` but to `modifierOptions`! 1814 | this.modifiers.forEach(function (modifierOptions) { 1815 | if (modifierOptions.enabled && isFunction(modifierOptions.onLoad)) { 1816 | modifierOptions.onLoad(_this.reference, _this.popper, _this.options, modifierOptions, _this.state); 1817 | } 1818 | }); 1819 | 1820 | // determine how we should set the origin of offsets 1821 | this.state.isParentTransformed = isTransformed(this.popper.parentNode); 1822 | 1823 | // fire the first update to position the popper in the right place 1824 | this.update(); 1825 | 1826 | var eventsEnabled = this.options.eventsEnabled; 1827 | if (eventsEnabled) { 1828 | // setup event listeners, they will take care of update the position in specific situations 1829 | this.enableEventListeners(); 1830 | } 1831 | 1832 | this.state.eventsEnabled = eventsEnabled; 1833 | } 1834 | 1835 | // 1836 | // Methods 1837 | // 1838 | 1839 | /** 1840 | * Updates the position of the popper, computing the new offsets and applying the new style 1841 | * Prefer `scheduleUpdate` over `update` because of performance reasons 1842 | * @method 1843 | * @memberof Popper 1844 | */ 1845 | 1846 | 1847 | createClass(Popper, [{ 1848 | key: 'update', 1849 | value: function update() { 1850 | // if popper is destroyed, don't perform any further update 1851 | if (this.state.isDestroyed) { 1852 | return; 1853 | } 1854 | 1855 | var data = { 1856 | instance: this, 1857 | styles: {}, 1858 | attributes: {}, 1859 | flipped: false, 1860 | offsets: {} 1861 | }; 1862 | 1863 | // make sure to apply the popper position before any computation 1864 | this.state.position = getPosition(this.reference); 1865 | setStyles(this.popper, { position: this.state.position }); 1866 | 1867 | // compute reference element offsets 1868 | data.offsets.reference = getReferenceOffsets(this.state, this.popper, this.reference); 1869 | 1870 | // compute auto placement, store placement inside the data object, 1871 | // modifiers will be able to edit `placement` if needed 1872 | // and refer to originalPlacement to know the original value 1873 | data.placement = computeAutoPlacement(this.options.placement, data.offsets.reference, this.popper); 1874 | 1875 | // store the computed placement inside `originalPlacement` 1876 | data.originalPlacement = this.options.placement; 1877 | 1878 | // compute the popper offsets 1879 | data.offsets.popper = getPopperOffsets(this.state, this.popper, data.offsets.reference, data.placement); 1880 | 1881 | // run the modifiers 1882 | data = runModifiers(this.modifiers, data); 1883 | 1884 | // the first `update` will call `onCreate` callback 1885 | // the other ones will call `onUpdate` callback 1886 | if (!this.state.isCreated) { 1887 | this.state.isCreated = true; 1888 | this.options.onCreate(data); 1889 | } else { 1890 | this.options.onUpdate(data); 1891 | } 1892 | } 1893 | 1894 | /** 1895 | * Schedule an update, it will run on the next UI update available 1896 | * @method 1897 | * @memberof Popper 1898 | */ 1899 | 1900 | }, { 1901 | key: 'destroy', 1902 | 1903 | 1904 | /** 1905 | * Destroy the popper 1906 | * @method 1907 | * @memberof Popper 1908 | */ 1909 | value: function destroy() { 1910 | this.state.isDestroyed = true; 1911 | 1912 | // touch DOM only if `applyStyle` modifier is enabled 1913 | if (isModifierEnabled(this.modifiers, 'applyStyle')) { 1914 | this.popper.removeAttribute('x-placement'); 1915 | this.popper.style.left = ''; 1916 | this.popper.style.position = ''; 1917 | this.popper.style.top = ''; 1918 | this.popper.style[getSupportedPropertyName('transform')] = ''; 1919 | } 1920 | 1921 | this.disableEventListeners(); 1922 | 1923 | // remove the popper if user explicity asked for the deletion on destroy 1924 | // do not use `remove` because IE11 doesn't support it 1925 | if (this.options.removeOnDestroy) { 1926 | this.popper.parentNode.removeChild(this.popper); 1927 | } 1928 | return this; 1929 | } 1930 | 1931 | /** 1932 | * it will add resize/scroll events and start recalculating 1933 | * position of the popper element when they are triggered 1934 | * @method 1935 | * @memberof Popper 1936 | */ 1937 | 1938 | }, { 1939 | key: 'enableEventListeners', 1940 | value: function enableEventListeners() { 1941 | if (!this.state.eventsEnabled) { 1942 | this.state = setupEventListeners(this.reference, this.options, this.state, this.scheduleUpdate); 1943 | } 1944 | } 1945 | 1946 | /** 1947 | * it will remove resize/scroll events and won't recalculate 1948 | * popper position when they are triggered. It also won't trigger onUpdate callback anymore, 1949 | * unless you call 'update' method manually. 1950 | * @method 1951 | * @memberof Popper 1952 | */ 1953 | 1954 | }, { 1955 | key: 'disableEventListeners', 1956 | value: function disableEventListeners() { 1957 | if (this.state.eventsEnabled) { 1958 | cancelAnimationFrame(this.scheduledUpdate); 1959 | this.state = removeEventListeners(this.reference, this.state); 1960 | } 1961 | } 1962 | 1963 | /** 1964 | * Collection of utilities useful when writing custom modifiers 1965 | * @memberof Popper 1966 | */ 1967 | 1968 | 1969 | /** 1970 | * List of accepted placements to use as values of the `placement` option 1971 | * @memberof Popper 1972 | */ 1973 | 1974 | 1975 | /** 1976 | * Default Popper.js options 1977 | * @memberof Popper 1978 | */ 1979 | 1980 | }]); 1981 | return Popper; 1982 | }(); 1983 | 1984 | Popper.Utils = Utils; 1985 | Popper.placements = ['auto', 'auto-start', 'auto-end', 'top', 'top-start', 'top-end', 'right', 'right-start', 'right-end', 'bottom', 'bottom-start', 'bottom-end', 'left', 'left-start', 'left-end']; 1986 | Popper.Defaults = DEFAULTS; 1987 | 1988 | return Popper; 1989 | 1990 | }))); 1991 | 1992 | 1993 | },{}],2:[function(require,module,exports){ 1994 | 'use strict'; 1995 | 1996 | var Popper = require('popper.js'); 1997 | 1998 | module.exports = { 1999 | 2000 | props: { 2001 | showPopper: { 2002 | type: Boolean, 2003 | required: false, 2004 | default: false 2005 | }, 2006 | placement: { 2007 | type: String, 2008 | required: false, 2009 | default: 'top' 2010 | }, 2011 | content: { 2012 | type: String, 2013 | required: false, 2014 | default: '' 2015 | }, 2016 | closeButton: { 2017 | type: String, 2018 | required: false, 2019 | default: null 2020 | } 2021 | }, 2022 | 2023 | data: function data() { 2024 | return { 2025 | popperId: null, 2026 | popper: null 2027 | }; 2028 | }, 2029 | ready: function ready() { 2030 | var _this = this; 2031 | 2032 | this.$nextTick(function () { 2033 | if (_this.showPopper) { 2034 | _this.initPopper(); 2035 | } 2036 | }); 2037 | }, 2038 | 2039 | 2040 | watch: { 2041 | showPopper: function showPopper(val, oldVal) { 2042 | var _this2 = this; 2043 | 2044 | if (!!this.showPopper) { 2045 | this.$nextTick(function () { 2046 | _this2.initPopper(); 2047 | }); 2048 | } 2049 | } 2050 | }, 2051 | 2052 | destroyed: function destroyed() { 2053 | this.destroyPopper(); 2054 | }, 2055 | 2056 | 2057 | methods: { 2058 | initPopper: function initPopper() { 2059 | this.popperId = this.uuid4(); 2060 | this.popper = new Popper(this.$el, this.$el.querySelector('.vue-popper-component'), { 2061 | placement: this.placement || 'bottom', 2062 | removeOnDestroy: true 2063 | }); 2064 | }, 2065 | destroyPopper: function destroyPopper() { 2066 | if (this.popper) { 2067 | this.popper.destroy(); 2068 | this.popper = null; 2069 | } 2070 | }, 2071 | uuid4: function uuid4() { 2072 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 2073 | var r = Math.random() * 16 | 0, 2074 | v = c === 'x' ? r : r & 0x3 | 0x8; 2075 | return v.toString(16); 2076 | }); 2077 | } 2078 | } 2079 | }; 2080 | if (module.exports.__esModule) module.exports = module.exports.default 2081 | ;(typeof module.exports === "function"? module.exports.options: module.exports).template = "
{{ content }}
" 2082 | 2083 | },{"popper.js":1}]},{},[2])(2) 2084 | }); --------------------------------------------------------------------------------