coonlink-luxy 26.1.1 → 26.1.3
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/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +132 -40
- package/package.json +1 -1
- package/README.md +0 -36
package/dist/index.d.ts
CHANGED
|
@@ -5,13 +5,12 @@ export type CoonlinkLuxyOptions = {
|
|
|
5
5
|
targetSpeed?: number;
|
|
6
6
|
targetPercentage?: number;
|
|
7
7
|
respectReducedMotion?: boolean;
|
|
8
|
+
respectOpenModalOverlay?: boolean;
|
|
8
9
|
};
|
|
9
10
|
export interface CoonlinkLuxyInstance {
|
|
10
11
|
init(options?: CoonlinkLuxyOptions): boolean;
|
|
11
12
|
destroy(): void;
|
|
12
13
|
}
|
|
13
|
-
declare const defaults: Required<CoonlinkLuxyOptions>;
|
|
14
14
|
export declare function createCoonlinkLuxy(): CoonlinkLuxyInstance;
|
|
15
|
-
export declare function getCoonlinkLuxyDefaults(): Readonly<
|
|
16
|
-
export {};
|
|
15
|
+
export declare function getCoonlinkLuxyDefaults(): Readonly<Required<CoonlinkLuxyOptions>>;
|
|
17
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC;IAC7C,OAAO,IAAI,IAAI,CAAC;CACjB;AA4ND,wBAAgB,kBAAkB,IAAI,oBAAoB,CAEzD;AAED,wBAAgB,uBAAuB,IAAI,QAAQ,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAEjF"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
✨ CoonDev • https://dev.coonlink.com/
|
|
3
|
+
|
|
4
|
+
▄█▄ ████▄ ████▄ ▄ ██▄ ▄███▄ ▄
|
|
5
|
+
█▀ ▀▄ █ █ █ █ █ █ █ █▀ ▀ █
|
|
6
|
+
█ ▀ █ █ █ █ ██ █ █ █ ██▄▄ █ █
|
|
7
|
+
█▄ ▄▀ ▀████ ▀████ █ █ █ █ █ █▄ ▄▀ █ █
|
|
8
|
+
▀███▀ █ █ █ ███▀ ▀███▀ █ █
|
|
9
|
+
█ ██ █▐
|
|
10
|
+
▐
|
|
11
|
+
*/
|
|
1
12
|
const defaults = {
|
|
2
13
|
wrapper: '#luxy',
|
|
3
14
|
targets: '.luxy-el',
|
|
@@ -5,18 +16,24 @@ const defaults = {
|
|
|
5
16
|
targetSpeed: 0.02,
|
|
6
17
|
targetPercentage: 0.1,
|
|
7
18
|
respectReducedMotion: true,
|
|
19
|
+
respectOpenModalOverlay: true,
|
|
8
20
|
};
|
|
21
|
+
const SETTLE_EPS = 0.12;
|
|
22
|
+
function hasOpenModalOverlay() {
|
|
23
|
+
return !!document.querySelector('[data-slot="dialog-overlay"][data-state="open"],' +
|
|
24
|
+
'[data-slot="alert-dialog-overlay"][data-state="open"],' +
|
|
25
|
+
'[data-slot="sheet-overlay"][data-state="open"]');
|
|
26
|
+
}
|
|
9
27
|
function extend(base, over) {
|
|
10
|
-
return { ...base, ...(over
|
|
28
|
+
return { ...base, ...(over !== null && over !== void 0 ? over : {}) };
|
|
11
29
|
}
|
|
12
30
|
function getScrollTop() {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
document.body.scrollTop ??
|
|
16
|
-
0);
|
|
31
|
+
var _a, _b, _c;
|
|
32
|
+
return ((_c = (_b = (_a = window.scrollY) !== null && _a !== void 0 ? _a : document.documentElement.scrollTop) !== null && _b !== void 0 ? _b : document.body.scrollTop) !== null && _c !== void 0 ? _c : 0);
|
|
17
33
|
}
|
|
18
34
|
function readSpeedY(el) {
|
|
19
|
-
|
|
35
|
+
var _a;
|
|
36
|
+
return (_a = el.getAttribute('data-speed-y')) !== null && _a !== void 0 ? _a : el.getAttribute('data-speed-Y');
|
|
20
37
|
}
|
|
21
38
|
class Engine {
|
|
22
39
|
constructor() {
|
|
@@ -27,25 +44,114 @@ class Engine {
|
|
|
27
44
|
this.scrollTop = 0;
|
|
28
45
|
this.scrollRaf = 0;
|
|
29
46
|
this.resizeObserver = null;
|
|
47
|
+
this.pauseForOverlay = false;
|
|
48
|
+
this.overlayObserver = null;
|
|
49
|
+
this.onScrollResume = () => { this.ensureTicking(); };
|
|
30
50
|
this.onResize = () => {
|
|
31
51
|
if (!this.wrapper)
|
|
32
52
|
return;
|
|
33
53
|
const h = Math.max(this.wrapper.scrollHeight, this.wrapper.clientHeight);
|
|
34
54
|
document.body.style.height = `${h}px`;
|
|
55
|
+
this.ensureTicking();
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
isSettled() {
|
|
59
|
+
if (Math.abs(this.scrollTop - this.wrapperOffset) > SETTLE_EPS)
|
|
60
|
+
return false;
|
|
61
|
+
const ts = this.settings.targetSpeed;
|
|
62
|
+
const st = this.scrollTop;
|
|
63
|
+
for (let i = 0; i < this.targets.length; i++) {
|
|
64
|
+
const t = this.targets[i];
|
|
65
|
+
const idealY = st * Number(ts) * Number(t.speedY);
|
|
66
|
+
if (Math.abs(idealY - t.top) > SETTLE_EPS)
|
|
67
|
+
return false;
|
|
68
|
+
if (t.horizontal) {
|
|
69
|
+
const idealX = st * Number(ts) * Number(t.speedX);
|
|
70
|
+
if (Math.abs(idealX - t.left) > SETTLE_EPS)
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
stopScrollLoop() {
|
|
77
|
+
window.removeEventListener('scroll', this.onScrollResume);
|
|
78
|
+
if (this.scrollRaf) {
|
|
79
|
+
window.cancelAnimationFrame(this.scrollRaf);
|
|
80
|
+
this.scrollRaf = 0;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
ensureTicking() {
|
|
84
|
+
if (this.pauseForOverlay || !this.wrapper)
|
|
85
|
+
return;
|
|
86
|
+
window.removeEventListener('scroll', this.onScrollResume);
|
|
87
|
+
if (this.scrollRaf !== 0)
|
|
88
|
+
return;
|
|
89
|
+
const tick = () => {
|
|
90
|
+
if (this.pauseForOverlay || !this.wrapper) {
|
|
91
|
+
this.scrollRaf = 0;
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
this.scrollTop = getScrollTop();
|
|
95
|
+
this.wrapperUpdate();
|
|
96
|
+
for (let i = 0; i < this.targets.length; i++)
|
|
97
|
+
this.targetsUpdate(this.targets[i]);
|
|
98
|
+
if (this.isSettled()) {
|
|
99
|
+
this.scrollRaf = 0;
|
|
100
|
+
window.addEventListener('scroll', this.onScrollResume, { passive: true });
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
this.scrollRaf = window.requestAnimationFrame(tick);
|
|
35
104
|
};
|
|
105
|
+
this.scrollRaf = window.requestAnimationFrame(tick);
|
|
106
|
+
}
|
|
107
|
+
syncOverlayPause() {
|
|
108
|
+
if (!this.settings.respectOpenModalOverlay) {
|
|
109
|
+
this.pauseForOverlay = false;
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const blocked = hasOpenModalOverlay();
|
|
113
|
+
if (blocked === this.pauseForOverlay)
|
|
114
|
+
return;
|
|
115
|
+
this.pauseForOverlay = blocked;
|
|
116
|
+
if (blocked) {
|
|
117
|
+
this.stopScrollLoop();
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
this.onResize();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
attachOverlayWatcher() {
|
|
124
|
+
this.detachOverlayWatcher();
|
|
125
|
+
if (!this.settings.respectOpenModalOverlay)
|
|
126
|
+
return;
|
|
127
|
+
this.pauseForOverlay = hasOpenModalOverlay();
|
|
128
|
+
this.overlayObserver = new MutationObserver(() => {
|
|
129
|
+
this.syncOverlayPause();
|
|
130
|
+
if (!this.pauseForOverlay)
|
|
131
|
+
this.ensureTicking();
|
|
132
|
+
});
|
|
133
|
+
this.overlayObserver.observe(document.body, {
|
|
134
|
+
childList: true, subtree: true, attributes: true, attributeFilter: ['data-state'],
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
detachOverlayWatcher() {
|
|
138
|
+
var _a;
|
|
139
|
+
(_a = this.overlayObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
140
|
+
this.overlayObserver = null;
|
|
141
|
+
this.pauseForOverlay = false;
|
|
36
142
|
}
|
|
37
143
|
init(options) {
|
|
144
|
+
var _a;
|
|
38
145
|
this.destroy();
|
|
39
146
|
this.settings = extend(defaults, options);
|
|
40
147
|
if (this.settings.respectReducedMotion) {
|
|
41
|
-
const mq = window.matchMedia
|
|
42
|
-
if (mq
|
|
148
|
+
const mq = (_a = window.matchMedia) === null || _a === void 0 ? void 0 : _a.call(window, '(prefers-reduced-motion: reduce)');
|
|
149
|
+
if (mq === null || mq === void 0 ? void 0 : mq.matches)
|
|
43
150
|
return false;
|
|
44
151
|
}
|
|
45
152
|
const el = document.querySelector(this.settings.wrapper);
|
|
46
|
-
if (!el || !(el instanceof HTMLElement))
|
|
153
|
+
if (!el || !(el instanceof HTMLElement))
|
|
47
154
|
return false;
|
|
48
|
-
}
|
|
49
155
|
this.wrapper = el;
|
|
50
156
|
const nodeList = document.querySelectorAll(this.settings.targets);
|
|
51
157
|
const scrollHeight = Math.max(this.wrapper.scrollHeight, this.wrapper.clientHeight);
|
|
@@ -66,8 +172,7 @@ class Engine {
|
|
|
66
172
|
elm: node,
|
|
67
173
|
offset: offset ? parseInt(offset, 10) || 0 : 0,
|
|
68
174
|
horizontal: horizontal ? 1 : 0,
|
|
69
|
-
top: 0,
|
|
70
|
-
left: 0,
|
|
175
|
+
top: 0, left: 0,
|
|
71
176
|
speedX: speedX ? Number(speedX) || 1 : 1,
|
|
72
177
|
speedY: speedY ? Number(speedY) || 1 : 1,
|
|
73
178
|
percentage: percentage ? parseInt(percentage, 10) || 0 : 0,
|
|
@@ -76,61 +181,48 @@ class Engine {
|
|
|
76
181
|
this.resizeObserver = new ResizeObserver(this.onResize);
|
|
77
182
|
this.resizeObserver.observe(this.wrapper);
|
|
78
183
|
window.addEventListener('resize', this.onResize);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
this.
|
|
82
|
-
for (let i = 0; i < this.targets.length; i++) {
|
|
83
|
-
this.targetsUpdate(this.targets[i]);
|
|
84
|
-
}
|
|
85
|
-
this.scrollRaf = window.requestAnimationFrame(tickScroll);
|
|
86
|
-
};
|
|
87
|
-
this.scrollRaf = window.requestAnimationFrame(tickScroll);
|
|
184
|
+
this.attachOverlayWatcher();
|
|
185
|
+
if (!this.pauseForOverlay)
|
|
186
|
+
this.ensureTicking();
|
|
88
187
|
return true;
|
|
89
188
|
}
|
|
90
189
|
wrapperUpdate() {
|
|
91
190
|
if (!this.wrapper)
|
|
92
191
|
return;
|
|
93
|
-
this.wrapperOffset +=
|
|
94
|
-
|
|
192
|
+
this.wrapperOffset += (this.scrollTop - this.wrapperOffset) * this.settings.wrapperSpeed;
|
|
193
|
+
const maxOffset = Math.max(0, document.body.scrollHeight - window.innerHeight);
|
|
194
|
+
this.wrapperOffset = Math.max(0, Math.min(this.wrapperOffset, maxOffset));
|
|
95
195
|
const y = Math.round(-this.wrapperOffset * 100) / 100;
|
|
96
196
|
this.wrapper.style.transform = `translate3d(0, ${y}px, 0)`;
|
|
97
197
|
}
|
|
98
198
|
targetsUpdate(target) {
|
|
99
199
|
const ts = this.settings.targetSpeed;
|
|
100
200
|
const tp = this.settings.targetPercentage;
|
|
101
|
-
target.top +=
|
|
102
|
-
|
|
103
|
-
target.
|
|
104
|
-
(this.scrollTop * Number(ts) * Number(target.speedX) - target.left) * tp;
|
|
105
|
-
const targetOffsetTop = parseInt(String(target.percentage), 10) -
|
|
106
|
-
target.top -
|
|
107
|
-
parseInt(String(target.offset), 10);
|
|
201
|
+
target.top += (this.scrollTop * Number(ts) * Number(target.speedY) - target.top) * tp;
|
|
202
|
+
target.left += (this.scrollTop * Number(ts) * Number(target.speedX) - target.left) * tp;
|
|
203
|
+
const targetOffsetTop = parseInt(String(target.percentage), 10) - target.top - parseInt(String(target.offset), 10);
|
|
108
204
|
let offsetY = Math.round(targetOffsetTop * -100) / 100;
|
|
109
205
|
let offsetX = 0;
|
|
110
206
|
if (target.horizontal) {
|
|
111
|
-
const targetOffsetLeft = parseInt(String(target.percentage), 10) -
|
|
112
|
-
target.left -
|
|
113
|
-
parseInt(String(target.offset), 10);
|
|
207
|
+
const targetOffsetLeft = parseInt(String(target.percentage), 10) - target.left - parseInt(String(target.offset), 10);
|
|
114
208
|
offsetX = Math.round(targetOffsetLeft * -100) / 100;
|
|
115
209
|
}
|
|
116
210
|
target.elm.style.transform = `translate3d(${offsetX}px, ${offsetY}px, 0)`;
|
|
117
211
|
}
|
|
118
212
|
destroy() {
|
|
213
|
+
var _a;
|
|
214
|
+
this.detachOverlayWatcher();
|
|
215
|
+
this.stopScrollLoop();
|
|
119
216
|
window.removeEventListener('resize', this.onResize);
|
|
120
|
-
this.resizeObserver
|
|
217
|
+
(_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
121
218
|
this.resizeObserver = null;
|
|
122
|
-
if (this.scrollRaf) {
|
|
123
|
-
window.cancelAnimationFrame(this.scrollRaf);
|
|
124
|
-
this.scrollRaf = 0;
|
|
125
|
-
}
|
|
126
219
|
document.body.style.height = '';
|
|
127
220
|
if (this.wrapper) {
|
|
128
221
|
this.wrapper.removeAttribute('style');
|
|
129
222
|
this.wrapper = null;
|
|
130
223
|
}
|
|
131
|
-
for (let i = 0; i < this.targets.length; i++)
|
|
224
|
+
for (let i = 0; i < this.targets.length; i++)
|
|
132
225
|
this.targets[i].elm.removeAttribute('style');
|
|
133
|
-
}
|
|
134
226
|
this.targets = [];
|
|
135
227
|
this.wrapperOffset = 0;
|
|
136
228
|
}
|
package/package.json
CHANGED
package/README.md
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# coonlink-luxy
|
|
2
|
-
|
|
3
|
-
Inertia scroll and parallax (same idea as [luxy.js](https://github.com/min30327/luxy.js)), with fixes for modern browsers, `data-speed-y`, and clean `destroy()` for React/Next.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm i coonlink-luxy
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Markup
|
|
12
|
-
|
|
13
|
-
```html
|
|
14
|
-
<div id="luxy">
|
|
15
|
-
<div class="luxy-el" data-speed-y="5" data-offset="-50">…</div>
|
|
16
|
-
</div>
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Usage
|
|
20
|
-
|
|
21
|
-
```ts
|
|
22
|
-
import { createCoonlinkLuxy } from 'coonlink-luxy'
|
|
23
|
-
|
|
24
|
-
const luxy = createCoonlinkLuxy()
|
|
25
|
-
luxy.init({
|
|
26
|
-
wrapper: '#luxy',
|
|
27
|
-
targets: '.luxy-el',
|
|
28
|
-
wrapperSpeed: 0.08,
|
|
29
|
-
targetSpeed: 0.02,
|
|
30
|
-
targetPercentage: 0.1,
|
|
31
|
-
respectReducedMotion: true,
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
// SPA / React unmount:
|
|
35
|
-
luxy.destroy()
|
|
36
|
-
```
|