@brandocms/jupiter 5.0.0-beta.11 → 5.0.0-beta.13
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 +7 -0
- package/package.json +1 -1
- package/src/modules/Application/index.js +52 -40
- package/src/modules/Dataloader/index.js +136 -59
- package/src/modules/FeatureTests/index.js +2 -1
- package/src/modules/Lazyload/index.js +115 -49
- package/src/modules/Looper/index.js +354 -179
- package/src/modules/Moonwalk/index.js +194 -164
- package/src/utils/rafCallback.js +4 -5
- package/types/modules/Application/index.d.ts +7 -8
- package/types/modules/Dataloader/index.d.ts +48 -2
- package/types/modules/FeatureTests/index.d.ts +1 -1
- package/types/modules/FixedHeader/index.d.ts +58 -0
- package/types/modules/Lazyload/index.d.ts +32 -13
- package/types/modules/Moonwalk/index.d.ts +93 -18
|
@@ -11,13 +11,16 @@ import * as Events from '../../events'
|
|
|
11
11
|
import prefersReducedMotion from '../../utils/prefersReducedMotion'
|
|
12
12
|
import imageIsLoaded from '../../utils/imageIsLoaded'
|
|
13
13
|
import imagesAreLoaded from '../../utils/imagesAreLoaded'
|
|
14
|
-
import { set,
|
|
14
|
+
import { set, delayedCall, convertEasing } from '../../utils/motion-helpers'
|
|
15
15
|
import Dom from '../Dom'
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Debug logging
|
|
19
19
|
*/
|
|
20
20
|
const DEBUG = false
|
|
21
|
+
let _idCounter = 0
|
|
22
|
+
|
|
23
|
+
const MOONWALK_ATTRS = ['data-moonwalk', 'data-moonwalk-section', 'data-moonwalk-children']
|
|
21
24
|
|
|
22
25
|
function logMoonwalk(category, message, data = {}) {
|
|
23
26
|
if (DEBUG) {
|
|
@@ -40,30 +43,42 @@ function logComputedStyle(element, props = ['opacity', 'transform']) {
|
|
|
40
43
|
* @property {Object} to - Ending properties for the transition
|
|
41
44
|
*/
|
|
42
45
|
|
|
46
|
+
/**
|
|
47
|
+
* @typedef {Object} AlphaTweenConfig
|
|
48
|
+
* @property {number} [duration] - Duration of the alpha tween (defaults to walk duration)
|
|
49
|
+
* @property {string} [ease] - Easing function (defaults to 'easeIn')
|
|
50
|
+
* @property {number} [delay] - Additional delay before the alpha tween starts
|
|
51
|
+
*/
|
|
52
|
+
|
|
43
53
|
/**
|
|
44
54
|
* @typedef {Object} MoonwalkWalk
|
|
45
55
|
* @property {number} [startDelay=0] - Delay before the animation starts
|
|
46
56
|
* @property {number} [interval=0.15] - Time between animations in a sequence
|
|
47
57
|
* @property {number} [duration=0.65] - Duration of the animation
|
|
48
|
-
* @property {boolean|
|
|
49
|
-
* @property {MoonwalkTransition} transition - The transition configuration
|
|
50
|
-
* @property {string} [sectionTargets] - CSS selector for targeting elements in named sections
|
|
58
|
+
* @property {boolean|AlphaTweenConfig} [alphaTween=false] - Whether to add a separate opacity tween. Pass `true` for defaults or an AlphaTweenConfig object for control.
|
|
59
|
+
* @property {MoonwalkTransition|null} transition - The transition configuration. Set to `null` for CSS-only mode (uses `data-moonwalked` attribute for CSS transitions).
|
|
60
|
+
* @property {string} [sectionTargets] - CSS selector for targeting elements in named sections (instead of using direct children)
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @typedef {Object} MoonwalkRunMeta
|
|
65
|
+
* @property {string|null} direction - The viewport entry/exit direction ('top', 'bottom', 'left', 'right', or null)
|
|
51
66
|
*/
|
|
52
67
|
|
|
53
68
|
/**
|
|
54
69
|
* @typedef {Object} MoonwalkRun
|
|
55
70
|
* @property {number} [threshold=0] - IntersectionObserver threshold
|
|
56
|
-
* @property {
|
|
57
|
-
* @property {
|
|
71
|
+
* @property {(el: HTMLElement, repeated: boolean, meta: MoonwalkRunMeta) => void} callback - Function called when element enters viewport
|
|
72
|
+
* @property {(el: HTMLElement, exited: boolean, meta: MoonwalkRunMeta) => void} [onExit] - Function called when element exits viewport
|
|
58
73
|
* @property {boolean} [repeated=false] - Whether the run should repeat
|
|
59
74
|
* @property {string} [rootMargin] - IntersectionObserver rootMargin
|
|
60
|
-
* @property {
|
|
61
|
-
* @property {
|
|
75
|
+
* @property {(el: HTMLElement) => void} [initialize] - Function called during initialization
|
|
76
|
+
* @property {(el: HTMLElement) => void} [onReady] - Function called when APPLICATION_REVEALED fires, before viewport observers start
|
|
62
77
|
*/
|
|
63
78
|
|
|
64
79
|
/**
|
|
65
80
|
* @typedef {Object} MoonwalkOptions
|
|
66
|
-
* @property {string|
|
|
81
|
+
* @property {string|null} [on=Events.APPLICATION_REVEALED] - Event name to trigger animations. Set to `null` to trigger manually via `ready()`.
|
|
67
82
|
* @property {number} [initialDelay=0.1] - Delay before starting animations
|
|
68
83
|
* @property {boolean} [clearLazyload=false] - Clear data-ll-srcset attributes
|
|
69
84
|
* @property {boolean} [clearNestedSections=true] - Remove nested data-moonwalk-section attributes
|
|
@@ -75,7 +90,7 @@ function logComputedStyle(element, props = ['opacity', 'transform']) {
|
|
|
75
90
|
* @property {boolean} [uniqueIds=false] - Generate unique IDs for moonwalk elements
|
|
76
91
|
* @property {boolean} [addIndexes=false] - Add index attributes to elements
|
|
77
92
|
* @property {Object.<string, MoonwalkRun>} [runs={}] - Run configurations
|
|
78
|
-
* @property {Object.<string, MoonwalkWalk>} walks - Walk configurations
|
|
93
|
+
* @property {Object.<string, MoonwalkWalk>} [walks] - Walk configurations
|
|
79
94
|
*/
|
|
80
95
|
|
|
81
96
|
/** @type {MoonwalkOptions} */
|
|
@@ -166,7 +181,50 @@ const DEFAULT_OPTIONS = {
|
|
|
166
181
|
}
|
|
167
182
|
|
|
168
183
|
/**
|
|
169
|
-
*
|
|
184
|
+
* Normalize alphaTween config into a consistent object form.
|
|
185
|
+
* Returns a new object (never mutates the original).
|
|
186
|
+
*/
|
|
187
|
+
export function normalizeAlphaTween(alphaTween, duration) {
|
|
188
|
+
if (typeof alphaTween === 'object' && alphaTween !== null) {
|
|
189
|
+
return { ...alphaTween, duration: alphaTween.duration || duration }
|
|
190
|
+
}
|
|
191
|
+
if (alphaTween === true) {
|
|
192
|
+
return { duration, ease: 'easeIn' }
|
|
193
|
+
}
|
|
194
|
+
return alphaTween
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Moonwalk animation system for scroll-based reveal animations.
|
|
199
|
+
*
|
|
200
|
+
* ## HTML attributes
|
|
201
|
+
*
|
|
202
|
+
* - `data-moonwalk` / `data-moonwalk="{walkName}"` — marks an element for scroll-triggered animation
|
|
203
|
+
* - `data-moonwalk-section` / `data-moonwalk-section="{walkName}"` — groups elements; unnamed sections
|
|
204
|
+
* animate children individually, named sections stagger-reveal all children at once
|
|
205
|
+
* - `data-moonwalk-children` / `data-moonwalk-children="{walkName}"` — converts direct children
|
|
206
|
+
* into `data-moonwalk` (or `data-moonwalk="{walkName}"`) elements automatically
|
|
207
|
+
* - `data-moonwalk-stage="{walkName}"` — applies a walk transition to the section element itself
|
|
208
|
+
* before its children animate (e.g. fade in a container, then reveal items)
|
|
209
|
+
* - `data-moonwalk-order="{number}"` — overrides the DOM order of children inside a named section;
|
|
210
|
+
* elements with order are sorted first, unordered elements keep their relative position
|
|
211
|
+
* - `data-moonwalk-run="{runName}"` — standalone observer-based callback (not part of walk system)
|
|
212
|
+
* - `data-placeholder` / `data-ll-placeholder` — skip waiting for image load before tweening
|
|
213
|
+
*
|
|
214
|
+
* ## CSS-only mode
|
|
215
|
+
*
|
|
216
|
+
* Set `transition: null` on a walk to use CSS-only animations. Moonwalk will stagger-add the
|
|
217
|
+
* `data-moonwalked` attribute instead of running JS tweens. Style the reveal via CSS:
|
|
218
|
+
* ```css
|
|
219
|
+
* [data-moonwalk="fade"] { opacity: 0; transition: opacity 0.5s; }
|
|
220
|
+
* [data-moonwalk="fade"][data-moonwalked] { opacity: 1; }
|
|
221
|
+
* ```
|
|
222
|
+
*
|
|
223
|
+
* ## alphaTween
|
|
224
|
+
*
|
|
225
|
+
* Can be `true` (defaults: duration from walk, ease `'easeIn'`) or an object:
|
|
226
|
+
* `{ duration?: number, ease?: string, delay?: number }` for fine-grained control
|
|
227
|
+
* over a separate opacity animation layered on top of the main transition.
|
|
170
228
|
*/
|
|
171
229
|
export default class Moonwalk {
|
|
172
230
|
/**
|
|
@@ -178,7 +236,7 @@ export default class Moonwalk {
|
|
|
178
236
|
this.app = app
|
|
179
237
|
this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
|
|
180
238
|
if (container !== document.body) {
|
|
181
|
-
this.opts.on =
|
|
239
|
+
this.opts.on = null
|
|
182
240
|
}
|
|
183
241
|
this.initialize(container)
|
|
184
242
|
}
|
|
@@ -214,6 +272,7 @@ export default class Moonwalk {
|
|
|
214
272
|
}
|
|
215
273
|
|
|
216
274
|
this.addClass()
|
|
275
|
+
this._observers = []
|
|
217
276
|
this.sections = this.initializeSections(container)
|
|
218
277
|
this.runs = this.initializeRuns(container)
|
|
219
278
|
|
|
@@ -225,8 +284,9 @@ export default class Moonwalk {
|
|
|
225
284
|
this.removeAllWalks(container)
|
|
226
285
|
}
|
|
227
286
|
|
|
228
|
-
if (this.opts.on) {
|
|
229
|
-
|
|
287
|
+
if (this.opts.on && typeof this.opts.on === 'string') {
|
|
288
|
+
this._boundOnReady = this.onReady.bind(this)
|
|
289
|
+
window.addEventListener(this.opts.on, this._boundOnReady)
|
|
230
290
|
}
|
|
231
291
|
}
|
|
232
292
|
|
|
@@ -275,12 +335,7 @@ export default class Moonwalk {
|
|
|
275
335
|
* Remove all moonwalks. Useful for clients who prefer reduced motion
|
|
276
336
|
*/
|
|
277
337
|
removeAllWalks(container = document.body) {
|
|
278
|
-
|
|
279
|
-
'data-moonwalk',
|
|
280
|
-
'data-moonwalk-section',
|
|
281
|
-
'data-moonwalk-children',
|
|
282
|
-
]
|
|
283
|
-
keys.forEach((key) => {
|
|
338
|
+
MOONWALK_ATTRS.forEach((key) => {
|
|
284
339
|
const elems = container.querySelectorAll(`[${key}]`)
|
|
285
340
|
Array.from(elems).forEach((el) => el.removeAttribute(key))
|
|
286
341
|
container.removeAttribute(key)
|
|
@@ -288,12 +343,7 @@ export default class Moonwalk {
|
|
|
288
343
|
}
|
|
289
344
|
|
|
290
345
|
removeFor(container = document.body, selector) {
|
|
291
|
-
|
|
292
|
-
'data-moonwalk',
|
|
293
|
-
'data-moonwalk-section',
|
|
294
|
-
'data-moonwalk-children',
|
|
295
|
-
]
|
|
296
|
-
keys.forEach((key) => {
|
|
346
|
+
MOONWALK_ATTRS.forEach((key) => {
|
|
297
347
|
const elems = container.querySelectorAll(`${selector}[${key}]`)
|
|
298
348
|
Array.from(elems).forEach((el) => el.removeAttribute(key))
|
|
299
349
|
})
|
|
@@ -324,10 +374,7 @@ export default class Moonwalk {
|
|
|
324
374
|
*/
|
|
325
375
|
addIds(section) {
|
|
326
376
|
Array.from(section.querySelectorAll('[data-moonwalk]')).forEach((el) => {
|
|
327
|
-
el.setAttribute(
|
|
328
|
-
'data-moonwalk-id',
|
|
329
|
-
Math.random().toString(36).substring(7)
|
|
330
|
-
)
|
|
377
|
+
el.setAttribute('data-moonwalk-id', `mw-${++_idCounter}`)
|
|
331
378
|
})
|
|
332
379
|
}
|
|
333
380
|
|
|
@@ -345,7 +392,7 @@ export default class Moonwalk {
|
|
|
345
392
|
Array.from(elements).forEach((element, index) => {
|
|
346
393
|
element.setAttribute('data-moonwalk-idx', index + 1)
|
|
347
394
|
})
|
|
348
|
-
}
|
|
395
|
+
})
|
|
349
396
|
}
|
|
350
397
|
|
|
351
398
|
/**
|
|
@@ -355,25 +402,27 @@ export default class Moonwalk {
|
|
|
355
402
|
initializeRuns(container = document.body) {
|
|
356
403
|
const runs = container.querySelectorAll('[data-moonwalk-run]')
|
|
357
404
|
return Array.from(runs).map((run) => {
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
return {
|
|
364
|
-
el: run,
|
|
365
|
-
threshold: foundRun.threshold || 0,
|
|
366
|
-
initialize: foundRun.initialize,
|
|
367
|
-
onReady: foundRun.onReady,
|
|
368
|
-
callback: foundRun.callback,
|
|
369
|
-
onExit: foundRun.onExit,
|
|
370
|
-
repeated: foundRun.repeated,
|
|
371
|
-
rootMargin: foundRun.rootMargin,
|
|
372
|
-
}
|
|
405
|
+
const runName = run.getAttribute('data-moonwalk-run')
|
|
406
|
+
const foundRun = this.opts.runs[runName]
|
|
407
|
+
if (!foundRun) {
|
|
408
|
+
console.warn(`==> JUPITER/MOONWALK: Unknown run "${runName}" — not found in opts.runs`)
|
|
409
|
+
return null
|
|
373
410
|
}
|
|
374
411
|
|
|
375
|
-
|
|
376
|
-
|
|
412
|
+
if (foundRun.initialize) {
|
|
413
|
+
foundRun.initialize(run)
|
|
414
|
+
}
|
|
415
|
+
return {
|
|
416
|
+
el: run,
|
|
417
|
+
threshold: foundRun.threshold || 0,
|
|
418
|
+
initialize: foundRun.initialize,
|
|
419
|
+
onReady: foundRun.onReady,
|
|
420
|
+
callback: foundRun.callback,
|
|
421
|
+
onExit: foundRun.onExit,
|
|
422
|
+
repeated: foundRun.repeated,
|
|
423
|
+
rootMargin: foundRun.rootMargin,
|
|
424
|
+
}
|
|
425
|
+
}).filter(Boolean)
|
|
377
426
|
}
|
|
378
427
|
|
|
379
428
|
/**
|
|
@@ -408,7 +457,7 @@ export default class Moonwalk {
|
|
|
408
457
|
}
|
|
409
458
|
|
|
410
459
|
return {
|
|
411
|
-
id:
|
|
460
|
+
id: `mw-${++_idCounter}`,
|
|
412
461
|
el: section,
|
|
413
462
|
name: section.getAttribute('data-moonwalk-section') || null,
|
|
414
463
|
animation: {
|
|
@@ -464,7 +513,7 @@ export default class Moonwalk {
|
|
|
464
513
|
setAttrs(element, val) {
|
|
465
514
|
const affectedElements = []
|
|
466
515
|
|
|
467
|
-
Array.
|
|
516
|
+
Array.from(element.children).forEach((c) => {
|
|
468
517
|
c.setAttribute('data-moonwalk', val)
|
|
469
518
|
affectedElements.push(c)
|
|
470
519
|
})
|
|
@@ -548,6 +597,8 @@ export default class Moonwalk {
|
|
|
548
597
|
}
|
|
549
598
|
|
|
550
599
|
const observer = this.sectionObserver(section)
|
|
600
|
+
section.observer = observer
|
|
601
|
+
this._observers.push(observer)
|
|
551
602
|
observer.observe(section.el)
|
|
552
603
|
}
|
|
553
604
|
|
|
@@ -614,16 +665,7 @@ export default class Moonwalk {
|
|
|
614
665
|
})
|
|
615
666
|
} else {
|
|
616
667
|
// JS animation mode
|
|
617
|
-
|
|
618
|
-
tween.alphaTween.duration = tween.alphaTween.duration
|
|
619
|
-
? tween.alphaTween.duration
|
|
620
|
-
: tween.duration
|
|
621
|
-
} else if (tween.alphaTween === true) {
|
|
622
|
-
tween.alphaTween = {
|
|
623
|
-
duration: tween.duration,
|
|
624
|
-
ease: 'easeIn',
|
|
625
|
-
}
|
|
626
|
-
}
|
|
668
|
+
const resolvedAlpha = normalizeAlphaTween(tween.alphaTween, tween.duration)
|
|
627
669
|
|
|
628
670
|
// Extract ease from to values and convert for Motion.js
|
|
629
671
|
const { ease: tweenEase, ...toValues } = tween.transition.to
|
|
@@ -646,13 +688,13 @@ export default class Moonwalk {
|
|
|
646
688
|
|
|
647
689
|
animate(section.children, toValues, animationOptions)
|
|
648
690
|
|
|
649
|
-
if (
|
|
691
|
+
if (resolvedAlpha) {
|
|
650
692
|
animate(
|
|
651
693
|
section.children,
|
|
652
694
|
{ opacity: 1 },
|
|
653
695
|
{
|
|
654
|
-
duration:
|
|
655
|
-
ease: convertEasing(
|
|
696
|
+
duration: resolvedAlpha.duration,
|
|
697
|
+
ease: convertEasing(resolvedAlpha.ease || 'easeIn'),
|
|
656
698
|
delay: stagger(tween.interval, {
|
|
657
699
|
startDelay: tween.startDelay || 0,
|
|
658
700
|
}),
|
|
@@ -666,7 +708,7 @@ export default class Moonwalk {
|
|
|
666
708
|
}
|
|
667
709
|
}
|
|
668
710
|
},
|
|
669
|
-
{ rootMargin: opts.rootMargin }
|
|
711
|
+
{ rootMargin: opts.rootMargin, threshold: opts.threshold }
|
|
670
712
|
)
|
|
671
713
|
}
|
|
672
714
|
|
|
@@ -680,7 +722,7 @@ export default class Moonwalk {
|
|
|
680
722
|
const orderA = a.getAttribute('data-moonwalk-order')
|
|
681
723
|
? parseInt(a.getAttribute('data-moonwalk-order'))
|
|
682
724
|
: null
|
|
683
|
-
const orderB =
|
|
725
|
+
const orderB = b.getAttribute('data-moonwalk-order')
|
|
684
726
|
? parseInt(b.getAttribute('data-moonwalk-order'))
|
|
685
727
|
: null
|
|
686
728
|
|
|
@@ -758,11 +800,41 @@ export default class Moonwalk {
|
|
|
758
800
|
})
|
|
759
801
|
}
|
|
760
802
|
|
|
803
|
+
destroy() {
|
|
804
|
+
if (this.opts.on && typeof this.opts.on === 'string' && this._boundOnReady) {
|
|
805
|
+
window.removeEventListener(this.opts.on, this._boundOnReady)
|
|
806
|
+
this._boundOnReady = null
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
if (this._observers) {
|
|
810
|
+
this._observers.forEach(obs => obs.disconnect())
|
|
811
|
+
this._observers = []
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
if (this.sections) {
|
|
815
|
+
this.sections.forEach(section => {
|
|
816
|
+
section.el = null
|
|
817
|
+
section.elements = []
|
|
818
|
+
section.children = null
|
|
819
|
+
section.observer = null
|
|
820
|
+
})
|
|
821
|
+
this.sections = []
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
if (this.runs) {
|
|
825
|
+
this.runs.forEach(run => {
|
|
826
|
+
run.el = null
|
|
827
|
+
run.observer = null
|
|
828
|
+
})
|
|
829
|
+
this.runs = []
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
|
|
761
833
|
onReady() {
|
|
762
834
|
if (this.opts.initialDelay) {
|
|
763
835
|
setTimeout(() => {
|
|
764
836
|
this.ready()
|
|
765
|
-
}, this.opts.initialDelay)
|
|
837
|
+
}, this.opts.initialDelay * 1000)
|
|
766
838
|
} else {
|
|
767
839
|
this.ready()
|
|
768
840
|
}
|
|
@@ -778,7 +850,7 @@ export default class Moonwalk {
|
|
|
778
850
|
// Execute onReady callbacks for all runs
|
|
779
851
|
for (let idx = 0; idx < this.runs.length; idx += 1) {
|
|
780
852
|
const run = this.runs[idx]
|
|
781
|
-
if (run
|
|
853
|
+
if (run.onReady) {
|
|
782
854
|
run.onReady(run.el)
|
|
783
855
|
}
|
|
784
856
|
}
|
|
@@ -786,14 +858,10 @@ export default class Moonwalk {
|
|
|
786
858
|
for (let idx = 0; idx < this.runs.length; idx += 1) {
|
|
787
859
|
const run = this.runs[idx]
|
|
788
860
|
|
|
789
|
-
if (!run) {
|
|
790
|
-
return
|
|
791
|
-
}
|
|
792
|
-
|
|
793
861
|
// if this is the last section, set rootMargin to 0
|
|
794
862
|
let rootMargin
|
|
795
863
|
|
|
796
|
-
if (idx === this.
|
|
864
|
+
if (idx === this.runs.length - 1) {
|
|
797
865
|
rootMargin = '0px'
|
|
798
866
|
} else {
|
|
799
867
|
if (run.rootMargin) {
|
|
@@ -804,6 +872,8 @@ export default class Moonwalk {
|
|
|
804
872
|
}
|
|
805
873
|
|
|
806
874
|
const runObserver = this.runObserver(run, rootMargin)
|
|
875
|
+
run.observer = runObserver
|
|
876
|
+
this._observers.push(runObserver)
|
|
807
877
|
runObserver.observe(run.el)
|
|
808
878
|
}
|
|
809
879
|
|
|
@@ -822,6 +892,7 @@ export default class Moonwalk {
|
|
|
822
892
|
|
|
823
893
|
if (!section.name) {
|
|
824
894
|
section.observer = this.observer(section, rootMargin)
|
|
895
|
+
this._observers.push(section.observer)
|
|
825
896
|
}
|
|
826
897
|
|
|
827
898
|
section.elements = section.el.querySelectorAll('[data-moonwalk]')
|
|
@@ -851,6 +922,46 @@ export default class Moonwalk {
|
|
|
851
922
|
}
|
|
852
923
|
}
|
|
853
924
|
|
|
925
|
+
/**
|
|
926
|
+
* Get the viewport entry direction based on current scroll direction.
|
|
927
|
+
* When entering, elements appear from the opposite side of scroll direction.
|
|
928
|
+
*
|
|
929
|
+
* @param {boolean} isEntry - Whether this is an entry (true) or exit (false)
|
|
930
|
+
* @returns {string|null}
|
|
931
|
+
*/
|
|
932
|
+
getScrollDirection(isEntry) {
|
|
933
|
+
if (!this.app.state || !this.app.state.scrollDirection) {
|
|
934
|
+
return null
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
const entryMap = { down: 'bottom', up: 'top', right: 'left', left: 'right' }
|
|
938
|
+
const exitMap = { down: 'top', up: 'bottom', right: 'right', left: 'left' }
|
|
939
|
+
const map = isEntry ? entryMap : exitMap
|
|
940
|
+
|
|
941
|
+
return map[this.app.state.scrollDirection] || null
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
/**
|
|
945
|
+
* Get the exit direction for an element, falling back to position-based
|
|
946
|
+
* detection when scroll direction is unavailable.
|
|
947
|
+
*
|
|
948
|
+
* @param {IntersectionObserverEntry} entry
|
|
949
|
+
* @returns {string|null}
|
|
950
|
+
*/
|
|
951
|
+
getExitDirection(entry) {
|
|
952
|
+
const scrollDir = this.getScrollDirection(false)
|
|
953
|
+
if (scrollDir) {
|
|
954
|
+
return scrollDir
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
const { boundingClientRect: rect } = entry
|
|
958
|
+
if (rect.bottom <= 0) return 'top'
|
|
959
|
+
if (rect.top >= window.innerHeight) return 'bottom'
|
|
960
|
+
if (rect.right <= 0) return 'left'
|
|
961
|
+
if (rect.left >= window.innerWidth) return 'right'
|
|
962
|
+
return null
|
|
963
|
+
}
|
|
964
|
+
|
|
854
965
|
/**
|
|
855
966
|
* Creates and returns the RUN observer for data-moonwalk-run elements
|
|
856
967
|
*
|
|
@@ -858,52 +969,14 @@ export default class Moonwalk {
|
|
|
858
969
|
* @param {*} rootMargin
|
|
859
970
|
*/
|
|
860
971
|
runObserver(run, rootMargin) {
|
|
861
|
-
// Store the previous positions of observed elements to compare for exit direction
|
|
862
|
-
const elementPositions = new WeakMap()
|
|
863
|
-
|
|
864
972
|
return new IntersectionObserver(
|
|
865
973
|
(entries, self) => {
|
|
866
974
|
for (let i = 0; i < entries.length; i += 1) {
|
|
867
975
|
const entry = entries[i]
|
|
868
976
|
|
|
869
|
-
// Store the element's current position in the viewport
|
|
870
|
-
const boundingRect = entry.boundingClientRect
|
|
871
|
-
const viewportHeight = window.innerHeight
|
|
872
|
-
const viewportWidth = window.innerWidth
|
|
873
|
-
|
|
874
977
|
if (entry.isIntersecting && run.callback) {
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
// Use the app's scroll direction for reliable detection
|
|
879
|
-
// If scrollDirection is null, the element was likely revealed on initial load
|
|
880
|
-
if (this.app.state && this.app.state.scrollDirection) {
|
|
881
|
-
// Map scroll direction to viewport entry direction
|
|
882
|
-
switch (this.app.state.scrollDirection) {
|
|
883
|
-
case 'down':
|
|
884
|
-
meta.direction = 'bottom' // When scrolling down, elements enter from bottom
|
|
885
|
-
break
|
|
886
|
-
case 'up':
|
|
887
|
-
meta.direction = 'top' // When scrolling up, elements enter from top
|
|
888
|
-
break
|
|
889
|
-
case 'right':
|
|
890
|
-
meta.direction = 'left' // When scrolling right, elements enter from left
|
|
891
|
-
break
|
|
892
|
-
case 'left':
|
|
893
|
-
meta.direction = 'right' // When scrolling left, elements enter from right
|
|
894
|
-
break
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
// If no scroll direction is available, direction remains null
|
|
898
|
-
|
|
899
|
-
// Store the element's position when it enters the viewport
|
|
900
|
-
elementPositions.set(entry.target, {
|
|
901
|
-
top: boundingRect.top,
|
|
902
|
-
bottom: boundingRect.bottom,
|
|
903
|
-
left: boundingRect.left,
|
|
904
|
-
right: boundingRect.right
|
|
905
|
-
})
|
|
906
|
-
|
|
978
|
+
const meta = { direction: this.getScrollDirection(true) }
|
|
979
|
+
|
|
907
980
|
const runRepeated = entry.target.hasAttribute(
|
|
908
981
|
'data-moonwalk-run-triggered'
|
|
909
982
|
)
|
|
@@ -921,40 +994,8 @@ export default class Moonwalk {
|
|
|
921
994
|
'data-moonwalk-run-exit-triggered'
|
|
922
995
|
)
|
|
923
996
|
entry.target.setAttribute('data-moonwalk-run-exit-triggered', '')
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
let meta = { direction: null }
|
|
927
|
-
|
|
928
|
-
// Use the app's scroll direction for reliable detection
|
|
929
|
-
// For exit direction, it's the opposite of the entry direction for the same scroll
|
|
930
|
-
if (this.app.state && this.app.state.scrollDirection) {
|
|
931
|
-
// Map scroll direction to viewport exit direction
|
|
932
|
-
switch (this.app.state.scrollDirection) {
|
|
933
|
-
case 'down':
|
|
934
|
-
meta.direction = 'top' // When scrolling down, elements exit from top
|
|
935
|
-
break
|
|
936
|
-
case 'up':
|
|
937
|
-
meta.direction = 'bottom' // When scrolling up, elements exit from bottom
|
|
938
|
-
break
|
|
939
|
-
case 'right':
|
|
940
|
-
meta.direction = 'right' // When scrolling right, elements exit from right
|
|
941
|
-
break
|
|
942
|
-
case 'left':
|
|
943
|
-
meta.direction = 'left' // When scrolling left, elements exit from left
|
|
944
|
-
break
|
|
945
|
-
}
|
|
946
|
-
} else {
|
|
947
|
-
// If no scroll direction is available, use the simplest position-based check
|
|
948
|
-
if (boundingRect.bottom <= 0) {
|
|
949
|
-
meta.direction = 'top'
|
|
950
|
-
} else if (boundingRect.top >= viewportHeight) {
|
|
951
|
-
meta.direction = 'bottom'
|
|
952
|
-
} else if (boundingRect.right <= 0) {
|
|
953
|
-
meta.direction = 'left'
|
|
954
|
-
} else if (boundingRect.left >= viewportWidth) {
|
|
955
|
-
meta.direction = 'right'
|
|
956
|
-
}
|
|
957
|
-
}
|
|
997
|
+
|
|
998
|
+
const meta = { direction: this.getExitDirection(entry) }
|
|
958
999
|
|
|
959
1000
|
run.onExit(entry.target, runExited, meta)
|
|
960
1001
|
if (!run.repeated) {
|
|
@@ -987,8 +1028,6 @@ export default class Moonwalk {
|
|
|
987
1028
|
const entry = entries[i]
|
|
988
1029
|
|
|
989
1030
|
if (entry.isIntersecting || entry.intersectionRatio > 0) {
|
|
990
|
-
section.running = true
|
|
991
|
-
|
|
992
1031
|
const walkName = entry.target.getAttribute('data-moonwalk')
|
|
993
1032
|
const targetId =
|
|
994
1033
|
entry.target.getAttribute('data-testid') ||
|
|
@@ -1009,25 +1048,14 @@ export default class Moonwalk {
|
|
|
1009
1048
|
// Default interval to 0.15 if not specified (same as default walk)
|
|
1010
1049
|
const interval = cfg.interval !== undefined ? cfg.interval : 0.15
|
|
1011
1050
|
|
|
1012
|
-
|
|
1013
|
-
let overlap =
|
|
1051
|
+
const alphaTween = normalizeAlphaTween(cfg.alphaTween, duration)
|
|
1052
|
+
let overlap = interval - duration
|
|
1014
1053
|
|
|
1015
1054
|
if (section.stage.firstTween) {
|
|
1016
1055
|
overlap = 0
|
|
1017
1056
|
section.stage.firstTween = false
|
|
1018
1057
|
}
|
|
1019
1058
|
|
|
1020
|
-
if (typeof alphaTween === 'object' && alphaTween !== null) {
|
|
1021
|
-
alphaTween.duration = alphaTween.duration
|
|
1022
|
-
? alphaTween.duration
|
|
1023
|
-
: duration
|
|
1024
|
-
} else if (alphaTween === true) {
|
|
1025
|
-
alphaTween = {
|
|
1026
|
-
duration,
|
|
1027
|
-
ease: 'easeIn',
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
1059
|
const tweenFn = () => {
|
|
1032
1060
|
if (transition) {
|
|
1033
1061
|
this.tweenJS(
|
|
@@ -1104,6 +1132,7 @@ export default class Moonwalk {
|
|
|
1104
1132
|
* @param {*} section
|
|
1105
1133
|
* @param {*} target
|
|
1106
1134
|
* @param {*} tweenDuration
|
|
1135
|
+
* @param {*} tweenInterval
|
|
1107
1136
|
* @param {*} tweenTransition
|
|
1108
1137
|
* @param {*} tweenOverlap
|
|
1109
1138
|
* @param {*} alphaTween
|
|
@@ -1208,9 +1237,10 @@ export default class Moonwalk {
|
|
|
1208
1237
|
*
|
|
1209
1238
|
* @param {*} section
|
|
1210
1239
|
* @param {*} target
|
|
1211
|
-
* @param {*}
|
|
1212
|
-
* @param {*}
|
|
1213
|
-
* @param {*}
|
|
1240
|
+
* @param {*} tweenDuration
|
|
1241
|
+
* @param {*} tweenInterval
|
|
1242
|
+
* @param {*} tweenTransition
|
|
1243
|
+
* @param {*} tweenOverlap
|
|
1214
1244
|
*/
|
|
1215
1245
|
tweenCSS(
|
|
1216
1246
|
section,
|
package/src/utils/rafCallback.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const DEFAULT_FPS = 60
|
|
2
|
-
const SCOPES =
|
|
2
|
+
const SCOPES = new Map()
|
|
3
3
|
|
|
4
4
|
export default (callback, fps = DEFAULT_FPS) =>
|
|
5
5
|
(...passedArgs) =>
|
|
@@ -7,12 +7,11 @@ export default (callback, fps = DEFAULT_FPS) =>
|
|
|
7
7
|
const msCurrent = new Date().getTime()
|
|
8
8
|
const fpsInterval = 1000 / fps
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const msDelta = SCOPES[callback] ? msCurrent - SCOPES[callback] : null
|
|
10
|
+
const msLast = SCOPES.get(callback) || null
|
|
11
|
+
const msDelta = msLast ? msCurrent - msLast : null
|
|
13
12
|
|
|
14
13
|
if (msDelta === null || msDelta > fpsInterval) {
|
|
15
|
-
SCOPES
|
|
14
|
+
SCOPES.set(callback, msCurrent - (msDelta % fpsInterval))
|
|
16
15
|
callback(...passedArgs)
|
|
17
16
|
}
|
|
18
17
|
})
|
|
@@ -3,8 +3,8 @@ export default class Application {
|
|
|
3
3
|
debugType: number;
|
|
4
4
|
debugOverlay: Element;
|
|
5
5
|
userAgent: string;
|
|
6
|
-
_lastWindowHeight: number;
|
|
7
6
|
breakpoint: any;
|
|
7
|
+
root: HTMLElement;
|
|
8
8
|
language: string;
|
|
9
9
|
size: {
|
|
10
10
|
width: number;
|
|
@@ -28,19 +28,19 @@ export default class Application {
|
|
|
28
28
|
};
|
|
29
29
|
opts: any;
|
|
30
30
|
focusableSelectors: any;
|
|
31
|
+
browser: any;
|
|
31
32
|
featureTests: any;
|
|
32
33
|
breakpoints: any;
|
|
33
34
|
fontLoader: any;
|
|
34
|
-
fader: any;
|
|
35
35
|
callbacks: {};
|
|
36
36
|
SCROLL_LOCKED: boolean;
|
|
37
37
|
SCROLLBAR_WIDTH: number;
|
|
38
38
|
INITIALIZED: boolean;
|
|
39
39
|
PREFERS_REDUCED_MOTION: boolean;
|
|
40
|
-
beforeInitializedEvent: CustomEvent<
|
|
41
|
-
initializedEvent: CustomEvent<
|
|
42
|
-
readyEvent: CustomEvent<
|
|
43
|
-
revealedEvent: CustomEvent<
|
|
40
|
+
beforeInitializedEvent: CustomEvent<this>;
|
|
41
|
+
initializedEvent: CustomEvent<this>;
|
|
42
|
+
readyEvent: CustomEvent<this>;
|
|
43
|
+
revealedEvent: CustomEvent<this>;
|
|
44
44
|
/**
|
|
45
45
|
* Main init. Called from client application on DOMReady.
|
|
46
46
|
*/
|
|
@@ -110,7 +110,6 @@ export default class Application {
|
|
|
110
110
|
* Ugly hacks
|
|
111
111
|
*/
|
|
112
112
|
hacks(): void;
|
|
113
|
-
getIOSCurrentInnerHeight(): number;
|
|
114
113
|
getIOSInnerHeightMax(): number;
|
|
115
114
|
/**
|
|
116
115
|
* Event emitters
|
|
@@ -144,7 +143,7 @@ export default class Application {
|
|
|
144
143
|
onScroll(e: any): void;
|
|
145
144
|
onVisibilityChange(e: any): void;
|
|
146
145
|
pollForElement(selector: any, time?: number, callback?: () => void): void;
|
|
147
|
-
pollForVar(
|
|
146
|
+
pollForVar(getter: any, time?: number, callback?: () => void): void;
|
|
148
147
|
setupDebug(): void;
|
|
149
148
|
toggleDebug(): void;
|
|
150
149
|
/**
|