@linear_non/stellar-libs 1.2.6 → 1.2.7
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/package.json +1 -1
- package/src/CursorTracker/index.js +74 -0
- package/src/Marquee/index.js +91 -0
- package/src/index.js +3 -1
package/package.json
CHANGED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { lerp } from "@linear_non/stellar-kit/utils"
|
|
2
|
+
import { gsap } from "@linear_non/stellar-kit/gsap"
|
|
3
|
+
|
|
4
|
+
export default class CursorTracker {
|
|
5
|
+
constructor({ container, el, ease = 0.12, isCentered = true }) {
|
|
6
|
+
this.container = container
|
|
7
|
+
this.el = el
|
|
8
|
+
this.ease = ease
|
|
9
|
+
this.isCentered = isCentered
|
|
10
|
+
|
|
11
|
+
this.pos = { x: 0, y: 0 }
|
|
12
|
+
this.target = { x: 0, y: 0 }
|
|
13
|
+
this.isHovering = false
|
|
14
|
+
|
|
15
|
+
this.init()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
setup() {
|
|
19
|
+
if (this.isCentered) {
|
|
20
|
+
gsap.set(this.el, { xPercent: -50, yPercent: -50 })
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// GLOBAL TICK
|
|
25
|
+
tick({ mouse }) {
|
|
26
|
+
if (!this.isHovering) return
|
|
27
|
+
|
|
28
|
+
this.target.x = mouse.x
|
|
29
|
+
this.target.y = mouse.y
|
|
30
|
+
|
|
31
|
+
this.pos.x = lerp(this.pos.x, this.target.x, this.ease)
|
|
32
|
+
this.pos.y = lerp(this.pos.y, this.target.y, this.ease)
|
|
33
|
+
|
|
34
|
+
gsap.set(this.el, {
|
|
35
|
+
x: this.pos.x,
|
|
36
|
+
y: this.pos.y,
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
hoverIn = () => {
|
|
41
|
+
this.isHovering = true
|
|
42
|
+
gsap.to(this.el, { autoAlpha: 1, duration: 0.2, overwrite: true })
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
hoverOut = () => {
|
|
46
|
+
this.isHovering = false
|
|
47
|
+
gsap.to(this.el, { autoAlpha: 0, duration: 0.2, overwrite: true })
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
on() {
|
|
51
|
+
if (!this.container) return
|
|
52
|
+
|
|
53
|
+
this.container.addEventListener("mouseenter", this.hoverIn)
|
|
54
|
+
this.container.addEventListener("mouseleave", this.hoverOut)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
off() {
|
|
58
|
+
if (!this.container) return
|
|
59
|
+
|
|
60
|
+
this.container.removeEventListener("mouseenter", this.hoverIn)
|
|
61
|
+
this.container.removeEventListener("mouseleave", this.hoverOut)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
destroy() {
|
|
65
|
+
this.off()
|
|
66
|
+
this.container = null
|
|
67
|
+
this.el = null
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
init() {
|
|
71
|
+
this.setup()
|
|
72
|
+
this.on()
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { gsap } from "@linear_non/stellar-kit/gsap"
|
|
2
|
+
|
|
3
|
+
export default class Marquee {
|
|
4
|
+
constructor({ container, el, speed = 50, gap = "1.6rem" }) {
|
|
5
|
+
this.container = container
|
|
6
|
+
this.el = el
|
|
7
|
+
this.speed = speed
|
|
8
|
+
this.gap = gap
|
|
9
|
+
this.tween = null
|
|
10
|
+
this.init()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
setup() {
|
|
14
|
+
if (this.tween) this.tween.kill()
|
|
15
|
+
|
|
16
|
+
gsap.set(this.container, {
|
|
17
|
+
overflow: "hidden",
|
|
18
|
+
display: "flex",
|
|
19
|
+
alignItems: "flex-start",
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
gsap.set(this.el, {
|
|
23
|
+
display: "flex",
|
|
24
|
+
whiteSpace: "nowrap",
|
|
25
|
+
width: "max-content",
|
|
26
|
+
x: 0,
|
|
27
|
+
gap: this.gap,
|
|
28
|
+
willChange: "transform",
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const source = this.el.children[0]
|
|
32
|
+
if (!source) return
|
|
33
|
+
|
|
34
|
+
// Use bounding rect for more accurate (subpixel) width
|
|
35
|
+
const itemWidth = source.getBoundingClientRect().width
|
|
36
|
+
if (!itemWidth) return
|
|
37
|
+
|
|
38
|
+
// Convert computed gap to px
|
|
39
|
+
const gapPx = parseFloat(getComputedStyle(this.el).gap) || 0
|
|
40
|
+
|
|
41
|
+
// One "step" includes the gap after the item
|
|
42
|
+
const stepWidth = itemWidth + gapPx
|
|
43
|
+
|
|
44
|
+
// Copies needed to cover viewport (+ a little buffer)
|
|
45
|
+
const copies = Math.ceil(window.innerWidth / stepWidth) + 2
|
|
46
|
+
|
|
47
|
+
while (this.el.children.length < copies * 2) {
|
|
48
|
+
const clone = source.cloneNode(true)
|
|
49
|
+
clone.setAttribute("aria-hidden", "true")
|
|
50
|
+
this.el.appendChild(clone)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Loop distance must include gaps too
|
|
54
|
+
const setWidth = copies * stepWidth
|
|
55
|
+
const duration = setWidth / this.speed
|
|
56
|
+
|
|
57
|
+
const wrapX = gsap.utils.wrap(-setWidth, 0)
|
|
58
|
+
|
|
59
|
+
this.tween = gsap.to(this.el, {
|
|
60
|
+
x: `-=${setWidth}`,
|
|
61
|
+
duration,
|
|
62
|
+
ease: "none",
|
|
63
|
+
repeat: -1,
|
|
64
|
+
modifiers: {
|
|
65
|
+
// GSAP gives strings like "-123.45px"
|
|
66
|
+
x: v => `${wrapX(parseFloat(v))}px`,
|
|
67
|
+
},
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
on() {
|
|
72
|
+
this._onResize = () => this.setup()
|
|
73
|
+
window.addEventListener("resize", this._onResize)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
off() {
|
|
77
|
+
if (this._onResize) window.removeEventListener("resize", this._onResize)
|
|
78
|
+
this._onResize = null
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
destroy() {
|
|
82
|
+
this.off()
|
|
83
|
+
if (this.tween) this.tween.kill()
|
|
84
|
+
this.tween = null
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
init() {
|
|
88
|
+
this.setup()
|
|
89
|
+
this.on()
|
|
90
|
+
}
|
|
91
|
+
}
|
package/src/index.js
CHANGED
|
@@ -3,5 +3,7 @@ import Smooth from "./Smooth"
|
|
|
3
3
|
import SplitonScroll from "./SplitOnScroll"
|
|
4
4
|
import Noise from "./Noise"
|
|
5
5
|
import SpritePlayer from "./SpritePlayer"
|
|
6
|
+
import CursorTracker from "./CursorTracker"
|
|
7
|
+
import Marquee from "./Marquee"
|
|
6
8
|
|
|
7
|
-
export { Sticky, Smooth, SplitonScroll, Noise, SpritePlayer }
|
|
9
|
+
export { Sticky, Smooth, SplitonScroll, Noise, SpritePlayer, CursorTracker, Marquee }
|