Fix CountUp printing -0 when a value crosses or rounds to zero (#3221)

Co-authored-by: codecalm <codecalm@gmail.com>
This commit is contained in:
Bartosz-Doandcodecalm authored and GitHub committed 2026-09-25 15:34:35 +02:00
1 parent 0f6e843977
commit 0a9edcb400
3 files changed
+47 -4

No files matched your search

+8 -4
View File
@@ -331,14 +331,18 @@ class CountUp extends BaseComponent {
}
if (format === 'time') {
const minutes = Math.round(Math.abs(value))
return `${value < 0 ? '-' : ''}${prefix}${Math.floor(minutes / 60)}:${String(minutes % 60).padStart(2, '0')}${suffix}`
// Rounded away from zero on both sides, so -90.5 and 90.5 give the same
// minutes; a value that rounds to 0 stays unsigned (-0 < 0 is false).
const rounded = Math.sign(value) * Math.round(Math.abs(value))
const minutes = Math.abs(rounded)
return `${rounded < 0 ? '-' : ''}${prefix}${Math.floor(minutes / 60)}:${String(minutes % 60).padStart(2, '0')}${suffix}`
}
const [integer, fraction] = Math.abs(value).toFixed(decimalPlaces).split('.') as [string, string | undefined]
const fixed = value.toFixed(decimalPlaces)
const [integer, fraction] = fixed.replace('-', '').split('.') as [string, string | undefined]
const grouped = useGrouping ? integer.replace(/\B(?=(\d{3})+(?!\d))/g, separator) : integer
return `${value < 0 ? '-' : ''}${prefix}${grouped}${fraction ? decimal + fraction : ''}${suffix}`
return `${Number(fixed) < 0 ? '-' : ''}${prefix}${grouped}${fraction ? decimal + fraction : ''}${suffix}`
}
}
+34
View File
@@ -239,6 +239,15 @@ describe('CountUp', () => {
instance.reset()
expect(element().textContent).toBe('50,000')
})
it('should not print a negative zero when a value rounds to zero', async () => {
fixtureEl.innerHTML = '<h1 data-countup>-0.3</h1>'
quick({ decimalPlaces: 0 })
await wait(300)
expect(element().textContent).toBe('0')
})
})
describe('format', () => {
@@ -262,6 +271,31 @@ describe('CountUp', () => {
expect(element().textContent).toBe('9999999999')
})
it('should not print a negative zero when a time rounds to zero minutes', async () => {
fixtureEl.innerHTML = '<h1 data-countup=\'{"format":"time"}\'>0:00</h1>'
const instance = new CountUp(element(), { autoAnimate: false, duration: 0.1, format: 'time' })
await wait(300)
instance.update(-0.4)
await wait(300)
expect(element().textContent).toBe('0:00')
})
it('should round negative half minutes like positive ones in the time format', async () => {
fixtureEl.innerHTML = '<h1>0:00</h1>'
const instance = new CountUp(element(), { autoAnimate: false, duration: 0.1, format: 'time' })
await wait(300)
instance.update(90.5)
await wait(300)
expect(element().textContent).toBe('1:31')
instance.update(-90.5)
await wait(300)
expect(element().textContent).toBe('-1:31')
})
it('should use a formatter function from the config', async () => {
quick({ formatter: (value: number) => `${Math.round(value / 1000)}k` })
await wait(300)