@thinkpixellab-public/px-vue 3.0.108 → 3.0.110

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.
@@ -17,8 +17,67 @@ export default {
17
17
  return this.mediaQuery.currentBreakpoint;
18
18
  },
19
19
  },
20
-
21
20
  methods: {
21
+ /**
22
+ * Returns a value from a map that matches the current breakpoint or the nearest breakpoint.
23
+ * Nearest is determined by the searchDirection parameter.
24
+ *
25
+ * Usage:
26
+ *
27
+ * // returns 240 if mobile or smaller, 320 otherwise
28
+ * <Card :width="responsiveValue({mobile: 240}, 320)" />
29
+ *
30
+ * // returns 240 if mobile or smaller, 300 until lg, 320 otherwise
31
+ * <Card :width="responsiveValue({mobile: 240, lg: 300}, 320)" />
32
+ *
33
+ * // returns 200 if smaller than mobile, 240 if smaller than lg and 300 if bigger than lg
34
+ * <Card :width="responsiveValue({mobile: 240, lg: 300}, 200, 'down')" />
35
+ *
36
+ * // could also be used in a computed property....
37
+ * responsiveColor() {
38
+ * return this.responsiveValue({mobile: 'red', lg: 'blue'}, 'green');
39
+ * }
40
+ */
41
+
42
+ responsiveValue(lookup, fallback, searchDirection = 'up') {
43
+ const breakpoints = this.mediaQuery.breakpoints || {};
44
+ const current = this.currentBreakpoint;
45
+
46
+ if (!lookup || !Object.keys(lookup).length || current == null) {
47
+ return fallback;
48
+ }
49
+
50
+ // if the current breakpoint is in the lookup, just return the value
51
+ if (current in lookup) {
52
+ return lookup[current];
53
+ }
54
+
55
+ // convert keys to numbers so we can sort and find the nearest
56
+ lookup = Object.keys(lookup).reduce((acc, key) => {
57
+ if (key in breakpoints) {
58
+ acc[breakpoints[key]] = lookup[key];
59
+ }
60
+ return acc;
61
+ }, {});
62
+
63
+ const currentNum = breakpoints[current];
64
+
65
+ const keys = Object.keys(lookup)
66
+ .map(Number)
67
+ .sort((a, b) => (searchDirection == 'up' ? a - b : b - a));
68
+
69
+ // find the first key that is smaller than current
70
+ const match = keys.find(key => {
71
+ return searchDirection == 'up' ? key >= currentNum : key <= currentNum;
72
+ });
73
+
74
+ if (match) {
75
+ return lookup[match];
76
+ } else {
77
+ return fallback;
78
+ }
79
+ },
80
+
22
81
  isBreakpointOrSmaller(breakpoint) {
23
82
  if (this.currentBreakpoint === null) {
24
83
  return false;
@@ -123,7 +123,13 @@ export default {
123
123
  return;
124
124
  }
125
125
 
126
- const selected = this.$refs[this.getTabContentRefName(this.selectedItem)][0];
126
+ const refName = this.getTabContentRefName(this.selectedItem);
127
+
128
+ if (!this.$refs[refName]) {
129
+ return;
130
+ }
131
+
132
+ const selected = this.$refs[refName][0];
127
133
  const selectedRect = utils.getClientRect(selected, this.$refs.tabs);
128
134
 
129
135
  if (selected) {
@@ -1,40 +1,23 @@
1
1
  <!--
2
- Handle transitions between slides in PxSlide. Uses a hybrid css/javascript transition where
3
- fades are in css and the drag movement is done with gsap.
2
+ Describe this component...
4
3
  -->
5
4
  <template>
6
- <!--
7
- before-enter
8
- before-leave
9
- before-appear
10
- enter
11
- leave
12
- appear
13
- after-enter
14
- after-leave
15
- after-appear
16
- enter-cancelled
17
- leave-cancelled (v-show only)
18
- appear-cancelled
19
- -->
20
-
21
- <transition
22
- @before-enter="beforeEnter"
23
- @enter="enter"
24
- @leave="leave"
25
- v-on="$listeners"
26
- name="px-slide-transition-fade"
27
- >
5
+ <div :class="bem({ active: active })">
28
6
  <slot />
29
- </transition>
7
+ </div>
30
8
  </template>
31
9
 
32
10
  <script>
33
11
  import gsap from 'gsap';
34
12
 
35
13
  export default {
36
- name: 'px-slide-transition',
14
+ name: 'px-slides-transition',
15
+ // components: { Component },
16
+ // mixins: [ Mixin ],
17
+
37
18
  props: {
19
+ active: { type: Boolean, default: true },
20
+
38
21
  // selector used to find children of the element that should slide during the transition
39
22
  dragSelector: { type: String, default: '[data-drag]' },
40
23
 
@@ -50,28 +33,53 @@ export default {
50
33
  // vertical or horizontal
51
34
  orientation: { type: String, default: 'horizontal' },
52
35
 
36
+ disableAnimations: { type: Boolean, default: false },
37
+
53
38
  // TODO rtlAdjust: {type: Boolean, default: false }
54
39
 
55
40
  duration: { type: Number, default: 1 },
56
41
  ease: { type: String, default: 'power3.out' },
57
42
  slideAmount: { default: '40vw' },
43
+ },
58
44
 
59
- disableAnimations: { type: Boolean, default: false },
45
+ data() {
46
+ return { initialized: false };
60
47
  },
61
48
  computed: {
49
+ currentDuration() {
50
+ if (this.disableAnimations || !this.initialized) {
51
+ return 0;
52
+ }
53
+ return this.duration;
54
+ },
62
55
  tweenShared() {
63
56
  return {
64
- duration: this.duration,
57
+ duration: this.currentDuration,
65
58
  ease: this.ease,
66
59
  };
67
60
  },
68
61
  },
62
+ watch: {
63
+ active(isActive, wasActive) {
64
+ this.updateActive(isActive, wasActive);
65
+ },
66
+ },
69
67
  mounted() {
70
- if (this.disableAnimations) {
71
- gsap.globalTimeline.timeScale(Number.MAX_VALUE);
72
- }
68
+ this.updateActive(this.active, false);
69
+ setTimeout(() => {
70
+ this.initialized = true;
71
+ }, 0);
73
72
  },
74
73
  methods: {
74
+ updateActive(isActive, wasActive) {
75
+ if (isActive && !wasActive) {
76
+ this.enter(this.$el);
77
+ }
78
+
79
+ if (!isActive && wasActive) {
80
+ this.leave(this.$el);
81
+ }
82
+ },
75
83
  directionAmount(direction, addEquals = false) {
76
84
  let dir;
77
85
  if (addEquals) {
@@ -96,14 +104,14 @@ export default {
96
104
  return element.querySelectorAll(this.dragReverseSelector);
97
105
  },
98
106
 
99
- beforeEnter() {},
100
-
101
- enter(element, done) {
107
+ enter(element) {
102
108
  const slideElements = this.slideElements(element);
103
109
 
104
110
  if (slideElements?.length) {
105
111
  const from = {};
106
- const to = { ...this.tweenShared, onComplete: done };
112
+ const to = {
113
+ ...this.tweenShared,
114
+ };
107
115
 
108
116
  if (this.orientation === 'vertical') {
109
117
  from.y = this.directionAmount(this.direction * -1);
@@ -126,13 +134,25 @@ export default {
126
134
  );
127
135
  }
128
136
  }
137
+
138
+ // fade
139
+ gsap.to(element, {
140
+ opacity: 1,
141
+ duration: this.currentDuration,
142
+ ease: this.ease,
143
+ onStart: () => {
144
+ this.$emit('before-enter');
145
+ },
146
+ onComplete: () => {
147
+ this.$emit('after-enter');
148
+ },
149
+ });
129
150
  },
130
- leave(element, done) {
151
+ leave(element) {
131
152
  const slideElements = this.slideElements(element);
132
153
 
133
154
  const to = {
134
155
  ...this.tweenShared,
135
- onComplete: done,
136
156
  };
137
157
 
138
158
  if (this.orientation === 'vertical') {
@@ -159,18 +179,28 @@ export default {
159
179
  gsap.to(slideElementsReverse, toReverse);
160
180
  }
161
181
  }
182
+
183
+ gsap.to(element, {
184
+ opacity: 0,
185
+ duration: this.currentDuration,
186
+ ease: this.ease,
187
+ onStart: () => {
188
+ this.$emit('before-leave');
189
+ },
190
+ onComplete: () => {
191
+ this.$emit('after-leave');
192
+ },
193
+ });
162
194
  },
163
195
  },
164
196
  };
165
197
  </script>
166
198
 
167
199
  <style lang="scss">
168
- @use '../styles/helpers.scss' as *;
169
200
  @use '../styles/px.scss' as *;
170
-
171
- @include vue-transition-fade(px-slide-transition-fade, $dur: 1s);
172
-
173
- .slide-transition {
174
- // add styles here
201
+ .px-slides-transition {
202
+ opacity: 0;
203
+ width: 100%;
204
+ height: 100%;
175
205
  }
176
206
  </style>
@@ -1,8 +1,9 @@
1
1
  <!--
2
- Describe this component...
2
+ #VUE3 Todo
3
3
  -->
4
+
4
5
  <template>
5
- <div :class="bem(variantsMap)">
6
+ <div :class="bem({ hasOffset, orientation, ...variantsMap })">
6
7
  <div
7
8
  v-for="(item, index) in items"
8
9
  :key="getItemKey(item)"
@@ -10,14 +11,15 @@
10
11
  :class="bem('slide-wrapper', { selected: isItemSelected(item) })"
11
12
  >
12
13
  <px-slide-transition
14
+ :class="bem('transitioner')"
13
15
  :disable-animations="disableAnimations"
14
16
  :direction="direction"
15
17
  :orientation="orientation"
18
+ :active="isItemSelected(item)"
16
19
  @before-leave="transitionStart"
17
20
  @after-leave="transitionEnd"
18
- @leave-cancelled="transitionEnd"
19
21
  >
20
- <div :class="bem('slide')" v-show="isItemSelected(item)">
22
+ <div :class="bem('slide')">
21
23
  <slot
22
24
  name="slide"
23
25
  :selected="isItemSelected(item)"
@@ -128,7 +130,6 @@ export default {
128
130
  navigator.userAgent.indexOf('Win') != -1 ||
129
131
  this.$route.query?.scroll == 'windows'
130
132
  ) {
131
- //console.log('[Windows scroll values enabled.]');
132
133
  return {
133
134
  stability: stability || 8,
134
135
  sensitivity: sensitivity || 20,
@@ -176,6 +177,11 @@ export default {
176
177
  this.drag.enable();
177
178
  }
178
179
  },
180
+ orientation(nv) {
181
+ if (this.drag) {
182
+ this.drag.updateOptions({ lock: nv === 'horizontal' ? 'x' : 'y' });
183
+ }
184
+ },
179
185
  },
180
186
  mounted() {
181
187
  if (this.scrollEnabled) {
@@ -254,8 +260,10 @@ export default {
254
260
  }
255
261
 
256
262
  if (this.orientation === 'vertical') {
257
- gsap.set(this.dragElements, { y: ev.startDelta.y });
258
- gsap.set(this.dragElementsReverse, { y: -1 * ev.startDelta.y });
263
+ gsap.set(this.dragElements || [], { y: ev.startDelta.y });
264
+ if (this.dragElementsReverse?.length) {
265
+ gsap.set(this.dragElementsReverse, { y: -1 * ev.startDelta.y });
266
+ }
259
267
  } else {
260
268
  gsap.set(this.dragElements, { x: ev.startDelta.x });
261
269
  }
@@ -309,6 +317,7 @@ export default {
309
317
 
310
318
  if (this.scrollExcludeSelector) {
311
319
  const excludeElements = this.$el.querySelectorAll(this.scrollExcludeSelector);
320
+
312
321
  for (let i = 0; i < excludeElements.length; i++) {
313
322
  if (excludeElements[i].contains(e.target)) return;
314
323
  }
@@ -328,7 +337,6 @@ export default {
328
337
  }
329
338
 
330
339
  e.stopPropagation();
331
- e.preventDefault();
332
340
  }
333
341
  }
334
342
 
@@ -371,16 +379,22 @@ export default {
371
379
  </script>
372
380
 
373
381
  <style lang="scss">
374
- @use '../styles/helpers.scss' as *;
375
382
  @use '../styles/px.scss' as *;
376
383
 
377
384
  .px-slides {
378
385
  display: grid;
379
- grid-template-columns: 1fr;
380
- grid-template-rows: 1fr;
386
+ grid-template-columns: minmax(0, 1fr);
387
+ grid-template-rows: minmax(0, 1fr);
381
388
  grid-template-areas: 'content';
389
+ @include no-select();
390
+
382
391
  -webkit-transform-style: preserve-3d;
383
392
 
393
+ video,
394
+ img {
395
+ -webkit-user-drag: none;
396
+ }
397
+
384
398
  &__slide-wrapper {
385
399
  grid-area: content;
386
400
  width: 100%;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thinkpixellab-public/px-vue",
3
- "version": "3.0.108",
3
+ "version": "3.0.110",
4
4
  "description": "General purpose Vue components and helpers that can be used across projects.",
5
5
  "author": "Pixel Lab",
6
6
  "license": "MIT",
@@ -74,6 +74,9 @@ class HeightGroup {
74
74
 
75
75
  if (this.ops.varsParent) {
76
76
  this.ops.varsParent.style.setProperty(this.getVariableName(), max + 'px');
77
+ if (this.ops.debug) {
78
+ console.log(` ${this.getVariableName()}: ${max}px`);
79
+ }
77
80
  }
78
81
 
79
82
  if (this.ops.changeCallback) {
package/utils/drag.js CHANGED
@@ -341,7 +341,8 @@ function Drag(element, options) {
341
341
  };
342
342
 
343
343
  this.updateOptions = options => {
344
- this.ops = { ...this.ops, options };
344
+ this.ops = { ...this.ops, ...options };
345
+ this.reset();
345
346
  };
346
347
 
347
348
  this.disable = () => {
@@ -36,4 +36,4 @@ const getFontFromElement = element => {
36
36
  };
37
37
 
38
38
  export default textWidth;
39
- export { getFontFromElement };
39
+ export { textWidth, getFontFromElement };
package/utils/utils.js CHANGED
@@ -412,4 +412,28 @@ export default {
412
412
  ('000' + ((Math.random() * 46656) | 0).toString(36)).slice(-3)
413
413
  );
414
414
  },
415
+
416
+ findScrollParent(node) {
417
+ const isScrolling = node => {
418
+ let overflow = getComputedStyle(node, null).getPropertyValue('overflow');
419
+
420
+ return overflow.indexOf('scroll') > -1 || overflow.indexOf('auto') > -1;
421
+ };
422
+
423
+ if (!(node instanceof HTMLElement || node instanceof SVGElement)) {
424
+ return undefined;
425
+ }
426
+
427
+ let current = node.parentNode;
428
+
429
+ while (current?.parentNode) {
430
+ if (isScrolling(current)) {
431
+ return current;
432
+ }
433
+
434
+ current = current.parentNode;
435
+ }
436
+
437
+ return document.scrollingElement || document.documentElement;
438
+ },
415
439
  };