@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 CHANGED
@@ -1,67 +1,75 @@
1
1
  # stellar-kit
2
2
 
3
- A modular frontend utility kit for custom websites. Built for performance, extensibility, and clean developer ergonomics — with support for smooth scrolling, events, tick updates, mouse tracking, and layout helpers.
3
+ > `@linear_non/stellar-kit` Front-end core framework for Non-Linear Studio projects.
4
4
 
5
- ## Features
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
- - RAF-based update loop (`Raf`)
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
- ## 🧱 Folder Structure
13
+ ## Quick Start
23
14
 
24
- ```
25
- stellar-kit/
26
- ├── classes/ # Core logic: Manager, Component.
27
- ├── events/ # Emitter system: Raf, Resize, Scroll, Mouse, etc.
28
- ├── utils/ # Utilities: bounds, clamp, selectors, sniffer, etc.
29
- ├── plugins/ # Helpers Grid, Observer, SplitText, etc.
30
- ├── kitStore.js # Central store shared across all modules
31
- └── index.js # Entry point for setupKit and kitStore access
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
- ## 🧪 Local Development
27
+ ## Imports
35
28
 
36
- ```bash
37
- npm install
38
- npm run dev
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
- > The `dev/` folder provides a Vite playground to test modules like Smooth, Scrollbar, and events. You can import any part of the kit and prototype in isolation.
39
+ ## Architecture
42
40
 
43
- ## 🛠️ Usage Example
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
- ```js
46
- // main.js or index.js of your project
47
- import { kitStore, setupKit } from "stellar-kit"
50
+ ## Scroll Modes
48
51
 
49
- setupKit() // Initializes Resize, Raf, Scroll, Mouse, etc.
52
+ **Internal** VirtualScroll + lerp interpolation in Raf:
50
53
 
51
- // Access anywhere
52
- kitStore.scroll
53
- kitStore.raf
54
- kitStore.mouse
54
+ ```js
55
+ engine.setup({ components, smooth })
55
56
  ```
56
57
 
57
- You can also import from specific paths:
58
+ **External (Lenis)** Lenis manages scroll, PageEngine sets up ScrollTrigger proxy:
58
59
 
59
60
  ```js
60
- import { bounds, clamp, qs } from "stellar-kit/utils"
61
- import { Manager } from "stellar-kit/classes"
62
- import { Raf } from "stellar-kit/events"
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
- Made with ❤️ by [Non-Linear Studio](https://non-linear.studio)
75
+ MIT [Non-Linear Studio](https://non-linear.studio)
@@ -31,8 +31,6 @@ export default class Component {
31
31
  this.off()
32
32
  }
33
33
 
34
- setWebgl() {}
35
-
36
34
  render() {
37
35
  this.setup()
38
36
  this.on()
@@ -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
- return new Worker(URL.createObjectURL(blob))
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
- w.onmessage = async e => {
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
- w.postMessage({ url })
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 = []
@@ -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
- this.trackImages()
138
- this.resize()
140
+ }
139
141
 
140
- this.manager.animateIn?.()
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: (value) => {
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, cb)
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) > 10
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
 
@@ -1,7 +1,7 @@
1
1
  // VirtualScroll.js
2
2
  import { kitStore } from "../kitStore"
3
3
  import emitter from "./Emitter"
4
- import { supportMouseTouch } from "../utils"
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
- document.addEventListener("focusin", () => (this.focusingInput = true))
38
- document.addEventListener("focusout", () => (this.focusingInput = false))
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.wheelDeltaX || e.deltaX * -1
60
- evt.deltaY = e.wheelDeltaY || e.deltaY * -1
61
+ evt.deltaX = e.deltaX * -1
62
+ evt.deltaY = e.deltaY * -1
61
63
 
62
- if (supportMouseTouch().isFirefox && e.deltaMode === 1) {
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
- const support = supportMouseTouch()
127
+ this.el.addEventListener("wheel", this.onWheel, this.listenerOptions)
136
128
 
137
- if (support.hasWheelEvent) this.el.addEventListener("wheel", this.onWheel, this.listenerOptions)
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 (support.hasPointer && support.hasTouchWin) {
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
- const support = supportMouseTouch()
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 (support.hasPointer && support.hasTouchWin) {
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.off(EVT_ID, () => {}) // Clear all
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.8",
3
+ "version": "3.0.11",
4
4
  "description": "Stellar frontend core for Non-Linear Studio projects.",
5
5
  "type": "module",
6
- "main": "/core/index.js",
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, supportMouseTouch } from "./support"
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 = p !== undefined ? Math.pow(10, p) : 1000
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 !this.isWindowsMobile && /ipad/i.test(this.uA) && this.isIOS
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 !this.isWindowsMobile && /iphone/i.test(this.uA) && this.isIOS
18
+ return /iphone/i.test(this.uA) && this.isIOS
27
19
  },
28
20
 
29
21
  get isMobileAndroid() {
30
- return !this.isWindowsMobile && /android.*mobile/.test(this.uA)
22
+ return /android.*mobile/.test(this.uA)
31
23
  },
32
24
 
33
25
  get isTabletAndroid() {
34
- return !this.isWindowsMobile && !this.isMobileAndroid && /android/i.test(this.uA)
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) || this.isWindowsMobile
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 ["Win32", "Win64", "Windows", "WinCE"].includes(window.navigator.platform)
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 navigator.platform.toLowerCase().includes("mac")
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 "ontouchstart" in window
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
- }