Skip to content

Commit ad3eaff

Browse files
fix(shared): parse negative decimals without integer part in numberRegex (#2397) (#2561)
Co-authored-by: Josh <joshua.ellis18@gmail.com>
1 parent fac7d3b commit ad3eaff

3 files changed

Lines changed: 33 additions & 1 deletion

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@react-spring/shared': patch
3+
---
4+
5+
fix(shared): parse negative decimals without an integer part in numberRegex
6+
7+
`numberRegex` required at least one digit before the decimal point, so a value like `-.0000298023` (emitted by Chrome for some `lab()`/`oklch()` colors) was split into several tokens instead of one. That inflated a keyframe's number count and threw `The arity of each "output" value must be equal` when interpolating between color formats. The regex now matches a leading-dot fraction as a single token while keeping all previously supported number formats.

packages/shared/src/regexs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Problem: https://github.com/animatedjs/animated/pull/102
22
// Solution: https://stackoverflow.com/questions/638565/parsing-scientific-notation-sensibly/658662
3-
export const numberRegex = /[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?/g
3+
export const numberRegex = /[+\-]?(?:(?:\d*\.\d+)|\d+)(?:[eE][+\-]?\d+)?/g
44

55
// Covers rgb, rgba, hsl, hsla
66
// Taken from https://gist.github.com/olmokramer/82ccce673f86db7cda5e

packages/shared/src/stringInterpolation.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,28 @@ it('interpolates a number-less output value instead of throwing on a null match'
1616
expect(interpolate(0)).toBe('none')
1717
expect(interpolate(0.5)).toBe('none')
1818
})
19+
20+
// https://github.com/pmndrs/react-spring/issues/2397
21+
// lab() values like `lab(77.96% -.0000298023 0)` contain decimals with no
22+
// integer part and a leading minus. The old number regex split these into
23+
// multiple tokens (`0`, `0`, `0`, `0`, `298023`) which broke arity
24+
// checks against other keyframes.
25+
it('interpolates colors containing negative decimals without an integer part', () => {
26+
const interpolate = createStringInterpolator({
27+
range: [0, 1],
28+
output: ['lab(77.96% -.0000298023 0)', 'oklch(0.4 0.2639 271.35 / 1)'],
29+
})
30+
31+
expect(() => interpolate(0.5)).not.toThrow()
32+
expect(interpolate(1)).toBe('oklch(0.4 0.2639 271.35 / 1)')
33+
})
34+
35+
it('parses a standalone negative decimal without an integer part', () => {
36+
const interpolate = createStringInterpolator({
37+
range: [0, 1],
38+
output: ['translateY(-.5px)', 'translateY(10px)'],
39+
})
40+
41+
expect(interpolate(0.5)).toBe('translateY(4.75px)')
42+
expect(interpolate(1)).toBe('translateY(10px)')
43+
})

0 commit comments

Comments
 (0)