@linear_non/stellar-libs 1.2.5 → 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/Sticky/index.js +28 -6
- 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/Sticky/index.js
CHANGED
|
@@ -5,13 +5,14 @@ import { kitStore } from "@linear_non/stellar-kit"
|
|
|
5
5
|
|
|
6
6
|
export default class Sticky {
|
|
7
7
|
constructor(obj) {
|
|
8
|
-
const { el, sticky, container, isSmooth, onUpdateCallback } = obj
|
|
8
|
+
const { el, sticky, container, frame, isSmooth, onUpdateCallback } = obj
|
|
9
9
|
|
|
10
10
|
this.el = el
|
|
11
11
|
this.sticky = sticky
|
|
12
12
|
this.isSticky = false
|
|
13
13
|
this.isSmooth = isSmooth
|
|
14
14
|
this.container = container
|
|
15
|
+
this.frame = frame || null
|
|
15
16
|
this.progress = 0
|
|
16
17
|
this.total = 0
|
|
17
18
|
this.positionX = 0
|
|
@@ -97,13 +98,34 @@ export default class Sticky {
|
|
|
97
98
|
resize() {
|
|
98
99
|
if (!this.sticky) return
|
|
99
100
|
|
|
100
|
-
// Get the viewport height dynamically instead of using store
|
|
101
101
|
const vh = window.innerHeight
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
|
|
103
|
+
const stickyRect = bounds(this.el)
|
|
104
|
+
|
|
105
|
+
// HEIGHT (same as you have)
|
|
106
106
|
this.config.totalHeight = this.snap(stickyRect.height - vh)
|
|
107
|
+
|
|
108
|
+
// WIDTH (fix)
|
|
109
|
+
if (!this.container) {
|
|
110
|
+
this.config.totalWidth = 0
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const frameEl = this.frame || this.container.parentElement
|
|
115
|
+
const frameRect = frameEl ? bounds(frameEl) : { width: window.innerWidth }
|
|
116
|
+
|
|
117
|
+
let padL = 0
|
|
118
|
+
let padR = 0
|
|
119
|
+
if (frameEl) {
|
|
120
|
+
const cs = getComputedStyle(frameEl)
|
|
121
|
+
padL = parseFloat(cs.paddingLeft) || 0
|
|
122
|
+
padR = parseFloat(cs.paddingRight) || 0
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const visibleContentWidth = Math.max(0, frameRect.width - padL - padR)
|
|
126
|
+
const totalContentWidth = this.container.scrollWidth || bounds(this.container).width
|
|
127
|
+
|
|
128
|
+
this.config.totalWidth = this.snap(Math.max(0, totalContentWidth - visibleContentWidth))
|
|
107
129
|
}
|
|
108
130
|
|
|
109
131
|
destroy() {
|
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 }
|