@thinkpixellab-public/px-vue 3.0.88 → 3.0.90
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.
- package/components/PxSlideTransition.vue +70 -16
- package/components/PxSlides.vue +52 -7
- package/components/PxSpinner.vue +18 -9
- package/package.json +1 -1
- package/utils/utils.js +47 -0
|
@@ -38,11 +38,18 @@ export default {
|
|
|
38
38
|
// selector used to find children of the element that should slide during the transition
|
|
39
39
|
dragSelector: { type: String, default: '[data-drag]' },
|
|
40
40
|
|
|
41
|
+
// selector used to find drag elements in the dom that should animate in a reverse direction in vertical transitions
|
|
42
|
+
dragReverseSelector: { type: String, default: '[data-drag-reverse]' },
|
|
43
|
+
|
|
41
44
|
// if true, slide the parent element if no slideSelect children are found (false will result just fading)
|
|
42
45
|
dragElementFallback: { type: Boolean, default: true },
|
|
43
46
|
|
|
44
|
-
// 1 moves to the
|
|
47
|
+
// 1 moves the content to the left/up, -1 moves to the right/down
|
|
45
48
|
direction: { type: Number, default: 1 },
|
|
49
|
+
|
|
50
|
+
// vertical or horizontal
|
|
51
|
+
orientation: { type: String, default: 'horizontal' },
|
|
52
|
+
|
|
46
53
|
// TODO rtlAdjust: {type: Boolean, default: false }
|
|
47
54
|
|
|
48
55
|
duration: { type: Number, default: 1 },
|
|
@@ -82,29 +89,76 @@ export default {
|
|
|
82
89
|
return element.querySelectorAll(this.dragSelector);
|
|
83
90
|
},
|
|
84
91
|
|
|
92
|
+
slideElementsReverse(element) {
|
|
93
|
+
if (!element || !this.orientation == 'vertical') {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
return element.querySelectorAll(this.dragReverseSelector);
|
|
97
|
+
},
|
|
98
|
+
|
|
85
99
|
beforeEnter() {},
|
|
86
100
|
|
|
87
101
|
enter(element, done) {
|
|
88
|
-
|
|
102
|
+
const slideElements = this.slideElements(element);
|
|
103
|
+
|
|
89
104
|
if (slideElements?.length) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
105
|
+
const from = {};
|
|
106
|
+
const to = { ...this.tweenShared, onComplete: done };
|
|
107
|
+
|
|
108
|
+
if (this.orientation === 'vertical') {
|
|
109
|
+
from.y = this.directionAmount(this.direction * -1);
|
|
110
|
+
to.y = 0;
|
|
111
|
+
} else {
|
|
112
|
+
from.x = this.directionAmount(this.direction * -1);
|
|
113
|
+
to.x = 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
gsap.fromTo(slideElements, from, to);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (this.orientation === 'vertical') {
|
|
120
|
+
const slideElementsReverse = this.slideElementsReverse(element);
|
|
121
|
+
if (slideElementsReverse?.length) {
|
|
122
|
+
gsap.fromTo(
|
|
123
|
+
slideElementsReverse,
|
|
124
|
+
{ y: this.directionAmount(this.direction) },
|
|
125
|
+
{ y: 0, ...this.tweenShared }
|
|
126
|
+
);
|
|
127
|
+
}
|
|
97
128
|
}
|
|
98
129
|
},
|
|
99
130
|
leave(element, done) {
|
|
100
|
-
|
|
101
|
-
|
|
131
|
+
const slideElements = this.slideElements(element);
|
|
132
|
+
|
|
133
|
+
const to = {
|
|
134
|
+
...this.tweenShared,
|
|
135
|
+
onComplete: done,
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
if (this.orientation === 'vertical') {
|
|
139
|
+
to.y = this.directionAmount(this.direction, true);
|
|
140
|
+
} else {
|
|
141
|
+
to.x = this.directionAmount(this.direction, true);
|
|
142
|
+
}
|
|
143
|
+
|
|
102
144
|
if (slideElements?.length) {
|
|
103
|
-
gsap.to(slideElements,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
145
|
+
gsap.to(slideElements, to);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (this.orientation === 'vertical') {
|
|
149
|
+
const slideElementsReverse = this.slideElementsReverse(element);
|
|
150
|
+
console.log(`slideElementsReverse.length: ${slideElementsReverse.length}`);
|
|
151
|
+
|
|
152
|
+
if (slideElementsReverse?.length) {
|
|
153
|
+
const slideElementsReverse = this.slideElementsReverse(element);
|
|
154
|
+
|
|
155
|
+
const toReverse = {
|
|
156
|
+
...this.tweenShared,
|
|
157
|
+
y: this.directionAmount(this.direction * -1, true),
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
gsap.to(slideElementsReverse, toReverse);
|
|
161
|
+
}
|
|
108
162
|
}
|
|
109
163
|
},
|
|
110
164
|
},
|
package/components/PxSlides.vue
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
<px-slide-transition
|
|
13
13
|
:disable-animations="disableAnimations"
|
|
14
14
|
:direction="direction"
|
|
15
|
+
:orientation="orientation"
|
|
15
16
|
@before-leave="transitionStart"
|
|
16
17
|
@after-leave="transitionEnd"
|
|
17
18
|
@leave-cancelled="transitionEnd"
|
|
@@ -55,6 +56,9 @@ export default {
|
|
|
55
56
|
components: { PxSlideTransition, PxIcon },
|
|
56
57
|
|
|
57
58
|
props: {
|
|
59
|
+
// vertical or horizontal
|
|
60
|
+
orientation: { type: String, default: 'horizontal' },
|
|
61
|
+
|
|
58
62
|
// whether drag interaction is enabled
|
|
59
63
|
dragEnabled: { type: Boolean, default: true },
|
|
60
64
|
|
|
@@ -70,9 +74,13 @@ export default {
|
|
|
70
74
|
// selector used to find drag elements in the dom
|
|
71
75
|
dragSelector: { type: String, default: '[data-drag]' },
|
|
72
76
|
|
|
77
|
+
// selector used to find drag elements in the dom that should animate in a reverse direction in vertical transitions
|
|
78
|
+
dragReverseSelector: { type: String, default: '[data-drag-reverse]' },
|
|
79
|
+
|
|
73
80
|
// exclude from drag
|
|
74
81
|
dragExcludeSelector: { type: String, default: 'input, button, [data-no-drag]' },
|
|
75
82
|
|
|
83
|
+
// exclude from scroll
|
|
76
84
|
scrollExcludeSelector: { type: String, default: '[data-no-slidescroll]' },
|
|
77
85
|
|
|
78
86
|
// override default
|
|
@@ -88,6 +96,9 @@ export default {
|
|
|
88
96
|
lastInteractionType: null,
|
|
89
97
|
activeTransitions: 0,
|
|
90
98
|
scrollPreview: 0,
|
|
99
|
+
|
|
100
|
+
// true whenver the selected item is in an offset by dragging or a transition
|
|
101
|
+
hasOffset: false,
|
|
91
102
|
};
|
|
92
103
|
},
|
|
93
104
|
computed: {
|
|
@@ -129,6 +140,13 @@ export default {
|
|
|
129
140
|
},
|
|
130
141
|
},
|
|
131
142
|
watch: {
|
|
143
|
+
hasOffset(nv) {
|
|
144
|
+
if (nv) {
|
|
145
|
+
this.$emit('offset-start');
|
|
146
|
+
} else {
|
|
147
|
+
this.$emit('offset-end');
|
|
148
|
+
}
|
|
149
|
+
},
|
|
132
150
|
syncSelected(nv, ov) {
|
|
133
151
|
let newIndex = this.itemKeys.indexOf(nv);
|
|
134
152
|
let oldIndex = this.itemKeys.indexOf(ov);
|
|
@@ -179,7 +197,7 @@ export default {
|
|
|
179
197
|
}
|
|
180
198
|
|
|
181
199
|
this.drag = new Drag(this.$el, {
|
|
182
|
-
lock: 'x',
|
|
200
|
+
lock: this.orientation === 'horizontal' ? 'x' : 'y',
|
|
183
201
|
onStart: this.onDragStart,
|
|
184
202
|
onDrag: this.onDrag,
|
|
185
203
|
onEnd: this.onDragEnd,
|
|
@@ -198,6 +216,7 @@ export default {
|
|
|
198
216
|
transitionStart() {
|
|
199
217
|
if (!this.activeTransitions) {
|
|
200
218
|
this.$emit('transitions-start');
|
|
219
|
+
this.hasOffset = true;
|
|
201
220
|
}
|
|
202
221
|
this.activeTransitions++;
|
|
203
222
|
},
|
|
@@ -208,6 +227,7 @@ export default {
|
|
|
208
227
|
this.$emit('transitions-end', {
|
|
209
228
|
toIndex: this.itemKeys.indexOf(this.syncSelected),
|
|
210
229
|
});
|
|
230
|
+
this.hasOffset = false;
|
|
211
231
|
}
|
|
212
232
|
},
|
|
213
233
|
|
|
@@ -217,26 +237,51 @@ export default {
|
|
|
217
237
|
|
|
218
238
|
if (slide) {
|
|
219
239
|
this.dragElements = [...slide.querySelectorAll(this.dragSelector)];
|
|
240
|
+
this.dragElementsReverse = [...slide.querySelectorAll(this.dragReverseSelector)];
|
|
220
241
|
}
|
|
242
|
+
|
|
243
|
+
this.hasOffset = true;
|
|
221
244
|
},
|
|
222
245
|
|
|
223
246
|
onDrag(ev) {
|
|
224
|
-
if (this.dragElements?.length) {
|
|
247
|
+
if (this.dragElements?.length || this.dragElementsReverse?.length) {
|
|
225
248
|
if (gsap.isTweening(this.dragElements[0])) {
|
|
226
249
|
gsap.killTweensOf(this.dragElements);
|
|
227
250
|
}
|
|
228
|
-
|
|
251
|
+
|
|
252
|
+
if (gsap.isTweening(this.dragElementsReverse[0])) {
|
|
253
|
+
gsap.killTweensOf(this.dragElementsReverse);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (this.orientation === 'vertical') {
|
|
257
|
+
gsap.set(this.dragElements, { y: ev.startDelta.y });
|
|
258
|
+
gsap.set(this.dragElementsReverse, { y: -1 * ev.startDelta.y });
|
|
259
|
+
} else {
|
|
260
|
+
gsap.set(this.dragElements, { x: ev.startDelta.x });
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
this.hasOffset = true;
|
|
229
264
|
}
|
|
230
265
|
},
|
|
231
266
|
|
|
232
267
|
onDragEnd(ev) {
|
|
233
|
-
|
|
234
|
-
|
|
268
|
+
const delta = this.orientation === 'vertical' ? ev.delta.y : ev.delta.x;
|
|
269
|
+
if (Math.abs(delta) < 10) {
|
|
270
|
+
this.hasOffset = false;
|
|
271
|
+
|
|
272
|
+
// snap back
|
|
273
|
+
const to = {};
|
|
274
|
+
to[this.orientation === 'vertical' ? 'y' : 'x'] = 0;
|
|
275
|
+
gsap.to(this.dragElements, { ...to });
|
|
276
|
+
|
|
277
|
+
// snap back reverse elements (vertical only)
|
|
278
|
+
if (this.orientation === 'vertical') {
|
|
279
|
+
gsap.to(this.dragElementsReverse, { y: 0 });
|
|
280
|
+
}
|
|
235
281
|
} else {
|
|
236
282
|
this.lastInteractionType = 'drag';
|
|
237
283
|
this.$emit('drag-complete');
|
|
238
|
-
|
|
239
|
-
if (ev.delta.x > 0) {
|
|
284
|
+
if (delta > 0) {
|
|
240
285
|
this.previous();
|
|
241
286
|
} else {
|
|
242
287
|
this.next();
|
package/components/PxSpinner.vue
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* classic - rotating semi-circle
|
|
8
8
|
* dots - three dots that fade in and out in turn
|
|
9
9
|
|
|
10
|
-
Size is derived from the current font size and color is derived from
|
|
10
|
+
Size is derived from the current font size and color is derived from var(--px-spinner-color). These
|
|
11
11
|
properties (as well as a transform) can be set on the component itself without side effects.
|
|
12
12
|
|
|
13
13
|
Future enhancements could include additional properties for controlling things like timing,
|
|
@@ -27,7 +27,10 @@ import PxBaseVisible from './PxBaseVisible.vue';
|
|
|
27
27
|
export default {
|
|
28
28
|
name: 'px-spinner',
|
|
29
29
|
mixins: [PxBaseVariants, PxBaseVisible],
|
|
30
|
-
props: {
|
|
30
|
+
props: {
|
|
31
|
+
variant: { type: String, default: 'classic' },
|
|
32
|
+
duration: { type: Number, default: 2 },
|
|
33
|
+
},
|
|
31
34
|
};
|
|
32
35
|
</script>
|
|
33
36
|
|
|
@@ -39,6 +42,11 @@ export default {
|
|
|
39
42
|
position: relative;
|
|
40
43
|
pointer-events: none;
|
|
41
44
|
|
|
45
|
+
--px-spinner-dur: 2s;
|
|
46
|
+
--px-spinner-linewidth: 0.15em;
|
|
47
|
+
--px-spinner-color: currentColor;
|
|
48
|
+
--px-spinner-color-secondary: transparent;
|
|
49
|
+
|
|
42
50
|
&__spinner {
|
|
43
51
|
display: block;
|
|
44
52
|
position: relative;
|
|
@@ -48,14 +56,15 @@ export default {
|
|
|
48
56
|
|
|
49
57
|
&--classic & {
|
|
50
58
|
&__spinner {
|
|
59
|
+
position: relative;
|
|
51
60
|
width: 1.33em;
|
|
52
61
|
height: 1.33em;
|
|
53
|
-
border:
|
|
54
|
-
border-bottom-color:
|
|
62
|
+
border: var(--px-spinner-linewidth) solid var(--px-spinner-color);
|
|
63
|
+
border-bottom-color: var(--px-spinner-color-secondary);
|
|
55
64
|
border-radius: 50%;
|
|
56
65
|
display: inline-block;
|
|
57
66
|
box-sizing: border-box;
|
|
58
|
-
animation: px-spinner-classic
|
|
67
|
+
animation: px-spinner-classic var(--px-spinner-dur) linear infinite;
|
|
59
68
|
}
|
|
60
69
|
}
|
|
61
70
|
|
|
@@ -91,15 +100,15 @@ export default {
|
|
|
91
100
|
height: 2.5em;
|
|
92
101
|
border-radius: 50%;
|
|
93
102
|
animation-fill-mode: both;
|
|
94
|
-
animation: px-spinner-dots
|
|
103
|
+
animation: px-spinner-dots var(--px-spinner-dur) infinite $ease-in-out-quart;
|
|
95
104
|
}
|
|
96
105
|
&__spinner {
|
|
97
106
|
left: 5em;
|
|
98
|
-
color:
|
|
107
|
+
color: var(--px-spinner-color);
|
|
99
108
|
position: relative;
|
|
100
109
|
text-indent: -9999em;
|
|
101
110
|
transform: translateZ(0);
|
|
102
|
-
animation-delay: (
|
|
111
|
+
animation-delay: calc((var(--px-spinner-dur) * -0.088888888));
|
|
103
112
|
}
|
|
104
113
|
&__spinner:before,
|
|
105
114
|
&__spinner:after {
|
|
@@ -109,7 +118,7 @@ export default {
|
|
|
109
118
|
}
|
|
110
119
|
&__spinner:before {
|
|
111
120
|
left: -5em;
|
|
112
|
-
animation-delay: (
|
|
121
|
+
animation-delay: calc((var(--px-spinner-dur) * -0.088888888 * 2));
|
|
113
122
|
}
|
|
114
123
|
&__spinner:after {
|
|
115
124
|
left: 5em;
|
package/package.json
CHANGED
package/utils/utils.js
CHANGED
|
@@ -354,6 +354,53 @@ export default {
|
|
|
354
354
|
});
|
|
355
355
|
},
|
|
356
356
|
|
|
357
|
+
/**
|
|
358
|
+
* Converts a floating-point number to a string value based on a map where the keys are string
|
|
359
|
+
* values and the corresponding values define ranges in the format 'start, end'. Open-ended
|
|
360
|
+
* ranges can be specified by using `null` for the start or end value. This approach avoids
|
|
361
|
+
* ambiguity with negative numbers by using commas to separate the range values. If the input
|
|
362
|
+
* value does not fall within any of the defined ranges, a fallback value is returned.
|
|
363
|
+
*
|
|
364
|
+
* @param {number} value - The floating-point number to be converted.
|
|
365
|
+
* @param {Object} valueMap - An object where keys are string values and values define ranges in
|
|
366
|
+
* the format 'start, end'. Use `null` to specify an open-ended start or end of a range.
|
|
367
|
+
* @param {string} fallbackValue - The value to return if the input does not match any defined
|
|
368
|
+
* range.
|
|
369
|
+
* @returns {string} - The string value corresponding to the range within which the input value
|
|
370
|
+
* falls, or the fallback value.
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* const valueMap = {
|
|
374
|
+
* 'low': 'null, 0.5',
|
|
375
|
+
* 'medium': '0.5, 1',
|
|
376
|
+
* 'high': '1, null'
|
|
377
|
+
* };
|
|
378
|
+
* const fallback = 'unknown';
|
|
379
|
+
*
|
|
380
|
+
* console.log(floatToEnum(0.25, valueMap, fallback)); // Expected "low"
|
|
381
|
+
* console.log(floatToEnum(0.75, valueMap, fallback)); // Expected "medium"
|
|
382
|
+
* console.log(floatToEnum(1.5, valueMap, fallback)); // Expected "high"
|
|
383
|
+
* console.log(floatToEnum(-1, valueMap, fallback)); // Expected "unknown"
|
|
384
|
+
**/
|
|
385
|
+
|
|
386
|
+
floatToEnum(value, valueMap, fallbackValue) {
|
|
387
|
+
const rangeRegex = /^\s*(null|[+-]?\d*(?:\.\d+)?)\s*,\s*(null|[+-]?\d*(?:\.\d+)?)\s*$/;
|
|
388
|
+
|
|
389
|
+
for (const [stringValue, range] of Object.entries(valueMap)) {
|
|
390
|
+
const match = range.match(rangeRegex);
|
|
391
|
+
if (!match) continue; // Skip invalid ranges
|
|
392
|
+
|
|
393
|
+
const start = match[1] !== 'null' ? parseFloat(match[1]) : -Infinity;
|
|
394
|
+
const end = match[2] !== 'null' ? parseFloat(match[2]) : Infinity;
|
|
395
|
+
|
|
396
|
+
if ((start === -Infinity || value >= start) && (end === Infinity || value < end)) {
|
|
397
|
+
return stringValue;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return fallbackValue;
|
|
402
|
+
},
|
|
403
|
+
|
|
357
404
|
/**
|
|
358
405
|
* Generate a 6 letter random sequence of letters and numbers, based on this:
|
|
359
406
|
* https://stackoverflow.com/questions/6248666/how-to-generate-short-uid-like-ax4j9z-in-js
|