@linear_non/stellar-kit 2.1.6 → 2.1.8
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/classes/Component.js +14 -20
- package/classes/Manager.js +48 -41
- package/package.json +1 -1
- package/plugins/Observer.js +54 -20
- package/plugins/SplitText.js +42 -18
package/classes/Component.js
CHANGED
|
@@ -1,32 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
import { qs, bounds } from "../utils"
|
|
1
|
+
import { bounds } from "../utils"
|
|
3
2
|
|
|
4
3
|
export default class Component {
|
|
5
|
-
constructor(
|
|
6
|
-
this.el =
|
|
7
|
-
this.
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
constructor({ el = null, index = 0, renderer = null, data = null } = {}) {
|
|
5
|
+
this.el = el
|
|
6
|
+
this.index = index
|
|
7
|
+
this.renderer = renderer
|
|
8
|
+
this.data = data
|
|
10
9
|
|
|
11
|
-
this.
|
|
12
|
-
this.hasAnimateIn = data?.hasAnimateIn || false
|
|
13
|
-
this.hasAnimateOut = data?.hasAnimateOut || false
|
|
14
|
-
this.hasAnimateOnScroll = data?.hasAnimateOnScroll || false
|
|
15
|
-
|
|
16
|
-
if (this.el) this.rect = bounds(this.el)
|
|
10
|
+
this.rect = this.el ? bounds(this.el) : null
|
|
17
11
|
}
|
|
18
12
|
|
|
19
|
-
setup() {
|
|
20
|
-
if (!this.name) return
|
|
21
|
-
this.el = qs(`[data-${this.name}]`)
|
|
22
|
-
}
|
|
13
|
+
setup() {}
|
|
23
14
|
|
|
24
15
|
animateIn() {}
|
|
25
16
|
animateOut() {}
|
|
26
17
|
animateOnScroll() {}
|
|
27
18
|
|
|
28
|
-
tick(
|
|
29
|
-
|
|
19
|
+
tick(_ctx) {}
|
|
20
|
+
|
|
21
|
+
resize() {
|
|
22
|
+
if (this.el) this.rect = bounds(this.el)
|
|
23
|
+
}
|
|
24
|
+
|
|
30
25
|
smoothResize() {}
|
|
31
26
|
|
|
32
27
|
on() {}
|
|
@@ -41,6 +36,5 @@ export default class Component {
|
|
|
41
36
|
render() {
|
|
42
37
|
this.setup()
|
|
43
38
|
this.on()
|
|
44
|
-
if (this.hasAnimateOnScroll) this.animateOnScroll()
|
|
45
39
|
}
|
|
46
40
|
}
|
package/classes/Manager.js
CHANGED
|
@@ -1,73 +1,80 @@
|
|
|
1
|
-
// Manager.js
|
|
2
1
|
import { qsa } from "../utils"
|
|
3
2
|
|
|
4
3
|
export default class Manager {
|
|
5
|
-
constructor() {
|
|
4
|
+
constructor({ renderer = null, data = {} } = {}) {
|
|
6
5
|
this.components = []
|
|
6
|
+
|
|
7
|
+
this.renderer = renderer
|
|
8
|
+
this.data = data
|
|
7
9
|
}
|
|
8
10
|
|
|
9
|
-
addComponent(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const data =
|
|
13
|
-
|
|
11
|
+
addComponent(def) {
|
|
12
|
+
if (!def || !def.instance || !def.name) return
|
|
13
|
+
|
|
14
|
+
const { name, instance, data = null } = def
|
|
15
|
+
|
|
16
|
+
// resolve selector from name
|
|
17
|
+
let selector
|
|
18
|
+
if (name.startsWith(".")) {
|
|
19
|
+
// "Class: .c-hero"
|
|
20
|
+
selector = name
|
|
21
|
+
} else if (name.startsWith("[")) {
|
|
22
|
+
// "Dataset: [data-video]"
|
|
23
|
+
selector = name
|
|
24
|
+
} else {
|
|
25
|
+
// "Transform: hero" -> "[data-hero]"
|
|
26
|
+
selector = `[data-${name}]`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const els = qsa(selector)
|
|
30
|
+
if (!els.length) return
|
|
14
31
|
|
|
15
|
-
|
|
16
|
-
data.hasAnimateIn = obj.hasAnimateIn || false
|
|
17
|
-
data.hasAnimateOut = obj.hasAnimateOut || false
|
|
18
|
-
data.hasAnimateOnScroll = obj.hasAnimateOnScroll || false
|
|
32
|
+
const mergedData = data ? { ...this.data, ...data } : this.data
|
|
19
33
|
|
|
20
34
|
els.forEach((el, index) => {
|
|
21
|
-
const
|
|
22
|
-
|
|
35
|
+
const c = new instance({
|
|
36
|
+
el,
|
|
37
|
+
index,
|
|
38
|
+
name,
|
|
39
|
+
renderer: this.renderer,
|
|
40
|
+
data: mergedData,
|
|
41
|
+
})
|
|
42
|
+
this.components.push(c)
|
|
23
43
|
})
|
|
24
44
|
}
|
|
25
45
|
|
|
26
|
-
|
|
27
|
-
this.components.forEach(
|
|
28
|
-
|
|
46
|
+
_call(method, ...args) {
|
|
47
|
+
this.components.forEach(c => {
|
|
48
|
+
const fn = c[method]
|
|
49
|
+
if (typeof fn === "function") fn.apply(c, args)
|
|
29
50
|
})
|
|
30
51
|
}
|
|
31
52
|
|
|
32
|
-
|
|
33
|
-
this.
|
|
34
|
-
component.hasAnimateIn && component.animateIn()
|
|
35
|
-
})
|
|
53
|
+
initialize() {
|
|
54
|
+
this._call("render")
|
|
36
55
|
}
|
|
37
56
|
|
|
38
|
-
|
|
39
|
-
this.
|
|
40
|
-
component.hasAnimateOut && component.animateOut()
|
|
41
|
-
})
|
|
57
|
+
animateIn() {
|
|
58
|
+
this._call("animateIn")
|
|
42
59
|
}
|
|
43
60
|
|
|
44
|
-
|
|
45
|
-
this.
|
|
46
|
-
component.hasAnimateOnScroll && component.animateOnScroll()
|
|
47
|
-
})
|
|
61
|
+
animateOut() {
|
|
62
|
+
this._call("animateOut")
|
|
48
63
|
}
|
|
49
64
|
|
|
50
|
-
|
|
51
|
-
this.
|
|
52
|
-
component.hasTick && component.tick(obj)
|
|
53
|
-
})
|
|
65
|
+
tick(obj) {
|
|
66
|
+
this._call("tick", obj)
|
|
54
67
|
}
|
|
55
68
|
|
|
56
69
|
resize() {
|
|
57
|
-
this.
|
|
58
|
-
component?.resize()
|
|
59
|
-
})
|
|
70
|
+
this._call("resize")
|
|
60
71
|
}
|
|
61
72
|
|
|
62
73
|
smoothResize() {
|
|
63
|
-
this.
|
|
64
|
-
component?.smoothResize()
|
|
65
|
-
})
|
|
74
|
+
this._call("smoothResize")
|
|
66
75
|
}
|
|
67
76
|
|
|
68
77
|
destroy() {
|
|
69
|
-
this.
|
|
70
|
-
component?.destroy()
|
|
71
|
-
})
|
|
78
|
+
this._call("destroy")
|
|
72
79
|
}
|
|
73
80
|
}
|
package/package.json
CHANGED
package/plugins/Observer.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
// libs/observer/Observer.js
|
|
2
|
-
import { ScrollTrigger } from "../libraries/gsap"
|
|
3
1
|
import { Emitter } from "../events"
|
|
2
|
+
import { ScrollTrigger } from "../libraries/gsap"
|
|
4
3
|
|
|
5
4
|
const DEFAULTS = {
|
|
6
5
|
trigger: null,
|
|
@@ -14,49 +13,83 @@ const DEFAULTS = {
|
|
|
14
13
|
export default class Observer extends Emitter {
|
|
15
14
|
constructor(opts = {}) {
|
|
16
15
|
super()
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
|
|
17
|
+
const merged = { ...DEFAULTS, ...opts }
|
|
18
|
+
if (!merged.trigger) {
|
|
19
|
+
throw new Error("Observer: `trigger` is required")
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
this.opts = merged
|
|
23
|
+
|
|
24
|
+
const { trigger, start, end, scrub, once, markers } = this.opts
|
|
25
|
+
const forward = type => self => this.emit(type, self, this)
|
|
19
26
|
|
|
20
27
|
this.st = ScrollTrigger.create({
|
|
21
|
-
trigger
|
|
22
|
-
start
|
|
23
|
-
end
|
|
24
|
-
scrub
|
|
25
|
-
once
|
|
26
|
-
markers
|
|
27
|
-
onEnter:
|
|
28
|
-
onLeave:
|
|
29
|
-
onEnterBack:
|
|
30
|
-
onLeaveBack:
|
|
31
|
-
onUpdate:
|
|
28
|
+
trigger,
|
|
29
|
+
start,
|
|
30
|
+
end,
|
|
31
|
+
scrub,
|
|
32
|
+
once,
|
|
33
|
+
markers,
|
|
34
|
+
onEnter: forward("enter"),
|
|
35
|
+
onLeave: forward("leave"),
|
|
36
|
+
onEnterBack: forward("enterBack"),
|
|
37
|
+
onLeaveBack: forward("leaveBack"),
|
|
38
|
+
onUpdate: forward("update"),
|
|
32
39
|
})
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
|
|
41
|
+
const listeners = this.opts.listeners
|
|
42
|
+
if (listeners) {
|
|
43
|
+
for (const [type, fn] of Object.entries(listeners)) {
|
|
36
44
|
this.on(type, fn)
|
|
37
45
|
}
|
|
38
46
|
}
|
|
39
47
|
}
|
|
40
48
|
|
|
49
|
+
// allow ["enter","enterBack"]
|
|
50
|
+
on(types, fn) {
|
|
51
|
+
if (Array.isArray(types)) {
|
|
52
|
+
types.forEach(t => super.on(t, fn))
|
|
53
|
+
} else {
|
|
54
|
+
super.on(types, fn)
|
|
55
|
+
}
|
|
56
|
+
return this
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
off(types, fn) {
|
|
60
|
+
if (Array.isArray(types)) {
|
|
61
|
+
types.forEach(t => super.off(t, fn))
|
|
62
|
+
} else {
|
|
63
|
+
super.off(types, fn)
|
|
64
|
+
}
|
|
65
|
+
return this
|
|
66
|
+
}
|
|
67
|
+
|
|
41
68
|
refresh() {
|
|
42
69
|
this.st?.refresh()
|
|
43
70
|
return this
|
|
44
71
|
}
|
|
72
|
+
|
|
45
73
|
enable() {
|
|
46
74
|
this.st?.enable()
|
|
47
75
|
return this
|
|
48
76
|
}
|
|
77
|
+
|
|
49
78
|
disable() {
|
|
50
79
|
this.st?.disable()
|
|
51
80
|
return this
|
|
52
81
|
}
|
|
53
82
|
|
|
54
|
-
update(
|
|
55
|
-
if (!this.st) return this
|
|
83
|
+
update(next) {
|
|
84
|
+
if (!this.st || !next) return this
|
|
85
|
+
|
|
86
|
+
const { start, end, scrub, markers } = next
|
|
87
|
+
|
|
56
88
|
if (start !== undefined) this.st.vars.start = start
|
|
57
89
|
if (end !== undefined) this.st.vars.end = end
|
|
58
90
|
if (scrub !== undefined) this.st.vars.scrub = scrub
|
|
59
91
|
if (markers !== undefined) this.st.vars.markers = markers
|
|
92
|
+
|
|
60
93
|
this.st.refresh()
|
|
61
94
|
return this
|
|
62
95
|
}
|
|
@@ -68,13 +101,14 @@ export default class Observer extends Emitter {
|
|
|
68
101
|
return this
|
|
69
102
|
}
|
|
70
103
|
|
|
71
|
-
// Handy getters
|
|
72
104
|
get progress() {
|
|
73
105
|
return this.st?.progress ?? 0
|
|
74
106
|
}
|
|
107
|
+
|
|
75
108
|
get isActive() {
|
|
76
109
|
return !!this.st?.isActive
|
|
77
110
|
}
|
|
111
|
+
|
|
78
112
|
get direction() {
|
|
79
113
|
return this.st?.direction ?? 1
|
|
80
114
|
}
|
package/plugins/SplitText.js
CHANGED
|
@@ -1,42 +1,66 @@
|
|
|
1
|
-
// splitText.js
|
|
2
1
|
import { Emitter, EVENTS } from "../events"
|
|
3
2
|
import { SplitText } from "../libraries/gsap"
|
|
4
3
|
|
|
5
4
|
export const splitText = data => {
|
|
6
5
|
const emitter = new Emitter()
|
|
7
6
|
const splits = []
|
|
8
|
-
|
|
7
|
+
const groups = {}
|
|
8
|
+
|
|
9
|
+
// Normalize to array and drop nulls/undefined
|
|
10
|
+
const items = Array.from(data || []).filter(Boolean)
|
|
11
|
+
|
|
12
|
+
// When no items, emit ready immediately
|
|
13
|
+
if (items.length === 0) {
|
|
14
|
+
queueMicrotask(() => {
|
|
15
|
+
emitter.emit(EVENTS.APP_SPLITTEXT_READY, splits, groups)
|
|
16
|
+
})
|
|
17
|
+
return emitter
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
items.forEach((el, elIndex) => {
|
|
21
|
+
const raw = el.dataset.split || ""
|
|
22
|
+
const types = raw
|
|
23
|
+
.split(/[,\s]+/)
|
|
24
|
+
.map(t => t.trim())
|
|
25
|
+
.filter(Boolean)
|
|
9
26
|
|
|
10
|
-
data.forEach(el => {
|
|
11
|
-
const dataset = el.dataset.split || ""
|
|
12
|
-
const parts = dataset.split(",")
|
|
13
27
|
const classes = {}
|
|
14
28
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (t === "
|
|
18
|
-
if (t === "
|
|
19
|
-
if (t === "chars") classes.charsClass = `char-${i} chr-++`
|
|
29
|
+
types.forEach(t => {
|
|
30
|
+
if (t === "lines") classes.linesClass = `line-${elIndex}`
|
|
31
|
+
if (t === "words") classes.wordsClass = `word-${elIndex}`
|
|
32
|
+
if (t === "chars") classes.charsClass = `char-${elIndex} chr`
|
|
20
33
|
})
|
|
21
34
|
|
|
35
|
+
const typeString = types.length ? types.join(",") : raw
|
|
36
|
+
|
|
22
37
|
const splitInstance = new SplitText(el, {
|
|
23
|
-
type:
|
|
38
|
+
type: typeString,
|
|
24
39
|
...classes,
|
|
25
40
|
})
|
|
26
41
|
|
|
27
42
|
splits.push(splitInstance)
|
|
28
|
-
remaining -= 1
|
|
29
43
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
44
|
+
// Grouping via data-split-group attribute if present
|
|
45
|
+
const groupName = el.dataset.splitGroup
|
|
46
|
+
if (groupName) {
|
|
47
|
+
if (!groups[groupName]) groups[groupName] = []
|
|
48
|
+
groups[groupName].push(splitInstance)
|
|
34
49
|
}
|
|
35
50
|
})
|
|
36
51
|
|
|
52
|
+
queueMicrotask(() => {
|
|
53
|
+
emitter.emit(EVENTS.APP_SPLITTEXT_READY, splits, groups)
|
|
54
|
+
})
|
|
55
|
+
|
|
37
56
|
return emitter
|
|
38
57
|
}
|
|
39
58
|
|
|
40
|
-
export const reverseSplit =
|
|
41
|
-
|
|
59
|
+
export const reverseSplit = splits => {
|
|
60
|
+
if (!splits) return
|
|
61
|
+
for (const split of splits) {
|
|
62
|
+
if (split && typeof split.revert === "function") {
|
|
63
|
+
split.revert()
|
|
64
|
+
}
|
|
65
|
+
}
|
|
42
66
|
}
|