uikit 3.14.1-dev.eeb4cd6ae → 3.14.2-dev.35b3deec9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/CHANGELOG.md +45 -3
  2. package/build/util.js +8 -2
  3. package/dist/css/uikit-core-rtl.css +93 -21
  4. package/dist/css/uikit-core-rtl.min.css +1 -1
  5. package/dist/css/uikit-core.css +93 -21
  6. package/dist/css/uikit-core.min.css +1 -1
  7. package/dist/css/uikit-rtl.css +99 -33
  8. package/dist/css/uikit-rtl.min.css +1 -1
  9. package/dist/css/uikit.css +99 -33
  10. package/dist/css/uikit.min.css +1 -1
  11. package/dist/js/components/countdown.js +1 -1
  12. package/dist/js/components/countdown.min.js +1 -1
  13. package/dist/js/components/filter.js +2 -2
  14. package/dist/js/components/filter.min.js +1 -1
  15. package/dist/js/components/lightbox-panel.js +111 -15
  16. package/dist/js/components/lightbox-panel.min.js +1 -1
  17. package/dist/js/components/lightbox.js +111 -15
  18. package/dist/js/components/lightbox.min.js +1 -1
  19. package/dist/js/components/notification.js +1 -1
  20. package/dist/js/components/notification.min.js +1 -1
  21. package/dist/js/components/parallax.js +18 -3
  22. package/dist/js/components/parallax.min.js +1 -1
  23. package/dist/js/components/slider-parallax.js +2 -2
  24. package/dist/js/components/slider-parallax.min.js +1 -1
  25. package/dist/js/components/slider.js +1 -1
  26. package/dist/js/components/slider.min.js +1 -1
  27. package/dist/js/components/slideshow-parallax.js +2 -2
  28. package/dist/js/components/slideshow-parallax.min.js +1 -1
  29. package/dist/js/components/slideshow.js +1 -1
  30. package/dist/js/components/slideshow.min.js +1 -1
  31. package/dist/js/components/sortable.js +1 -1
  32. package/dist/js/components/sortable.min.js +1 -1
  33. package/dist/js/components/tooltip.js +147 -34
  34. package/dist/js/components/tooltip.min.js +1 -1
  35. package/dist/js/components/upload.js +1 -1
  36. package/dist/js/components/upload.min.js +1 -1
  37. package/dist/js/uikit-core.js +280 -132
  38. package/dist/js/uikit-core.min.js +1 -1
  39. package/dist/js/uikit-icons.js +1 -1
  40. package/dist/js/uikit-icons.min.js +1 -1
  41. package/dist/js/uikit.js +298 -135
  42. package/dist/js/uikit.min.js +1 -1
  43. package/package.json +11 -11
  44. package/src/js/api/hooks.js +1 -1
  45. package/src/js/components/filter.js +1 -1
  46. package/src/js/components/parallax.js +16 -1
  47. package/src/js/core/accordion.js +3 -3
  48. package/src/js/core/alert.js +1 -1
  49. package/src/js/core/drop.js +47 -18
  50. package/src/js/core/height-viewport.js +15 -11
  51. package/src/js/core/margin.js +1 -1
  52. package/src/js/core/navbar.js +19 -18
  53. package/src/js/core/scrollspy.js +6 -1
  54. package/src/js/core/toggle.js +9 -8
  55. package/src/js/mixin/parallax.js +1 -1
  56. package/src/js/mixin/position.js +36 -20
  57. package/src/js/mixin/togglable.js +116 -18
  58. package/src/js/util/animation.js +1 -0
  59. package/src/js/util/position.js +24 -22
  60. package/src/js/util/viewport.js +7 -14
  61. package/src/less/components/drop.less +19 -4
  62. package/src/less/components/dropdown.less +21 -4
  63. package/src/less/components/margin.less +13 -14
  64. package/src/less/components/modal.less +19 -4
  65. package/src/less/components/nav.less +1 -1
  66. package/src/less/components/navbar.less +60 -19
  67. package/src/less/components/offcanvas.less +21 -21
  68. package/src/less/components/position.less +1 -1
  69. package/src/less/components/sticky.less +7 -0
  70. package/src/less/components/tooltip.less +1 -0
  71. package/src/less/components/utility.less +1 -2
  72. package/src/less/theme/dropdown.less +11 -0
  73. package/src/less/theme/navbar.less +10 -10
  74. package/src/scss/components/drop.scss +19 -4
  75. package/src/scss/components/dropdown.scss +21 -4
  76. package/src/scss/components/margin.scss +13 -14
  77. package/src/scss/components/modal.scss +19 -4
  78. package/src/scss/components/nav.scss +1 -1
  79. package/src/scss/components/navbar.scss +49 -8
  80. package/src/scss/components/offcanvas.scss +21 -21
  81. package/src/scss/components/position.scss +1 -1
  82. package/src/scss/components/sticky.scss +7 -0
  83. package/src/scss/components/tooltip.scss +1 -0
  84. package/src/scss/components/utility.scss +1 -2
  85. package/src/scss/mixins-theme.scss +8 -10
  86. package/src/scss/mixins.scss +2 -0
  87. package/src/scss/theme/dropdown.scss +8 -0
  88. package/src/scss/theme/navbar.scss +7 -0
  89. package/src/scss/variables-theme.scss +26 -11
  90. package/src/scss/variables.scss +24 -11
  91. package/tests/drop.html +165 -4
  92. package/tests/dropdown.html +234 -13
  93. package/tests/height-viewport.html +62 -0
  94. package/tests/navbar.html +333 -64
  95. package/tests/notification.html +1 -1
  96. package/tests/offcanvas.html +8 -8
  97. package/tests/sticky-navbar.html +132 -0
  98. package/tests/sticky-parallax.html +2 -1
  99. package/tests/sticky.html +5 -4
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "uikit",
3
3
  "title": "UIkit",
