@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linear_non/stellar-libs",
3
- "version": "1.2.6",
3
+ "version": "1.2.7",
4
4
  "description": "Reusable JavaScript libraries for Non-Linear Studio projects.",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -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 }