uikit 3.14.3 → 3.14.4-dev.6a00f7fe6

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 (84) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/css/uikit-core-rtl.css +84 -26
  3. package/dist/css/uikit-core-rtl.min.css +1 -1
  4. package/dist/css/uikit-core.css +84 -26
  5. package/dist/css/uikit-core.min.css +1 -1
  6. package/dist/css/uikit-rtl.css +90 -41
  7. package/dist/css/uikit-rtl.min.css +1 -1
  8. package/dist/css/uikit.css +90 -41
  9. package/dist/css/uikit.min.css +1 -1
  10. package/dist/js/components/countdown.js +1 -1
  11. package/dist/js/components/countdown.min.js +1 -1
  12. package/dist/js/components/filter.js +1 -1
  13. package/dist/js/components/filter.min.js +1 -1
  14. package/dist/js/components/lightbox-panel.js +101 -22
  15. package/dist/js/components/lightbox-panel.min.js +1 -1
  16. package/dist/js/components/lightbox.js +101 -22
  17. package/dist/js/components/lightbox.min.js +1 -1
  18. package/dist/js/components/notification.js +1 -1
  19. package/dist/js/components/notification.min.js +1 -1
  20. package/dist/js/components/parallax.js +1 -1
  21. package/dist/js/components/parallax.min.js +1 -1
  22. package/dist/js/components/slider-parallax.js +1 -1
  23. package/dist/js/components/slider-parallax.min.js +1 -1
  24. package/dist/js/components/slider.js +1 -1
  25. package/dist/js/components/slider.min.js +1 -1
  26. package/dist/js/components/slideshow-parallax.js +1 -1
  27. package/dist/js/components/slideshow-parallax.min.js +1 -1
  28. package/dist/js/components/slideshow.js +1 -1
  29. package/dist/js/components/slideshow.min.js +1 -1
  30. package/dist/js/components/sortable.js +1 -1
  31. package/dist/js/components/sortable.min.js +1 -1
  32. package/dist/js/components/tooltip.js +135 -34
  33. package/dist/js/components/tooltip.min.js +1 -1
  34. package/dist/js/components/upload.js +1 -1
  35. package/dist/js/components/upload.min.js +1 -1
  36. package/dist/js/uikit-core.js +206 -77
  37. package/dist/js/uikit-core.min.js +1 -1
  38. package/dist/js/uikit-icons.js +1 -1
  39. package/dist/js/uikit-icons.min.js +1 -1
  40. package/dist/js/uikit.js +206 -77
  41. package/dist/js/uikit.min.js +1 -1
  42. package/package.json +1 -1
  43. package/src/js/core/accordion.js +3 -3
  44. package/src/js/core/alert.js +1 -1
  45. package/src/js/core/drop.js +40 -20
  46. package/src/js/core/height-viewport.js +14 -9
  47. package/src/js/core/navbar.js +11 -9
  48. package/src/js/core/switcher.js +1 -1
  49. package/src/js/mixin/position.js +44 -13
  50. package/src/js/mixin/togglable.js +105 -24
  51. package/src/js/util/animation.js +1 -0
  52. package/src/js/util/viewport.js +1 -1
  53. package/src/less/components/drop.less +19 -5
  54. package/src/less/components/dropdown.less +21 -5
  55. package/src/less/components/margin.less +13 -14
  56. package/src/less/components/modal.less +19 -4
  57. package/src/less/components/nav.less +1 -1
  58. package/src/less/components/navbar.less +54 -21
  59. package/src/less/components/offcanvas.less +21 -21
  60. package/src/less/components/position.less +1 -1
  61. package/src/less/components/utility.less +0 -1
  62. package/src/less/theme/dropdown.less +11 -0
  63. package/src/less/theme/navbar.less +10 -12
  64. package/src/scss/components/drop.scss +19 -5
  65. package/src/scss/components/dropdown.scss +21 -5
  66. package/src/scss/components/margin.scss +13 -14
  67. package/src/scss/components/modal.scss +19 -4
  68. package/src/scss/components/nav.scss +1 -1
  69. package/src/scss/components/navbar.scss +43 -10
  70. package/src/scss/components/offcanvas.scss +21 -21
  71. package/src/scss/components/position.scss +1 -1
  72. package/src/scss/components/utility.scss +0 -1
  73. package/src/scss/mixins-theme.scss +8 -12
  74. package/src/scss/mixins.scss +2 -0
  75. package/src/scss/theme/dropdown.scss +8 -0
  76. package/src/scss/theme/navbar.scss +7 -0
  77. package/src/scss/variables-theme.scss +26 -11
  78. package/src/scss/variables.scss +24 -11
  79. package/tests/drop.html +145 -2
  80. package/tests/dropdown.html +228 -13
  81. package/tests/height-viewport.html +62 -0
  82. package/tests/navbar.html +321 -14
  83. package/tests/offcanvas.html +8 -8
  84. package/tests/sticky-navbar.html +132 -0
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.3",
5
+ "version": "3.14.4-dev.6a00f7fe6",
6
6
  "main": "dist/js/uikit.js",