4
4
  "description": "UIkit is a lightweight and modular front-end framework for developing fast and powerful web interfaces.",
5
- "version": "3.14.1-dev.eeb4cd6ae",
5
+ "version": "3.14.2-dev.35b3deec9",
6
6
  "main": "dist/js/uikit.js",
7
7
  "style": "dist/css/uikit.css",
8
8
  "sideEffects": [
@@ -34,32 +34,32 @@
34
34
  },
35
35
  "homepage": "https://getuikit.com",
36
36
  "devDependencies": {
37
- "@babel/core": "^7.17.8",
38
- "@babel/preset-env": "^7.16.4",
37
+ "@babel/core": "^7.17.10",
38
+ "@babel/preset-env": "^7.17.10",
39
39
  "@rollup/plugin-alias": "^3.1.9",
40
40
  "@rollup/plugin-babel": "^5.3.1",
41
41
  "@rollup/plugin-replace": "^4.0.0",
42
- "archiver": "^5.3.0",
42
+ "archiver": "^5.3.1",
43
43
  "camelcase": "^6.3.0",
44
44
  "clean-css": "^5.3.0",
45
45
  "dateformat": "^5.0.3",
46
- "esbuild": "^0.14.32",
47
- "eslint": "^8.12.0",
46
+ "esbuild": "^0.14.38",
47
+ "eslint": "^8.15.0",
48
48
  "eslint-config-prettier": "^8.5.0",
49
- "fs-extra": "^10.0.1",
50
- "glob": "^7.2.0",
51
- "inquirer": "^8.2.2",
49
+ "fs-extra": "^10.1.0",
50
+ "glob": "^8.0.1",
51
+ "inquirer": "^8.2.4",
52
52
  "less": "^4.1.2",
53
53
  "minimist": "^1.2.6",
54
54
  "number-precision": "^1.5.2",
55
55
  "p-limit": "^4.0.0",
56
56
  "prettier": "^2.6.2",
57
- "rollup": "^2.70.1",
57
+ "rollup": "^2.72.1",
58
58
  "rollup-plugin-esbuild": "^4.9.1",
59
59
  "rollup-plugin-html": "^0.2.1",
60
60
  "rollup-plugin-modify": "^3.0.0",
61
61
  "rtlcss": "^3.5.0",
62
- "semver": "^7.3.2",
62
+ "semver": "^7.3.7",
63
63
  "svgo": "^2.8.0",
64
64
  "watch-run": "^1.2.5"
65
65
  }
