@linear_non/stellar-kit 3.0.8 → 3.0.11
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/README.md +49 -41
- package/classes/Component.js +0 -2
- package/classes/ImageLoader.js +34 -8
- package/core/PageEngine.js +24 -6
- package/events/Emitter.js +4 -1
- package/events/Mouse.js +1 -3
- package/events/Raf.js +7 -1
- package/events/VirtualScroll.js +19 -45
- package/kitStore.js +25 -1
- package/package.json +2 -2
- package/utils/index.js +1 -1
- package/utils/math.js +2 -2
- package/utils/sniffer.js +13 -35
- package/utils/support.js +0 -15
package/README.md
CHANGED
|
@@ -1,67 +1,75 @@
|
|
|
1
1
|
# stellar-kit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> `@linear_non/stellar-kit` — Front-end core framework for Non-Linear Studio projects.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A modular frontend toolkit that handles the application lifecycle, scroll management (internal smooth scroll via VirtualScroll or external via Lenis), per-frame animation ticking, component orchestration, asset loading, and responsive layout utilities.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- Virtual scroll support (`Scroll`)
|
|
9
|
-
- Viewport-based resize tracking (`Resize`)
|
|
10
|
-
- Centralized event system (`Emitter`)
|
|
11
|
-
- Mouse tracking (`Mouse`)
|
|
12
|
-
- Utility helpers (DOM selection, bounds, clamping, etc.)
|
|
13
|
-
- Designed for use with Astro, GSAP, Three.js, and modular frontend setups
|
|
14
|
-
|
|
15
|
-
## 📦 Installation
|
|
7
|
+
## Installation
|
|
16
8
|
|
|
17
9
|
```bash
|
|
18
10
|
npm install @linear_non/stellar-kit
|
|
19
|
-
|
|
20
11
|
```
|
|
21
12
|
|
|
22
|
-
##
|
|
13
|
+
## Quick Start
|
|
23
14
|
|
|
24
|
-
```
|
|
25
|
-
stellar-kit/
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
15
|
+
```js
|
|
16
|
+
import { Application } from "@linear_non/stellar-kit/core"
|
|
17
|
+
|
|
18
|
+
await Application.initialize({
|
|
19
|
+
url: window.location,
|
|
20
|
+
page: { element: "[data-taxi-view]", container: "#app" },
|
|
21
|
+
isSmooth: true,
|
|
22
|
+
useExternalScroll: false,
|
|
23
|
+
dim: { d: 1440, m: 390 },
|
|
24
|
+
})
|
|
32
25
|
```
|
|
33
26
|
|
|
34
|
-
##
|
|
27
|
+
## Imports
|
|
35
28
|
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
|
|
29
|
+
```js
|
|
30
|
+
import { kitStore } from "@linear_non/stellar-kit"
|
|
31
|
+
import { Application, PageEngine } from "@linear_non/stellar-kit/core"
|
|
32
|
+
import { Component, Manager, MasterLoader, ImageLoader, FontLoader } from "@linear_non/stellar-kit/classes"
|
|
33
|
+
import { emitter, EVENTS, PRIORITY } from "@linear_non/stellar-kit/events"
|
|
34
|
+
import { Grid, Observer, splitText, reverseSplit } from "@linear_non/stellar-kit/plugins"
|
|
35
|
+
import { qs, qsa, bounds, lerp, clamp, sniffer, listener } from "@linear_non/stellar-kit/utils"
|
|
36
|
+
import { gsap, ScrollTrigger, SplitText } from "@linear_non/stellar-kit/gsap"
|
|
39
37
|
```
|
|
40
38
|
|
|
41
|
-
|
|
39
|
+
## Architecture
|
|
42
40
|
|
|
43
|
-
|
|
41
|
+
| Module | Purpose |
|
|
42
|
+
| --------- | ------------------------------------------------------------- |
|
|
43
|
+
| `core` | `Application` singleton + `PageEngine` per-page lifecycle |
|
|
44
|
+
| `classes` | `Component` base class, `Manager`, asset loaders |
|
|
45
|
+
| `events` | `Emitter` pub/sub, `Raf`, `Resize`, `Scroll`, `Mouse` |
|
|
46
|
+
| `plugins` | `Grid` overlay, `Observer` (ScrollTrigger), `splitText` |
|
|
47
|
+
| `utils` | DOM helpers, math, sniffer, viewport, debug |
|
|
48
|
+
| `gsap` | Pre-configured GSAP with ScrollTrigger, SplitText, CustomEase |
|
|
44
49
|
|
|
45
|
-
|
|
46
|
-
// main.js or index.js of your project
|
|
47
|
-
import { kitStore, setupKit } from "stellar-kit"
|
|
50
|
+
## Scroll Modes
|
|
48
51
|
|
|
49
|
-
|
|
52
|
+
**Internal** — VirtualScroll + lerp interpolation in Raf:
|
|
50
53
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
kitStore.raf
|
|
54
|
-
kitStore.mouse
|
|
54
|
+
```js
|
|
55
|
+
engine.setup({ components, smooth })
|
|
55
56
|
```
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
**External (Lenis)** — Lenis manages scroll, PageEngine sets up ScrollTrigger proxy:
|
|
58
59
|
|
|
59
60
|
```js
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
engine.setup({ components, lenis, wrapper })
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Local Development
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npm install
|
|
68
|
+
npm run dev
|
|
63
69
|
```
|
|
64
70
|
|
|
65
|
-
|
|
71
|
+
The `dev/` folder provides a Vite playground for testing.
|
|
72
|
+
|
|
73
|
+
## License
|
|
66
74
|
|
|
67
|
-
|
|
75
|
+
MIT — [Non-Linear Studio](https://non-linear.studio)
|
package/classes/Component.js
CHANGED
package/classes/ImageLoader.js
CHANGED
|
@@ -24,6 +24,8 @@ export default class ImageLoader {
|
|
|
24
24
|
|
|
25
25
|
this._results = new Map() // url -> HTMLImageElement
|
|
26
26
|
this._objectURLs = [] // for revoke
|
|
27
|
+
this._worker = null // shared worker instance
|
|
28
|
+
this._workerURL = null // blob URL for cleanup
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
async load() {
|
|
@@ -61,6 +63,9 @@ export default class ImageLoader {
|
|
|
61
63
|
|
|
62
64
|
await Promise.all(toLoad.map(url => this._loadOne(url)))
|
|
63
65
|
|
|
66
|
+
// Terminate shared worker if created
|
|
67
|
+
this._terminateWorker()
|
|
68
|
+
|
|
64
69
|
// build ordered result (use cache first, then freshly loaded)
|
|
65
70
|
this.images = urls.map(u => this.cache?.get(u) || this._results.get(u) || null)
|
|
66
71
|
this.isLoaded = true
|
|
@@ -69,19 +74,34 @@ export default class ImageLoader {
|
|
|
69
74
|
}
|
|
70
75
|
|
|
71
76
|
_createInlineWorker() {
|
|
77
|
+
if (this._worker) return this._worker
|
|
78
|
+
|
|
72
79
|
const code = `
|
|
73
80
|
self.onmessage = async (e) => {
|
|
74
|
-
const { url } = e.data;
|
|
81
|
+
const { url, id } = e.data;
|
|
75
82
|
try {
|
|
76
83
|
const res = await fetch(url);
|
|
77
84
|
const blob = await res.blob();
|
|
78
|
-
self.postMessage({ url, blob });
|
|
85
|
+
self.postMessage({ url, id, blob });
|
|
79
86
|
} catch (err) {
|
|
80
|
-
self.postMessage({ url, error: String(err) });
|
|
87
|
+
self.postMessage({ url, id, error: String(err) });
|
|
81
88
|
}
|
|
82
89
|
};`
|
|
83
90
|
const blob = new Blob([code], { type: "application/javascript" })
|
|
84
|
-
|
|
91
|
+
this._workerURL = URL.createObjectURL(blob)
|
|
92
|
+
this._worker = new Worker(this._workerURL)
|
|
93
|
+
return this._worker
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
_terminateWorker() {
|
|
97
|
+
if (this._worker) {
|
|
98
|
+
this._worker.terminate()
|
|
99
|
+
this._worker = null
|
|
100
|
+
}
|
|
101
|
+
if (this._workerURL) {
|
|
102
|
+
URL.revokeObjectURL(this._workerURL)
|
|
103
|
+
this._workerURL = null
|
|
104
|
+
}
|
|
85
105
|
}
|
|
86
106
|
|
|
87
107
|
async _loadOne(url) {
|
|
@@ -89,20 +109,25 @@ export default class ImageLoader {
|
|
|
89
109
|
if (this.useWorker && typeof Worker !== "undefined") {
|
|
90
110
|
return new Promise(resolve => {
|
|
91
111
|
const w = this._createInlineWorker()
|
|
92
|
-
|
|
112
|
+
const id = url // use url as unique message id
|
|
113
|
+
|
|
114
|
+
const handler = async e => {
|
|
115
|
+
if (e.data.id !== id) return // not our message
|
|
116
|
+
w.removeEventListener("message", handler)
|
|
117
|
+
|
|
93
118
|
const { blob, error } = e.data
|
|
94
119
|
if (error || !blob) {
|
|
95
120
|
this._bumpProgress()
|
|
96
|
-
w.terminate()
|
|
97
121
|
return resolve(null)
|
|
98
122
|
}
|
|
99
123
|
const img = await this._blobToImage(blob)
|
|
100
124
|
this._store(url, img)
|
|
101
125
|
this._bumpProgress()
|
|
102
|
-
w.terminate()
|
|
103
126
|
resolve(img)
|
|
104
127
|
}
|
|
105
|
-
|
|
128
|
+
|
|
129
|
+
w.addEventListener("message", handler)
|
|
130
|
+
w.postMessage({ url, id })
|
|
106
131
|
})
|
|
107
132
|
}
|
|
108
133
|
|
|
@@ -155,6 +180,7 @@ export default class ImageLoader {
|
|
|
155
180
|
}
|
|
156
181
|
|
|
157
182
|
destroy() {
|
|
183
|
+
this._terminateWorker()
|
|
158
184
|
this._objectURLs.forEach(u => URL.revokeObjectURL(u))
|
|
159
185
|
this._objectURLs.length = 0
|
|
160
186
|
this.images = []
|
package/core/PageEngine.js
CHANGED
|
@@ -123,6 +123,8 @@ export default class PageEngine {
|
|
|
123
123
|
this.smooth = smooth
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
this.trackImages()
|
|
127
|
+
|
|
126
128
|
this.manager = new Manager()
|
|
127
129
|
|
|
128
130
|
if (this.manager && this.components.length) {
|
|
@@ -132,12 +134,27 @@ export default class PageEngine {
|
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
this.manager.initialize()
|
|
137
|
+
this.resize()
|
|
135
138
|
|
|
136
139
|
this.on()
|
|
137
|
-
|
|
138
|
-
this.resize()
|
|
140
|
+
}
|
|
139
141
|
|
|
140
|
-
|
|
142
|
+
/**
|
|
143
|
+
* Trigger entry animations on all components.
|
|
144
|
+
* Call this from the page/renderer at the appropriate moment
|
|
145
|
+
* (e.g. after loader completes or onEnterCompleted).
|
|
146
|
+
*/
|
|
147
|
+
animateIn() {
|
|
148
|
+
this.manager?.animateIn?.()
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Trigger exit animations on all components.
|
|
153
|
+
* Call this from the page/renderer before leaving
|
|
154
|
+
* (e.g. during onLeave or transition out).
|
|
155
|
+
*/
|
|
156
|
+
animateOut() {
|
|
157
|
+
this.manager?.animateOut?.()
|
|
141
158
|
}
|
|
142
159
|
|
|
143
160
|
/**
|
|
@@ -167,7 +184,7 @@ export default class PageEngine {
|
|
|
167
184
|
|
|
168
185
|
// Setup ScrollTrigger scroller proxy
|
|
169
186
|
ScrollTrigger.scrollerProxy(wrapper, {
|
|
170
|
-
scrollTop:
|
|
187
|
+
scrollTop: value => {
|
|
171
188
|
if (value !== undefined) {
|
|
172
189
|
this.lenis.scrollTo(value, { immediate: true })
|
|
173
190
|
}
|
|
@@ -286,7 +303,6 @@ export default class PageEngine {
|
|
|
286
303
|
*/
|
|
287
304
|
off() {
|
|
288
305
|
this.listeners("off")
|
|
289
|
-
this.destroy()
|
|
290
306
|
}
|
|
291
307
|
|
|
292
308
|
/**
|
|
@@ -309,10 +325,12 @@ export default class PageEngine {
|
|
|
309
325
|
}
|
|
310
326
|
|
|
311
327
|
/**
|
|
312
|
-
* Cleanup Smooth + Manager.
|
|
328
|
+
* Cleanup listeners, Smooth + Manager.
|
|
313
329
|
* Called by Page.onLeaveCompleted().
|
|
314
330
|
*/
|
|
315
331
|
destroy() {
|
|
332
|
+
this.off()
|
|
333
|
+
|
|
316
334
|
this.manager?.destroy?.()
|
|
317
335
|
this.manager = null
|
|
318
336
|
|
package/events/Emitter.js
CHANGED
|
@@ -33,7 +33,7 @@ class Emitter {
|
|
|
33
33
|
}
|
|
34
34
|
this.on(event, onceCallback, priority)
|
|
35
35
|
return () => {
|
|
36
|
-
this.off(event,
|
|
36
|
+
this.off(event, onceCallback)
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -53,6 +53,9 @@ const EVENTS = {
|
|
|
53
53
|
APP_MOUSEMOVE: "mousemove",
|
|
54
54
|
APP_MOUSEDOWN: "mousedown",
|
|
55
55
|
APP_MOUSEUP: "mouseup",
|
|
56
|
+
APP_ROUTE_IN: "route:in",
|
|
57
|
+
APP_ROUTE_OUT: "route:out",
|
|
58
|
+
APP_ROUTE_END: "route:end",
|
|
56
59
|
APP_SPLITTEXT_READY: "splittext:ready",
|
|
57
60
|
APP_IMAGES_LOADED: "images:loaded",
|
|
58
61
|
APP_IMAGES_PROGRESS: "images:progress",
|
package/events/Mouse.js
CHANGED
|
@@ -15,8 +15,6 @@ export default class Mouse {
|
|
|
15
15
|
down: sniffer.isDevice ? "touchstart" : "mousedown",
|
|
16
16
|
up: sniffer.isDevice ? "touchend" : "mouseup",
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
this.on()
|
|
20
18
|
}
|
|
21
19
|
|
|
22
20
|
on() {
|
|
@@ -54,7 +52,7 @@ export default class Mouse {
|
|
|
54
52
|
onUp = e => {
|
|
55
53
|
const { x, target } = this.getPos(e)
|
|
56
54
|
this.state.off = x
|
|
57
|
-
const isClick = Math.abs(this.state.on - this.state.off)
|
|
55
|
+
const isClick = Math.abs(this.state.on - this.state.off) <= 10
|
|
58
56
|
emitter.emit(EVENTS.APP_MOUSEUP, { x, target, isClick })
|
|
59
57
|
}
|
|
60
58
|
}
|
package/events/Raf.js
CHANGED
|
@@ -313,12 +313,18 @@ export default class Raf {
|
|
|
313
313
|
})
|
|
314
314
|
|
|
315
315
|
ScrollTrigger.scrollerProxy(scroller, {
|
|
316
|
-
scrollTop:
|
|
316
|
+
scrollTop: value => {
|
|
317
|
+
if (value !== undefined) {
|
|
318
|
+
this.scroll.target = value
|
|
319
|
+
this.scroll.current = value
|
|
320
|
+
this.scroll.rounded = value
|
|
321
|
+
}
|
|
317
322
|
return this.getScroll()
|
|
318
323
|
},
|
|
319
324
|
getBoundingClientRect() {
|
|
320
325
|
return { top: 0, left: 0, width: window.innerWidth, height: window.innerHeight }
|
|
321
326
|
},
|
|
327
|
+
pinType: "transform",
|
|
322
328
|
})
|
|
323
329
|
}
|
|
324
330
|
|
package/events/VirtualScroll.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// VirtualScroll.js
|
|
2
2
|
import { kitStore } from "../kitStore"
|
|
3
3
|
import emitter from "./Emitter"
|
|
4
|
-
import {
|
|
4
|
+
import { sniffer } from "../utils"
|
|
5
5
|
import Lethargy from "lethargy"
|
|
6
6
|
|
|
7
7
|
const EVT_ID = "virtualscroll"
|
|
@@ -25,7 +25,6 @@ export default class VirtualScroll {
|
|
|
25
25
|
this.event = { x: 0, y: 0, deltaX: 0, deltaY: 0 }
|
|
26
26
|
this.touchStartX = null
|
|
27
27
|
this.touchStartY = null
|
|
28
|
-
this.bodyTouchAction = null
|
|
29
28
|
this.focusingInput = false
|
|
30
29
|
|
|
31
30
|
if (this.options.limitInertia) this.lethargy = new Lethargy()
|
|
@@ -34,8 +33,11 @@ export default class VirtualScroll {
|
|
|
34
33
|
this.listenerOptions = { passive: this.options.passive }
|
|
35
34
|
}
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
this._onFocusIn = () => (this.focusingInput = true)
|
|
37
|
+
this._onFocusOut = () => (this.focusingInput = false)
|
|
38
|
+
|
|
39
|
+
document.addEventListener("focusin", this._onFocusIn)
|
|
40
|
+
document.addEventListener("focusout", this._onFocusOut)
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
notify(e) {
|
|
@@ -56,10 +58,10 @@ export default class VirtualScroll {
|
|
|
56
58
|
if (this.lethargy && !this.lethargy.check(e)) return
|
|
57
59
|
|
|
58
60
|
const evt = this.event
|
|
59
|
-
evt.deltaX = e.
|
|
60
|
-
evt.deltaY = e.
|
|
61
|
+
evt.deltaX = e.deltaX * -1
|
|
62
|
+
evt.deltaY = e.deltaY * -1
|
|
61
63
|
|
|
62
|
-
if (
|
|
64
|
+
if (sniffer.isFirefox && e.deltaMode === 1) {
|
|
63
65
|
evt.deltaX *= this.options.firefoxMultiplier
|
|
64
66
|
evt.deltaY *= this.options.firefoxMultiplier
|
|
65
67
|
}
|
|
@@ -70,16 +72,6 @@ export default class VirtualScroll {
|
|
|
70
72
|
this.notify(e)
|
|
71
73
|
}
|
|
72
74
|
|
|
73
|
-
onMouseWheel = e => {
|
|
74
|
-
if (this.options.limitInertia && !this.lethargy.check(e)) return
|
|
75
|
-
|
|
76
|
-
const evt = this.event
|
|
77
|
-
evt.deltaX = e.wheelDeltaX || 0
|
|
78
|
-
evt.deltaY = e.wheelDeltaY || e.wheelDelta
|
|
79
|
-
|
|
80
|
-
this.notify(e)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
75
|
onTouchStart = e => {
|
|
84
76
|
const t = e.targetTouches ? e.targetTouches[0] : e
|
|
85
77
|
this.touchStartX = t.pageX
|
|
@@ -132,44 +124,23 @@ export default class VirtualScroll {
|
|
|
132
124
|
}
|
|
133
125
|
|
|
134
126
|
bind = () => {
|
|
135
|
-
|
|
127
|
+
this.el.addEventListener("wheel", this.onWheel, this.listenerOptions)
|
|
136
128
|
|
|
137
|
-
if (
|
|
138
|
-
|
|
139
|
-
if (support.hasMouseWheelEvent)
|
|
140
|
-
this.el.addEventListener("mousewheel", this.onMouseWheel, this.listenerOptions)
|
|
141
|
-
|
|
142
|
-
if (support.hasTouch && this.options.useTouch) {
|
|
129
|
+
if (sniffer.isTouch && this.options.useTouch) {
|
|
143
130
|
this.el.addEventListener("touchstart", this.onTouchStart, this.listenerOptions)
|
|
144
131
|
this.el.addEventListener("touchmove", this.onTouchMove, this.listenerOptions)
|
|
145
132
|
}
|
|
146
133
|
|
|
147
|
-
if (
|
|
148
|
-
this.bodyTouchAction = document.body.style.msTouchAction
|
|
149
|
-
document.body.style.msTouchAction = "none"
|
|
150
|
-
this.el.addEventListener("MSPointerDown", this.onTouchStart, true)
|
|
151
|
-
this.el.addEventListener("MSPointerMove", this.onTouchMove, true)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (support.hasKeyDown && this.options.useKeyboard) document.addEventListener("keydown", this.onKeyDown)
|
|
134
|
+
if (this.options.useKeyboard) document.addEventListener("keydown", this.onKeyDown)
|
|
155
135
|
}
|
|
156
136
|
|
|
157
137
|
unbind = () => {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (support.hasWheelEvent) this.el.removeEventListener("wheel", this.onWheel)
|
|
161
|
-
if (support.hasMouseWheelEvent) this.el.removeEventListener("mousewheel", this.onMouseWheel)
|
|
162
|
-
if (support.hasTouch) {
|
|
138
|
+
this.el.removeEventListener("wheel", this.onWheel)
|
|
139
|
+
if (sniffer.isTouch) {
|
|
163
140
|
this.el.removeEventListener("touchstart", this.onTouchStart)
|
|
164
141
|
this.el.removeEventListener("touchmove", this.onTouchMove)
|
|
165
142
|
}
|
|
166
|
-
if (
|
|
167
|
-
document.body.style.msTouchAction = this.bodyTouchAction
|
|
168
|
-
this.el.removeEventListener("MSPointerDown", this.onTouchStart, true)
|
|
169
|
-
this.el.removeEventListener("MSPointerMove", this.onTouchMove, true)
|
|
170
|
-
}
|
|
171
|
-
if (support.hasKeyDown && this.options.useKeyboard)
|
|
172
|
-
document.removeEventListener("keydown", this.onKeyDown)
|
|
143
|
+
if (this.options.useKeyboard) document.removeEventListener("keydown", this.onKeyDown)
|
|
173
144
|
}
|
|
174
145
|
|
|
175
146
|
on = (cb, priority = 0) => {
|
|
@@ -191,6 +162,9 @@ export default class VirtualScroll {
|
|
|
191
162
|
|
|
192
163
|
destroy = () => {
|
|
193
164
|
this.unbind()
|
|
194
|
-
emitter.
|
|
165
|
+
emitter.events[EVT_ID] = []
|
|
166
|
+
|
|
167
|
+
document.removeEventListener("focusin", this._onFocusIn)
|
|
168
|
+
document.removeEventListener("focusout", this._onFocusOut)
|
|
195
169
|
}
|
|
196
170
|
}
|
package/kitStore.js
CHANGED
|
@@ -40,12 +40,36 @@ export const kitStore = {
|
|
|
40
40
|
breakpoints,
|
|
41
41
|
mouse,
|
|
42
42
|
flags,
|
|
43
|
-
pageContent: null,
|
|
44
43
|
assets,
|
|
44
|
+
|
|
45
|
+
/** @type {HTMLElement | null} — main content container (#app) */
|
|
46
|
+
pageContent: null,
|
|
47
|
+
|
|
48
|
+
/** @type {HTMLElement | null} — current page/view element ([data-taxi-view]) */
|
|
49
|
+
currentPage: null,
|
|
50
|
+
|
|
51
|
+
/** @type {URL | string | null} — current URL (set by Application) */
|
|
52
|
+
currentURL: null,
|
|
53
|
+
|
|
54
|
+
/** @type {HTMLElement | null} — loader element (set by Application) */
|
|
55
|
+
load: null,
|
|
56
|
+
|
|
45
57
|
/**
|
|
46
58
|
* Scroll scroller element (wrapper for Lenis, pageContent for internal scroll).
|
|
47
59
|
* Used by ScrollTrigger components to get the correct scroller.
|
|
48
60
|
* @type {HTMLElement | null}
|
|
49
61
|
*/
|
|
50
62
|
scroller: null,
|
|
63
|
+
|
|
64
|
+
/** @type {import("./events/Raf").default | null} */
|
|
65
|
+
raf: null,
|
|
66
|
+
|
|
67
|
+
/** @type {import("./events/Scroll").default | null} */
|
|
68
|
+
scroll: null,
|
|
69
|
+
|
|
70
|
+
/** @type {import("./events/Resize").default | null} */
|
|
71
|
+
resize: null,
|
|
72
|
+
|
|
73
|
+
/** @type {any | null} — Taxi router instance (if attached via Application.attachTaxi()) */
|
|
74
|
+
taxi: null,
|
|
51
75
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linear_non/stellar-kit",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.11",
|
|
4
4
|
"description": "Stellar frontend core for Non-Linear Studio projects.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "
|
|
6
|
+
"main": "./core/index.js",
|
|
7
7
|
"sass": "./styles/index.scss",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": "./kitStore.js",
|
package/utils/index.js
CHANGED
|
@@ -5,6 +5,6 @@ export { offset } from "./offset"
|
|
|
5
5
|
export { getViewport, getWindowSizes, setViewportHeight } from "./window"
|
|
6
6
|
export { sniffer } from "./sniffer"
|
|
7
7
|
export { lerp, clamp, norm, round } from "./math"
|
|
8
|
-
export { supportWebp
|
|
8
|
+
export { supportWebp } from "./support"
|
|
9
9
|
export { listener } from "./listener"
|
|
10
10
|
export { raf2 } from "./timing"
|
package/utils/math.js
CHANGED
|
@@ -31,7 +31,7 @@ export const clamp = (val, min, max) => Math.min(Math.max(val, min), max)
|
|
|
31
31
|
* @param {number} [p=3] - Decimal precision
|
|
32
32
|
* @returns {number}
|
|
33
33
|
*/
|
|
34
|
-
export const round = (n, p) => {
|
|
35
|
-
const precision =
|
|
34
|
+
export const round = (n, p = 3) => {
|
|
35
|
+
const precision = Math.pow(10, p)
|
|
36
36
|
return Math.round(n * precision) / precision
|
|
37
37
|
}
|
package/utils/sniffer.js
CHANGED
|
@@ -2,20 +2,12 @@
|
|
|
2
2
|
export const sniffer = {
|
|
3
3
|
uA: navigator.userAgent.toLowerCase(),
|
|
4
4
|
|
|
5
|
-
get isWindowsMobile() {
|
|
6
|
-
return /windows phone|iemobile|wpdesktop/.test(this.uA)
|
|
7
|
-
},
|
|
8
|
-
|
|
9
|
-
get isMobileOpera() {
|
|
10
|
-
return /opera mini/i.test(this.uA)
|
|
11
|
-
},
|
|
12
|
-
|
|
13
5
|
get isIOS() {
|
|
14
6
|
return /iphone|ipad|ipod/i.test(this.uA)
|
|
15
7
|
},
|
|
16
8
|
|
|
17
9
|
get isIpad() {
|
|
18
|
-
return
|
|
10
|
+
return /ipad/i.test(this.uA) && this.isIOS
|
|
19
11
|
},
|
|
20
12
|
|
|
21
13
|
get isLatestIpad() {
|
|
@@ -23,15 +15,15 @@ export const sniffer = {
|
|
|
23
15
|
},
|
|
24
16
|
|
|
25
17
|
get isIphone() {
|
|
26
|
-
return
|
|
18
|
+
return /iphone/i.test(this.uA) && this.isIOS
|
|
27
19
|
},
|
|
28
20
|
|
|
29
21
|
get isMobileAndroid() {
|
|
30
|
-
return
|
|
22
|
+
return /android.*mobile/.test(this.uA)
|
|
31
23
|
},
|
|
32
24
|
|
|
33
25
|
get isTabletAndroid() {
|
|
34
|
-
return !this.
|
|
26
|
+
return !this.isMobileAndroid && /android/i.test(this.uA)
|
|
35
27
|
},
|
|
36
28
|
|
|
37
29
|
get isAndroid() {
|
|
@@ -39,7 +31,7 @@ export const sniffer = {
|
|
|
39
31
|
},
|
|
40
32
|
|
|
41
33
|
get isPhone() {
|
|
42
|
-
return this.isMobileAndroid || (this.isIOS && !this.isIpad)
|
|
34
|
+
return this.isMobileAndroid || (this.isIOS && !this.isIpad)
|
|
43
35
|
},
|
|
44
36
|
|
|
45
37
|
get isTablet() {
|
|
@@ -62,20 +54,8 @@ export const sniffer = {
|
|
|
62
54
|
return this.uA.includes("opr")
|
|
63
55
|
},
|
|
64
56
|
|
|
65
|
-
get isIE11() {
|
|
66
|
-
return !window.ActiveXObject && "ActiveXObject" in window
|
|
67
|
-
},
|
|
68
|
-
|
|
69
|
-
get isIE() {
|
|
70
|
-
return this.uA.includes("msie") || this.isIE11 || this.uA.includes("edge")
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
get isEdge() {
|
|
74
|
-
return this.uA.includes("edge")
|
|
75
|
-
},
|
|
76
|
-
|
|
77
57
|
get isWindows() {
|
|
78
|
-
return
|
|
58
|
+
return /windows/i.test(this.uA)
|
|
79
59
|
},
|
|
80
60
|
|
|
81
61
|
get isChrome() {
|
|
@@ -83,13 +63,12 @@ export const sniffer = {
|
|
|
83
63
|
window.chrome !== null &&
|
|
84
64
|
window.chrome !== undefined &&
|
|
85
65
|
navigator.vendor.toLowerCase() === "google inc." &&
|
|
86
|
-
!this.isOpera
|
|
87
|
-
!this.isEdge
|
|
66
|
+
!this.isOpera
|
|
88
67
|
)
|
|
89
68
|
},
|
|
90
69
|
|
|
91
70
|
get isMac() {
|
|
92
|
-
return
|
|
71
|
+
return /macintosh|mac os x/i.test(this.uA)
|
|
93
72
|
},
|
|
94
73
|
|
|
95
74
|
get isDesktop() {
|
|
@@ -97,13 +76,15 @@ export const sniffer = {
|
|
|
97
76
|
},
|
|
98
77
|
|
|
99
78
|
get isTouch() {
|
|
100
|
-
return
|
|
79
|
+
return (
|
|
80
|
+
"ontouchstart" in window ||
|
|
81
|
+
!!window.TouchEvent ||
|
|
82
|
+
(navigator.maxTouchPoints && navigator.maxTouchPoints > 0)
|
|
83
|
+
)
|
|
101
84
|
},
|
|
102
85
|
|
|
103
86
|
get sniff() {
|
|
104
87
|
return {
|
|
105
|
-
isWindowsMobile: this.isWindowsMobile,
|
|
106
|
-
isMobileOpera: this.isMobileOpera,
|
|
107
88
|
isIOS: this.isIOS,
|
|
108
89
|
isIpad: this.isIpad,
|
|
109
90
|
isIphone: this.isIphone,
|
|
@@ -113,9 +94,6 @@ export const sniffer = {
|
|
|
113
94
|
isFirefox: this.isFirefox,
|
|
114
95
|
isSafari: this.isSafari,
|
|
115
96
|
isOpera: this.isOpera,
|
|
116
|
-
isIE11: this.isIE11,
|
|
117
|
-
isIE: this.isIE,
|
|
118
|
-
isEdge: this.isEdge,
|
|
119
97
|
isChrome: this.isChrome,
|
|
120
98
|
isMac: this.isMac,
|
|
121
99
|
isPhone: this.isPhone,
|
package/utils/support.js
CHANGED
|
@@ -6,18 +6,3 @@ export const supportWebp = () => {
|
|
|
6
6
|
}
|
|
7
7
|
return false
|
|
8
8
|
}
|
|
9
|
-
|
|
10
|
-
export const supportMouseTouch = () => {
|
|
11
|
-
return {
|
|
12
|
-
hasWheelEvent: "onwheel" in document,
|
|
13
|
-
hasMouseWheelEvent: "onmousewheel" in document,
|
|
14
|
-
hasTouch:
|
|
15
|
-
"ontouchstart" in window ||
|
|
16
|
-
window.TouchEvent ||
|
|
17
|
-
(window.DocumentTouch && document instanceof DocumentTouch),
|
|
18
|
-
hasTouchWin: navigator.msMaxTouchPoints && navigator.msMaxTouchPoints > 1,
|
|
19
|
-
hasPointer: !!window.navigator.msPointerEnabled,
|
|
20
|
-
hasKeyDown: "onkeydown" in document,
|
|
21
|
-
isFirefox: navigator.userAgent.indexOf("Firefox") > -1,
|
|
22
|
-
}
|
|
23
|
-
}
|