7
7
  "style": "dist/css/uikit.css",
8
8
  "sideEffects": [
@@ -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 },
@@ -8,7 +8,6 @@ import {
8
8
  apply,
9
9
  attr,
10
10
  css,
11
- getCssVar,
12
11
  hasClass,
13
12
  includes,
14
13
  isTouch,
@@ -16,6 +15,7 @@ import {
16
15
  MouseTracker,
17
16
  observeResize,
18
17
  offset,
18
+ offsetViewport,
19
19
  on,
20
20
  once,
21
21
  parent,
@@ -28,7 +28,6 @@ import {
28
28
  removeClass,
29
29
  scrollParents,
30
30
  toggleClass,
31
- toPx,
32
31
  within,
33
32
  } from 'uikit-util';
34
33
 
@@ -48,6 +47,7 @@ export default {
48
47
  delayHide: Number,
49
48
  display: String,
50
49
  clsDrop: String,
50
+ animateOut: Boolean,
51
51
  },
52
52
 
53
53
  data: {
@@ -62,6 +62,7 @@ export default {
62
62
  animation: ['uk-animation-fade'],
63
63
  cls: 'uk-open',
64
64
  container: false,
65
+ animateOut: false,
65
66
  },
66
67
 
67
68
  created() {
@@ -249,7 +250,7 @@ export default {
249
250
  }
250
251
  }),
251
252
 
252
- ...(this.display === 'static'
253
+ ...(this.display === 'static' && this.align !== 'stretch'
253
254
  ? []
254
255
  : (() => {
255
256
  const handler = () => this.$emit();
@@ -310,7 +311,7 @@ export default {
310
311
  methods: {
311
312
  show(target = this.target, delay = true) {
312
313
  if (this.isToggled() && target && this.target && target !== this.target) {
313
- this.hide(false);
314
+ this.hide(false, false);
314
315
  }
315
316
 
316
317
  this.target = target;
@@ -330,7 +331,7 @@ export default {
330
331
  let prev;
331
332
  while (active && prev !== active && !within(this.$el, active.$el)) {
332
333
  prev = active;
333
- active.hide(false);
334
+ active.hide(false, false);
334
335
  }
335
336
  }
336
337
 
@@ -344,8 +345,8 @@ export default {
344
345
  );
345
346
  },
346
347
 
347
- hide(delay = true) {
348
- 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);
349
350
 
350
351
  this.clearTimers();
351
352
 
@@ -377,40 +378,59 @@ export default {
377
378
  position() {
378
379
  removeClass(this.$el, `${this.clsDrop}-stack`);
379
380
  toggleClass(this.$el, `${this.clsDrop}-boundary`, this.boundaryAlign);
381
+ toggleClass(this.$el, `${this.clsDrop}-stretch`, this.align === 'stretch');
380
382
 
381
383
  const boundary = query(this.boundary, this.$el);
382
- const scrollParentOffset = offset(
383
- scrollParents(boundary && this.boundaryAlign ? boundary : this.$el)[0]
384
+ const target = boundary && this.boundaryAlign ? boundary : this.target;
385
+ const [scrollParent] = scrollParents(
386
+ boundary && this.boundaryAlign ? boundary : this.$el
384
387
  );
388
+ const scrollParentOffset = offset(scrollParent);
385
389
  const boundaryOffset = boundary ? offset(boundary) : scrollParentOffset;
390
+ const viewportOffset = this.getViewportOffset(this.$el);
386
391
 
387
392
  css(this.$el, 'maxWidth', '');
388
- const maxWidth =
389
- scrollParentOffset.width -
390
- 2 * toPx(getCssVar('position-viewport-offset', this.$el));
393
+ const maxWidth = scrollParentOffset.width - 2 * viewportOffset;
391
394
 
392
- if (this.pos[1] === 'justify') {
395
+ if (this.align === 'justify') {
393
396
  const prop = this.axis === 'y' ? 'width' : 'height';
394
397
  css(
395
398
  this.$el,
396
399
  prop,
397
400
  Math.min(
398
401
  (boundary ? boundaryOffset : offset(this.target))[prop],
399
- scrollParentOffset[prop] -
400
- 2 * toPx(getCssVar('position-viewport-offset', this.$el))
402
+ scrollParentOffset[prop] - 2 * viewportOffset
401
403
  )
402
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
+ });
403
427
  } else if (this.$el.offsetWidth > maxWidth) {
404
428
  addClass(this.$el, `${this.clsDrop}-stack`);
405
429
  }
406
430
 
407
431
  css(this.$el, 'maxWidth', maxWidth);
408
432
 
409
- this.positionAt(
410
- this.$el,
411
- boundary && this.boundaryAlign ? boundary : this.target,
412
- boundary
413
- );
433
+ this.positionAt(this.$el, target, boundary);
414
434
  },
415
435
  },
416
436
  };
@@ -4,12 +4,13 @@ import {
4
4
  css,
5
5
  dimensions,
6
6
  endsWith,
7
- height,
8
7
  isNumeric,
9
8
  isString,
10
9
  isVisible,
11
- offset,
10
+ offsetPosition,
11
+ offsetViewport,
12
12
  query,
13
+ scrollParents,
13
14
  toFloat,
14
15
  } from 'uikit-util';
15
16
 
@@ -32,7 +33,7 @@ export default {
32
33
 
33
34
  resizeTargets() {
34
35
  // check for offsetTop change
35
- return [this.$el, document.documentElement];
36
+ return [this.$el, ...scrollParents(this.$el, /auto|scroll/)];
36
37
  },
37
38
 
38
39
  update: {
@@ -44,21 +45,25 @@ export default {
44
45
  let minHeight = '';
45
46
  const box = boxModelAdjust(this.$el, 'height', 'content-box');
46
47
 
48
+ const [scrollElement] = scrollParents(this.$el, /auto|scroll/);
49
+ const { height: viewportHeight } = offsetViewport(scrollElement);
50
+
47
51
  if (this.expand) {
48
52
  minHeight = Math.max(
49
- height(window) -
50
- (dimensions(document.documentElement).height -
51
- dimensions(this.$el).height) -
53
+ viewportHeight -
54
+ (dimensions(scrollElement).height - dimensions(this.$el).height) -
52
55
  box,
53
56
  0
54
57
  );
55
58
  } else {
56
59
  // on mobile devices (iOS and Android) window.innerHeight !== 100vh
57
- minHeight = 'calc(100vh';
60
+ minHeight = `calc(${
61
+ document.scrollingElement === scrollElement ? '100vh' : `${viewportHeight}px`
62
+ }`;
58
63
 
59
64
  if (this.offsetTop) {
60
- const { top } = offset(this.$el);
61
- 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` : '';
62
67
  }
63
68
 
64
69
  if (this.offsetBottom === true) {
@@ -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,8 +309,8 @@ export default {
309
309
  return this.dropbar;
310
310
  },
311
311
 
312
- handler(_, { $el }) {
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
 
@@ -360,8 +360,8 @@ 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
 
@@ -387,7 +387,7 @@ export default {
387
387
 
388
388
  el = oldHeight < newHeight && el;
389
389
 
390
- 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)`);
391
391
 
392
392
  height(dropbar, oldHeight);
393
393
 
@@ -396,12 +396,14 @@ export default {
396
396
  Transition.start(dropbar, { height: newHeight }, this.duration),
397
397
  Transition.start(
398
398
  el,
399
- { clip: `rect(0,${el.offsetWidth}px,${newHeight}px,0)` },
399
+ {
400
+ clipPath: `polygon(0 0,100% 0,100% ${newHeight}px,0 ${newHeight}px)`,
401
+ },
400
402
  this.duration
401
403
  ),
402
404
  ])
403
405
  .catch(noop)
404
- .then(() => css(el, { clip: '' }));
406
+ .then(() => css(el, { clipPath: '' }));
405
407
  },
406
408
 
407
409
  getDropdown(el) {
@@ -48,7 +48,7 @@ export default {
48
48
 
49
49
  watch(connects) {
50
50
  if (this.swiping) {
51
- css(connects, 'touch-action', 'pan-y pinch-zoom');
51
+ css(connects, 'touchAction', 'pan-y pinch-zoom');
52
52
  }
53
53
 
54
54
  const index = this.index();
@@ -1,4 +1,13 @@
1
- import { flipPosition, getCssVar, includes, isRtl, positionAt, toPx } from 'uikit-util';
1
+ import {
2
+ css,
3
+ dimensions,
4
+ flipPosition,
5
+ getCssVar,
6
+ includes,
7
+ isRtl,
8
+ positionAt,
9
+ toPx,
10
+ } from 'uikit-util';
2
11
 
3
12
  export default {
4
13
  props: {
@@ -15,23 +24,17 @@ export default {
15
24
 
16
25
  connected() {
17
26
  this.pos = this.$props.pos.split('-').concat('center').slice(0, 2);
18
- 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';
19
29
  },
20
30
 
21
31
  methods: {
22
32
  positionAt(element, target, boundary) {
23
- const [dir, align] = this.pos;
24
-
25
- let offset = toPx(
26
- this.offset === false ? getCssVar('position-offset', element) : this.offset,
27
- this.axis === 'x' ? 'width' : 'height',
28
- element
29
- );
30
- offset = [includes(['left', 'top'], dir) ? -offset : +offset, 0];
33
+ let offset = [this.getPositionOffset(element), this.getShiftOffset(element)];
31
34
 
32
35
  const attach = {
33
- element: [flipPosition(dir), align],
34
- target: [dir, align],
36
+ element: [flipPosition(this.dir), this.align],
37
+ target: [this.dir, this.align],
35
38
  };
36
39
 
37
40
  if (this.axis === 'y') {
@@ -41,13 +44,41 @@ export default {
41
44
  offset = offset.reverse();
42
45
  }
43
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
+
44
51
  positionAt(element, target, {
45
52
  attach,
46
53
  offset,
47
54
  boundary,
48
55
  flip: this.flip,
49
- viewportOffset: toPx(getCssVar('position-viewport-offset', element)),
56
+ viewportOffset: this.getViewportOffset(element),
50
57
  });
51
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
+ },
52
83
  },
53
84
  };
@@ -5,13 +5,15 @@ import {
5
5
  css,
6
6
  fastdom,
7
7
  hasClass,
8
- height,
9
8
  includes,
10
9
  isBoolean,
11
10
  isFunction,
12
11
  isVisible,
13
12
  noop,
13
+ offset,
14
14
  removeClass,
15
+ scrollParents,
16
+ startsWith,
15
17
  toFloat,
16
18
  toggleClass,
17
19
  toNodes,
@@ -41,7 +43,7 @@ export default {
41
43
 
42
44
  initProps: {
43
45
  overflow: '',
44
- height: '',
46
+ maxHeight: '',
45
47
  paddingTop: '',
46
48
  paddingBottom: '',
47
49
  marginTop: '',
@@ -51,7 +53,7 @@ export default {
51
53
 
52
54
  hideProps: {
53
55
  overflow: 'hidden',
54
- height: 0,
56
+ maxHeight: 0,
55
57
  paddingTop: 0,
56
58
  paddingBottom: 0,
57
59
  marginTop: 0,
@@ -66,7 +68,7 @@ export default {
66
68
  },
67
69
 
68
70
  hasTransition({ animation }) {
69
- return this.hasAnimation && animation[0] === true;
71
+ return startsWith(animation[0], 'slide');
70
72
  },
71
73
  },
72
74
 
@@ -81,18 +83,13 @@ export default {
81
83
  return Promise.reject();
82
84
  }
83
85
 
84
- if (!animate) {
85
- Animation.cancel(el);
86
- Transition.cancel(el);
87
- }
88
-
89
86
  const promise = (
90
87
  isFunction(animate)
91
88
  ? animate
92
89
  : animate === false || !this.hasAnimation
93
- ? this._toggle
90
+ ? toggleInstant(this)
94
91
  : this.hasTransition
95
- ? toggleHeight(this)
92
+ ? toggleTransition(this)
96
93
  : toggleAnimation(this)
97
94
  )(el, show);
98
95
 
@@ -156,7 +153,25 @@ export default {
156
153
  },
157
154
  };
158
155
 
159
- export function toggleHeight({
156
+ function toggleInstant({ _toggle }) {
157
+ return (el, show) => {
158
+ Animation.cancel(el);
159
+ Transition.cancel(el);
160
+ return _toggle(el, show);
161
+ };
162
+ }
163
+
164
+ function toggleTransition(cmp) {
165
+ switch (cmp.animation[0]) {
166
+ case 'slide-left':
167
+ return slideHorizontal(cmp);
168
+ case 'slide-right':
169
+ return slideHorizontal(cmp, true);
170
+ }
171
+ return slide(cmp);
172
+ }
173
+
174
+ export function slide({
160
175
  isToggled,
161
176
  duration,
162
177
  velocity,
@@ -167,11 +182,14 @@ export function toggleHeight({
167
182
  }) {
168
183
  return (el, show) => {
169
184
  const inProgress = Transition.inProgress(el);
170
- const inner = el.hasChildNodes()
171
- ? toFloat(css(el.firstElementChild, 'marginTop')) +
172
- toFloat(css(el.lastElementChild, 'marginBottom'))
173
- : 0;
174
- const currentHeight = isVisible(el) ? height(el) + (inProgress ? 0 : inner) : 0;
185
+ const inner =
186
+ !inProgress && el.hasChildNodes()
187
+ ? toFloat(css(el.firstElementChild, 'marginTop')) +
188
+ toFloat(css(el.lastElementChild, 'marginBottom'))
189
+ : 0;
190
+ const currentHeight = isVisible(el) ? toFloat(css(el, 'height')) + inner : 0;
191
+
192
+ const props = inProgress ? css(el, Object.keys(initProps)) : show ? hideProps : initProps;
175
193
 
176
194
  Transition.cancel(el);
177
195
 
@@ -179,34 +197,97 @@ export function toggleHeight({
179
197
  _toggle(el, true);
180
198
  }
181
199
 
182
- height(el, '');
200
+ css(el, 'maxHeight', '');
183
201
 
184
202
  // Update child components first
185
203
  fastdom.flush();
186
204
 
187
- const endHeight = height(el) + (inProgress ? 0 : inner);
188
- duration = velocity * el.offsetHeight + duration;
205
+ const endHeight = toFloat(css(el, 'height')) + inner;
206
+ duration = velocity * endHeight + duration;
189
207
 
190
- height(el, currentHeight);
208
+ css(el, { ...props, maxHeight: currentHeight });
191
209
 
192
210
  return (
193
211
  show
194
212
  ? Transition.start(
195
213
  el,
196
- { ...initProps, overflow: 'hidden', height: endHeight },
197
- Math.round(duration * (1 - currentHeight / endHeight)),
214
+ { ...initProps, overflow: 'hidden', maxHeight: endHeight },
215
+ duration * (1 - currentHeight / endHeight),
198
216
  transition
199
217
  )
200
218
  : Transition.start(
201
219
  el,
202
220
  hideProps,
203
- Math.round(duration * (currentHeight / endHeight)),
221
+ duration * (currentHeight / endHeight),
204
222
  transition
205
223
  ).then(() => _toggle(el, false))
206
224
  ).then(() => css(el, initProps));
207
225
  };
208
226
  }
209
227
 
228
+ function slideHorizontal({ isToggled, duration, velocity, transition, _toggle }, right) {
229
+ return (el, show) => {
230
+ const visible = isVisible(el);
231
+ const marginLeft = toFloat(css(el, 'marginLeft'));
232
+
233
+ Transition.cancel(el);
234
+
235
+ const [scrollElement] = scrollParents(el);
236
+ css(scrollElement, 'overflowX', 'hidden');
237
+
238
+ if (!isToggled(el)) {
239
+ _toggle(el, true);
240
+ }
241
+
242
+ const width = toFloat(css(el, 'width'));
243
+ duration = velocity * width + duration;
244
+
245
+ const percent = visible ? ((width + marginLeft * (right ? -1 : 1)) / width) * 100 : 0;
246
+ const offsetEl = offset(el);
247
+ const useClipPath = right
248
+ ? offsetEl.right < scrollElement.clientWidth
249
+ : Math.round(offsetEl.left) > 0;
250
+
251
+ css(el, {
252
+ clipPath: useClipPath
253
+ ? right
254
+ ? `polygon(0 0,${percent}% 0,${percent}% 100%,0 100%)`
255
+ : `polygon(${100 - percent}% 0,100% 0,100% 100%,${100 - percent}% 100%)`
256
+ : '',
257
+ marginLeft: (((100 - percent) * (right ? 1 : -1)) / 100) * width,
258
+ });
259
+
260
+ return (
261
+ show
262
+ ? Transition.start(
263
+ el,
264
+ {
265
+ clipPath: useClipPath ? `polygon(0 0,100% 0,100% 100%,0 100%)` : '',
266
+ marginLeft: 0,
267
+ },
268
+ duration * (1 - percent / 100),
269
+ transition
270
+ )
271
+ : Transition.start(
272
+ el,
273
+ {
274
+ clipPath: useClipPath
275
+ ? right
276
+ ? `polygon(0 0,0 0,0 100%,0 100%)`
277
+ : `polygon(100% 0,100% 0,100% 100%,100% 100%)`
278
+ : '',
279
+ marginLeft: (right ? 1 : -1) * width,
280
+ },
281
+ duration * (percent / 100),
282
+ transition
283
+ ).then(() => _toggle(el, false))
284
+ ).then(() => {
285
+ css(scrollElement, 'overflowX', '');
286
+ css(el, { clipPath: '', marginLeft: '' });
287
+ });
288
+ };
289
+ }
290
+
210
291
  function toggleAnimation(cmp) {
211
292
  return (el, show) => {
212
293
  Animation.cancel(el);
@@ -5,6 +5,7 @@ import { startsWith, toNodes } from './lang';
5
5
  import { addClass, hasClass, removeClass, removeClasses } from './class';
6
6
 
7
7
  export function transition(element, props, duration = 400, timing = 'linear') {
8
+ duration = Math.round(duration);
8
9
  return Promise.all(
9
10
  toNodes(element).map(
10
11
  (element) =>
@@ -128,7 +128,7 @@ export function scrolledOver(element, startOffset = 0, endOffset = 0) {
128
128
  return clamp((scrollTop - start) / (end - start));
129
129
  }
130
130
 
131
- export function scrollParents(element, overflowRe = /auto|scroll|hidden/, scrollable = false) {
131
+ export function scrollParents(element, overflowRe = /auto|scroll|hidden|clip/, scrollable = false) {
132
132
  const scrollEl = scrollingElement(element);
133
133
 
134
134
  let ancestors = parents(element).reverse();