@@ -105,7 +105,7 @@ export default function (UIkit) {
105
105
  const {
106
106
  $options: { computed },
107
107
  } = this;
108
- const values = { ...(initial ? {} : this._computed) };
108
+ const values = { ...this._computed };
109
109
  this._computed = {};
110
110
 
111
111
  for (const key in computed) {
@@ -194,7 +194,7 @@ function matchFilter(
194
194
  }
195
195
 
196
196
  function isEqualList(listA, listB) {
197
- return listA.length === listB.length && listA.every((el) => ~listB.indexOf(el));
197
+ return listA.length === listB.length && listA.every((el) => listB.includes(el));
198
198
  }
199
199
 
200
200
  function getSelector({ filter }) {
@@ -73,8 +73,23 @@ export default {
73
73
  },
74
74
  };
75
75
 
76
+ /*
77
+ * Inspired by https://gist.github.com/gre/1650294?permalink_comment_id=3477425#gistcomment-3477425
78
+ *
79
+ * linear: 0
80
+ * easeInSine: 0.5
81
+ * easeOutSine: -0.5
82
+ * easeInQuad: 1
83
+ * easeOutQuad: -1
84
+ * easeInCubic: 2
85
+ * easeOutCubic: -2
86
+ * easeInQuart: 3
87
+ * easeOutQuart: -3
88
+ * easeInQuint: 4
89
+ * easeOutQuint: -4
90
+ */
76
91
  function ease(percent, easing) {
77
- return easing >= 0 ? Math.pow(percent, easing + 1) : 1 - Math.pow(1 - percent, -easing + 1);
92
+ return easing >= 0 ? Math.pow(percent, easing + 1) : 1 - Math.pow(1 - percent, 1 - easing);
78
93
  }
79
94
 
80
95
  // SVG elements do not inherit from HTMLElement
@@ -1,6 +1,6 @@
1
1
  import Class from '../mixin/class';
2
2
  import Lazyload from '../mixin/lazyload';
3
- import { default as Togglable, toggleHeight } from '../mixin/togglable';
3
+ import { slide, default as Togglable } from '../mixin/togglable';
4
4
  import {
5
5
  $,
6
6
  $$,
@@ -34,7 +34,7 @@ export default {
34
34
  data: {
35
35
  targets: '> *',
36
36
  active: false,
37
- animation: [true],
37
+ animation: ['slide'],
38
38
  collapsible: true,
39
39
  multiple: false,
40
40
  clsOpen: 'uk-open',
@@ -144,7 +144,7 @@ export default {
144
144
  }
145
145
 
146
146
  hide(content, false);
147
- await toggleHeight(this)(el._wrapper, show);
147
+ await slide(this)(el._wrapper, show);
148
148
  hide(content, !show);
149
149
 
150
150
  delete el._wrapper;
@@ -11,7 +11,7 @@ export default {
11
11
  },
12
12
 
13
13
  data: {
14
- animation: [true],
14
+ animation: ['slide'],
15
15
  selClose: '.uk-alert-close',
16
16
  duration: 150,
17
17
  hideProps: { opacity: 0, ...Togglable.data.hideProps },
@@ -47,6 +47,7 @@ export default {
47
47
  delayHide: Number,
48
48
  display: String,
49
49
  clsDrop: String,
50
+ animateOut: Boolean,
50
51
  },
51
52
 
52
53
  data: {
@@ -61,6 +62,7 @@ export default {
61
62
  animation: ['uk-animation-fade'],
62
63
  cls: 'uk-open',
63
64
  container: false,
65
+ animateOut: false,
64
66
  },
65
67
 
66
68
  created() {
@@ -248,7 +250,7 @@ export default {
248
250
  }
249
251
  }),
250
252
 
251
- ...(this.display === 'static'
253
+ ...(this.display === 'static' && this.align !== 'stretch'
252
254
  ? []
253
255
  : (() => {
254
256
  const handler = () => this.$emit();
@@ -309,7 +311,7 @@ export default {
309
311
  methods: {
310
312
  show(target = this.target, delay = true) {
311
313
  if (this.isToggled() && target && this.target && target !== this.target) {
312
- this.hide(false);
314
+ this.hide(false, false);
313
315
  }
314
316
 
315
317
  this.target = target;
@@ -329,7 +331,7 @@ export default {
329
331
  let prev;
330
332
  while (active && prev !== active && !within(this.$el, active.$el)) {
331
333
  prev = active;
332
- active.hide(false);
334
+ active.hide(false, false);
333
335
  }
334
336
  }
335
337
 
@@ -343,8 +345,8 @@ export default {
343
345
  );
344
346
  },
345
347
 
346
- hide(delay = true) {
347
- const hide = () => this.toggleElement(this.$el, false, false);
348
+ hide(delay = true, animate = true) {
349
+ const hide = () => this.toggleElement(this.$el, false, this.animateOut && animate);
348
350
 
349
351
  this.clearTimers();
350
352
 
@@ -376,32 +378,59 @@ export default {
376
378
  position() {
377
379
  removeClass(this.$el, `${this.clsDrop}-stack`);
378
380
  toggleClass(this.$el, `${this.clsDrop}-boundary`, this.boundaryAlign);
381
+ toggleClass(this.$el, `${this.clsDrop}-stretch`, this.align === 'stretch');
379
382
 
380
383
  const boundary = query(this.boundary, this.$el);
381
- const [scrollParent] = scrollParents(this.$el);
382
- const scrollParentOffset = offsetViewport(scrollParent);
384
+ const target = boundary && this.boundaryAlign ? boundary : this.target;
385
+ const [scrollParent] = scrollParents(
386
+ boundary && this.boundaryAlign ? boundary : this.$el
387
+ );
388
+ const scrollParentOffset = offset(scrollParent);
383
389
  const boundaryOffset = boundary ? offset(boundary) : scrollParentOffset;
390
+ const viewportOffset = this.getViewportOffset(this.$el);
384
391
 
385
392
  css(this.$el, 'maxWidth', '');
386
- const maxWidth =
387
- scrollParentOffset.width - (this.boundaryAlign ? 0 : 2 * this.viewportPadding);
393
+ const maxWidth = scrollParentOffset.width - 2 * viewportOffset;
388
394
 
389
- if (this.pos[1] === 'justify') {
395
+ if (this.align === 'justify') {
390
396
  const prop = this.axis === 'y' ? 'width' : 'height';
391
- const targetOffset = offset(this.target);
392
- const alignTo = this.boundaryAlign ? boundaryOffset : targetOffset;
393
- css(this.$el, prop, alignTo[prop]);
397
+ css(
398
+ this.$el,
399
+ prop,
400
+ Math.min(
401
+ (boundary ? boundaryOffset : offset(this.target))[prop],
402
+ scrollParentOffset[prop] - 2 * viewportOffset
403
+ )
404
+ );
405
+ } else if (this.align === 'stretch') {
406
+ this.flip = this.axis === 'y' ? 'x' : 'y';
407
+ this.display = 'static';
408
+
409
+ const viewport = offsetViewport(scrollParent);
410
+ const targetDim = offset(target);
411
+ const elOffset = Math.abs(this.getPositionOffset(this.$el)) + viewportOffset;
412
+
413
+ css(this.$el, {
414
+ width:
415
+ this.axis === 'y'
416
+ ? viewport.width
417
+ : (this.dir === 'left'
418
+ ? targetDim.left - viewport.left
419
+ : viewport.right - targetDim.right) - elOffset,
420
+ height:
421
+ this.axis === 'x'
422
+ ? viewport.height
423
+ : (this.dir === 'top'
424
+ ? targetDim.top - viewport.top
425
+ : viewport.bottom - targetDim.bottom) - elOffset,
426
+ });
394
427
  } else if (this.$el.offsetWidth > maxWidth) {
395
428
  addClass(this.$el, `${this.clsDrop}-stack`);
396
429
  }
397
430
 
398
431
  css(this.$el, 'maxWidth', maxWidth);
399
432
 
400
- this.positionAt(
401
- this.$el,
402
- boundary && this.boundaryAlign ? boundary : this.target,
403
- boundary
404
- );
433
+ this.positionAt(this.$el, target, boundary);
405
434
  },
406
435
  },
407
436
  };
@@ -1,21 +1,21 @@
1
- import Class from '../mixin/class';
2
1
  import Resize from '../mixin/resize';
3
2
  import {
4
3
  boxModelAdjust,
5
4
  css,
6
5
  dimensions,
7
6
  endsWith,
8
- height,
9
7
  isNumeric,
10
8
  isString,
11
9
  isVisible,
12
- offset,
10
+ offsetPosition,
11
+ offsetViewport,
13
12
  query,
13
+ scrollParents,
14
14
  toFloat,
15
15
  } from 'uikit-util';
16
16
 
17
17
  export default {
18
- mixins: [Class, Resize],
18
+ mixins: [Resize],
19
19
 
20
20
  props: {
21
21
  expand: Boolean,
@@ -33,7 +33,7 @@ export default {
33
33
 
34
34
  resizeTargets() {
35
35
  // check for offsetTop change
36
- return [this.$el, document.documentElement];
36
+ return [this.$el, ...scrollParents(this.$el, /auto|scroll/)];
37
37
  },
38
38
 
39
39
  update: {
@@ -45,21 +45,25 @@ export default {
45
45
  let minHeight = '';
46
46
  const box = boxModelAdjust(this.$el, 'height', 'content-box');
47
47
 
48
+ const [scrollElement] = scrollParents(this.$el, /auto|scroll/);
49
+ const { height: viewportHeight } = offsetViewport(scrollElement);
50
+
48
51
  if (this.expand) {
49
52
  minHeight = Math.max(
50
- height(window) -
51
- (dimensions(document.documentElement).height -
52
- dimensions(this.$el).height) -
53
+ viewportHeight -
54
+ (dimensions(scrollElement).height - dimensions(this.$el).height) -
53
55
  box,
54
56
  0
55
57
  );
56
58
  } else {
57
59
  // on mobile devices (iOS and Android) window.innerHeight !== 100vh
58
- minHeight = 'calc(100vh';
60
+ minHeight = `calc(${
61
+ document.scrollingElement === scrollElement ? '100vh' : `${viewportHeight}px`
62
+ }`;
59
63
 
60
64
  if (this.offsetTop) {
61
- const { top } = offset(this.$el);
62
- minHeight += top > 0 && top < height(window) / 2 ? ` - ${top}px` : '';
65
+ const top = offsetPosition(this.$el)[0] - offsetPosition(scrollElement)[0];
66
+ minHeight += top > 0 && top < viewportHeight / 2 ? ` - ${top}px` : '';
63
67
  }
64
68
 
65
69
  if (this.offsetBottom === true) {
@@ -47,7 +47,7 @@ export default {
47
47
  for (const row of rows) {
48
48
  for (const column of row) {
49
49
  toggleClass(column, this.margin, rows[0] !== row);
50
- toggleClass(column, this.firstColumn, !!~columns[0].indexOf(column));
50
+ toggleClass(column, this.firstColumn, columns[0].includes(column));
51
51
  }
52
52
  }
53
53
  },
@@ -13,9 +13,9 @@ import {
13
13
  height,
14
14
  includes,
15
15
  isRtl,
16
- isVisible,
17
16
  matches,
18
17
  noop,
18
+ observeResize,
19
19
  offset,
20
20
  once,
21
21
  parent,
@@ -285,8 +285,8 @@ export default {
285
285
  return this.dropbar;
286
286
  },
287
287
 
288
- handler(_, { $el }) {
289
- if (!hasClass($el, this.clsDrop)) {
288
+ handler(_, { $el, align }) {
289
+ if (!hasClass($el, this.clsDrop) || align === 'stretch') {
290
290
  return;
291
291
  }
292
292
 
@@ -309,19 +309,19 @@ export default {
309
309
  return this.dropbar;
310
310
  },
311
311
 
312
- handler(_, { $el, pos: [dir] = [] }) {
313
- if (!hasClass($el, this.clsDrop)) {
312
+ handler(_, { $el, align }) {
313
+ if (!hasClass($el, this.clsDrop) || align === 'stretch') {
314
314
  return;
315
315
  }
316
316
 
317
- if (dir === 'bottom') {
317
+ this._observer = observeResize($el, () =>
318
318
  this.transitionTo(
319
319
  offset($el).bottom -
320
320
  offset(this.dropbar).top +
321
321
  toFloat(css($el, 'marginBottom')),
322
322
  $el
323
- );
324
- }
323
+ )
324
+ );
325
325
  },
326
326
  },
327
327
 
@@ -360,11 +360,13 @@ export default {
360
360
  return this.dropbar;
361
361
  },
362
362
 
363
- handler(_, { $el }) {
364
- if (!hasClass($el, this.clsDrop)) {
363
+ handler(_, { $el, align }) {
364
+ if (!hasClass($el, this.clsDrop) || align === 'stretch') {
365
365
  return;
366
366
  }
367
367
 
368
+ this._observer.disconnect();
369
+
368
370
  const active = this.getActive();
369
371
 
370
372
  if (!active || active?.$el === $el) {
@@ -381,28 +383,27 @@ export default {
381
383
 
382
384
  transitionTo(newHeight, el) {
383
385
  const { dropbar } = this;
384
- const oldHeight = isVisible(dropbar) ? height(dropbar) : 0;
386
+ const oldHeight = height(dropbar);
385
387
 
386
388
  el = oldHeight < newHeight && el;
387
389
 
388
- css(el, 'clip', `rect(0,${el.offsetWidth}px,${oldHeight}px,0)`);
390
+ css(el, 'clipPath', `polygon(0 0,100% 0,100% ${oldHeight}px,0 ${oldHeight}px)`);
389
391
 
390
392
  height(dropbar, oldHeight);
391
393
 
392
394
  Transition.cancel([el, dropbar]);
393
- return Promise.all([
395
+ Promise.all([
394
396
  Transition.start(dropbar, { height: newHeight }, this.duration),
395
397
  Transition.start(
396
398
  el,
397
- { clip: `rect(0,${el.offsetWidth}px,${newHeight}px,0)` },
399
+ {
400
+ clipPath: `polygon(0 0,100% 0,100% ${newHeight}px,0 ${newHeight}px)`,
401
+ },
398
402
  this.duration
399
403
  ),
400
404
  ])
401
405
  .catch(noop)
402
- .then(() => {
403
- css(el, { clip: '' });
404
- this.$update(dropbar);
405
- });
406
+ .then(() => css(el, { clipPath: '' }));
406
407
  },
407
408
 
408
409
  getDropdown(el) {
@@ -4,6 +4,7 @@ import {
4
4
  css,
5
5
  filter,
6
6
  data as getData,
7
+ isEqual,
7
8
  observeIntersection,
8
9
  once,
9
10
  removeClass,
@@ -50,7 +51,7 @@ export default {
50
51
  css(filter(elements, `:not(.${this.inViewClass})`), 'visibility', 'hidden');
51
52
  }
52
53
 
53
- if (prev) {
54
+ if (!isEqual(elements, prev)) {
54
55
  this.$reset();
55
56
  }
56
57
  },
@@ -127,6 +128,10 @@ export default {
127
128
  toggle(el, inview) {
128
129
  const state = this._data.elements.get(el);
129
130
 
131
+ if (!state) {
132
+ return;
133
+ }
134
+
130
135
  state.off?.();
131
136
 
132
137
  css(el, 'visibility', !inview && this.hidden ? 'hidden' : '');
@@ -77,6 +77,8 @@ export default {
77
77
  },
78
78
 
79
79
  handler(e) {
80
+ this._preventClick = null;
81
+
80
82
  if (!isTouch(e) || this._showState) {
81
83
  return;
82
84
  }
@@ -156,9 +158,14 @@ export default {
156
158
  {
157
159
  name: 'click',
158
160
 
161
+ filter() {
162
+ return ['click', 'hover'].some((mode) => includes(this.mode, mode));
163
+ },
164
+
159
165
  handler(e) {
160
166
  let link;
161
167
  if (
168
+ this._preventClick ||
162
169
  closest(e.target, 'a[href="#"], a[href=""]') ||
163
170
  ((link = closest(e.target, 'a[href]')) &&
164
171
  (attr(this.$el, 'aria-expanded') !== 'true' ||
@@ -167,15 +174,9 @@ export default {
167
174
  e.preventDefault();
168
175
  }
169
176
 
170
- if (this._preventClick) {
171
- return (this._preventClick = null);
172
- }
173
-
174
- if (!includes(this.mode, 'click')) {
175
- return;
177
+ if (!this._preventClick && includes(this.mode, 'click')) {
178
+ this.toggle();
176
179
  }
177
-
178
- this.toggle();
179
180
  },
180
181
  },
181
182
 
@@ -333,7 +333,7 @@ function getValue(stops, percent) {
333
333
  return isNumber(start) ? start + Math.abs(start - end) * p * (start < end ? 1 : -1) : +end;
334
334
  }
335
335
 
336
- const unitRe = /^-?\d+([^\s]*)/;
336
+ const unitRe = /^-?\d+(\S*)/;
337
337
  function getUnit(stops, defaultUnit) {
338
338
  for (const stop of stops) {
339
339
  const match = stop.match?.(unitRe);
@@ -1,10 +1,9 @@
1
1
  import {
2
- $,
2
+ css,
3
+ dimensions,
3
4
  flipPosition,
4
5
  getCssVar,
5
- offset as getOffset,
6
6
  includes,
7
- isNumeric,
8
7
  isRtl,
9
8
  positionAt,
10
9
  toPx,
@@ -21,32 +20,21 @@ export default {
21
20
  pos: `bottom-${isRtl ? 'right' : 'left'}`,
22
21
  flip: true,
23
22
  offset: false,
24
- viewportPadding: 10,
25
23
  },
26
24
 
27
25
  connected() {
28
26
  this.pos = this.$props.pos.split('-').concat('center').slice(0, 2);
29
- this.axis = includes(['top', 'bottom'], this.pos[0]) ? 'y' : 'x';
27
+ [this.dir, this.align] = this.pos;
28
+ this.axis = includes(['top', 'bottom'], this.dir) ? 'y' : 'x';
30
29
  },
31
30
 
32
31
  methods: {
33
32
  positionAt(element, target, boundary) {
34
- const [dir, align] = this.pos;
35
-
36
- let { offset } = this;
37
- if (!isNumeric(offset)) {
38
- const node = $(offset);
39
- offset = node
40
- ? getOffset(node)[this.axis === 'x' ? 'left' : 'top'] -
41
- getOffset(target)[this.axis === 'x' ? 'right' : 'bottom']
42
- : 0;
43
- }
44
- offset = toPx(offset) + toPx(getCssVar('position-offset', element));
45
- offset = [includes(['left', 'top'], dir) ? -offset : +offset, 0];
33
+ let offset = [this.getPositionOffset(element), this.getShiftOffset(element)];
46
34
 
47
35
  const attach = {
48
- element: [flipPosition(dir), align],
49
- target: [dir, align],
36
+ element: [flipPosition(this.dir), this.align],
37
+ target: [this.dir, this.align],
50
38
  };
51
39
 
52
40
  if (this.axis === 'y') {
@@ -56,13 +44,41 @@ export default {
56
44
  offset = offset.reverse();
57
45
  }
58
46
 
47
+ // Ensure none positioned element does not generate scrollbars
48
+ const elDim = dimensions(element);
49
+ css(element, { top: -elDim.height, left: -elDim.width });
50
+
59
51
  positionAt(element, target, {
60
52
  attach,
61
53
  offset,
62
54
  boundary,
63
- viewportPadding: this.viewportPadding,
64
55
  flip: this.flip,
56
+ viewportOffset: this.getViewportOffset(element),
65
57
  });
66
58
  },
59
+
60
+ getPositionOffset(element) {
61
+ return (
62
+ toPx(
63
+ this.offset === false ? getCssVar('position-offset', element) : this.offset,
64
+ this.axis === 'x' ? 'width' : 'height',
65
+ element
66
+ ) * (includes(['left', 'top'], this.dir) ? -1 : 1)
67
+ );
68
+ },
69
+
70
+ getShiftOffset(element) {
71
+ return includes(['center', 'justify', 'stretch'], this.align)
72
+ ? 0
73
+ : toPx(
74
+ getCssVar('position-shift-offset', element),
75
+ this.axis === 'y' ? 'width' : 'height',
76
+ element
77
+ ) * (includes(['left', 'top'], this.align) ? 1 : -1);
78
+ },
79
+
80
+ getViewportOffset(element) {
81
+ return toPx(getCssVar('position-viewport-offset', element));
82
+ },
67
83
  },
68
84
  };