mirror of
https://github.com/tabler/tabler.git
synced 2026-10-12 05:06:55 +04:00
Fix complete.bs.countup firing twice when update() runs before the element is in view (#3193)
This commit is contained in:
1 parent
e2da442007
commit
77480290dc
3 files changed
+62
-7
No files matched your search
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/core": patch
|
||||
---
|
||||
|
||||
Fixed CountUp firing `complete.bs.countup` twice when `update()` ran before it scrolled into view.
|
||||
+15
-7
@@ -147,6 +147,7 @@ class CountUp extends BaseComponent {
|
||||
_elapsed = 0
|
||||
_running = false
|
||||
_paused = false
|
||||
_started = false
|
||||
|
||||
constructor(element: ElementSelector, config?: ComponentConfigInput) {
|
||||
super(element, config)
|
||||
@@ -175,13 +176,7 @@ class CountUp extends BaseComponent {
|
||||
return
|
||||
}
|
||||
|
||||
this._observer = new IntersectionObserver((entries) => {
|
||||
if (entries.some((entry) => entry.isIntersecting)) {
|
||||
this._observer?.disconnect()
|
||||
this._observer = null
|
||||
this.start()
|
||||
}
|
||||
})
|
||||
this._observer = new IntersectionObserver((entries) => this._observerCallback(entries))
|
||||
this._observer.observe(this._element)
|
||||
}
|
||||
|
||||
@@ -253,8 +248,21 @@ class CountUp extends BaseComponent {
|
||||
return super._mergeConfigObj({ ...coerceOptions(dataOptions), ...config }, element)
|
||||
}
|
||||
|
||||
_observerCallback(entries: IntersectionObserverEntry[]): void {
|
||||
if (entries.some((entry) => entry.isIntersecting)) {
|
||||
this._observer?.disconnect()
|
||||
this._observer = null
|
||||
|
||||
// update() may have already animated it while it was off screen.
|
||||
if (!this._started) {
|
||||
this.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_animate(from: number, to: number): void {
|
||||
this._stop()
|
||||
this._started = true
|
||||
|
||||
// Users who asked for less motion get the final number at once.
|
||||
if (from === to || this._config.duration <= 0 || reducedMotion()) {
|
||||
|
||||
@@ -113,6 +113,48 @@ describe('CountUp', () => {
|
||||
|
||||
expect(element().textContent).toBe('77')
|
||||
})
|
||||
|
||||
it('should not fire complete.bs.countup a second time when the element scrolls into view after update()', () => {
|
||||
const spy = vi.fn()
|
||||
element().addEventListener('complete.bs.countup', spy)
|
||||
|
||||
const instance = new CountUp(element(), { duration: 0 })
|
||||
instance.update(77)
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
|
||||
instance._observerCallback([{ isIntersecting: true } as unknown as IntersectionObserverEntry])
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
expect(element().textContent).toBe('77')
|
||||
})
|
||||
|
||||
it('should not fire complete.bs.countup twice when update() ran off screen and it then really scrolls into view', async () => {
|
||||
const spy = vi.fn()
|
||||
const off = document.createElement('h1')
|
||||
off.dataset.countup = '{"duration":0.1}'
|
||||
off.textContent = '500'
|
||||
off.style.position = 'absolute'
|
||||
off.style.top = '-10000px'
|
||||
off.style.left = '-10000px'
|
||||
document.body.append(off)
|
||||
off.addEventListener('complete.bs.countup', spy)
|
||||
|
||||
try {
|
||||
const instance = new CountUp(off)
|
||||
instance.update(77)
|
||||
await wait(300)
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
|
||||
off.style.top = '0px'
|
||||
off.style.left = '0px'
|
||||
await wait(500)
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
expect(off.textContent).toBe('77')
|
||||
} finally {
|
||||
off.remove()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('data-tblr-countup', () => {
|
||||
|
||||
Reference in new issue
Block a user