Skip to content

Commit f16db94

Browse files
authored
fix(postcss-ordered-values): incorrect order when using calc for animation property (#1629)
1 parent edc002b commit f16db94

File tree

3 files changed

+78
-10
lines changed

3 files changed

+78
-10
lines changed

packages/cssnano/test/issue1527.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
'use strict';
2+
const { test } = require('node:test');
3+
const assert = require('node:assert/strict');
4+
const postcss = require('postcss');
5+
const preset = require('cssnano-preset-default');
6+
const nano = require('..');
7+
8+
const fixture = `
9+
.b {
10+
animation: opacity 0ms calc(1000ms);
11+
}
12+
`;
13+
14+
const expected = '.b{animation:opacity 0ms calc(1s)}';
15+
16+
test('it should keep quote', () => {
17+
const processor = postcss([
18+
nano({
19+
preset: preset({ calc: false }),
20+
}),
21+
]);
22+
23+
return processor
24+
.process(fixture, { from: undefined })
25+
.then((r) => assert.strictEqual(r.css, expected));
26+
});

packages/postcss-ordered-values/src/rules/animation.js

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ const { unit } = require('postcss-value-parser');
33
const { getArguments } = require('cssnano-utils');
44
const addSpace = require('../lib/addSpace');
55
const getValue = require('../lib/getValue');
6+
const mathFunctions = require('../lib/mathfunctions.js');
67

78
// animation: [ none | <keyframes-name> ] || <time> || <single-timing-function> || <time> || <single-animation-iteration-count> || <single-animation-direction> || <single-animation-fill-mode> || <single-animation-play-state>
8-
const functions = new Set(['steps', 'cubic-bezier', 'frames']);
9-
const keywords = new Set([
9+
const timingFunctions = new Set(['steps', 'cubic-bezier', 'frames']);
10+
const timingKeywords = new Set([
1011
'ease',
1112
'ease-in',
1213
'ease-in-out',
@@ -28,11 +29,35 @@ const timeUnits = new Set(['ms', 's']);
2829

2930
/**
3031
* @param {string} value
31-
* @param {string} type
32+
* @param {import('postcss-value-parser').Node} node
33+
* @return {false | import('postcss-value-parser').Dimension}
34+
*/
35+
function unitFromNode(value, node) {
36+
if (node.type !== 'function') {
37+
return unit(value);
38+
}
39+
if (mathFunctions.has(value)) {
40+
// If it is a math function, it checks the unit of the parameter and returns it.
41+
for (const param of node.nodes) {
42+
const paramUnit = unitFromNode(param.value.toLowerCase(), param);
43+
if (paramUnit && paramUnit.unit && paramUnit.unit !== '%') {
44+
return paramUnit;
45+
}
46+
}
47+
}
48+
return false;
49+
}
50+
51+
/**
52+
* @param {string} value
53+
* @param {import('postcss-value-parser').Node} node
3254
* @return {boolean}
3355
*/
34-
const isTimingFunction = (value, type) => {
35-
return (type === 'function' && functions.has(value)) || keywords.has(value);
56+
const isTimingFunction = (value, { type }) => {
57+
return (
58+
(type === 'function' && timingFunctions.has(value)) ||
59+
timingKeywords.has(value)
60+
);
3661
};
3762
/**
3863
* @param {string} value
@@ -57,19 +82,21 @@ const isPlayState = (value) => {
5782
};
5883
/**
5984
* @param {string} value
85+
* @param {import('postcss-value-parser').Node} node
6086
* @return {boolean}
6187
*/
62-
const isTime = (value) => {
63-
const quantity = unit(value);
88+
const isTime = (value, node) => {
89+
const quantity = unitFromNode(value, node);
6490

6591
return quantity && timeUnits.has(quantity.unit);
6692
};
6793
/**
6894
* @param {string} value
95+
* @param {import('postcss-value-parser').Node} node
6996
* @return {boolean}
7097
*/
71-
const isIterationCount = (value) => {
72-
const quantity = unit(value);
98+
const isIterationCount = (value, node) => {
99+
const quantity = unitFromNode(value, node);
73100

74101
return value === 'infinite' || (quantity && !quantity.unit);
75102
};
@@ -113,7 +140,7 @@ function normalize(args) {
113140
value = value.toLowerCase();
114141

115142
const hasMatch = stateConditions.some(({ property, delegate }) => {
116-
if (delegate(value, type) && !state[property].length) {
143+
if (delegate(value, node) && !state[property].length) {
117144
state[property] = [node, addSpace()];
118145
return true;
119146
}

packages/postcss-ordered-values/test/rules.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const assert = require('node:assert/strict');
44
const valueParser = require('postcss-value-parser');
55
const normalizeBorder = require('../src/rules/border.js');
66
const normalizeBoxShadow = require('../src/rules/boxShadow.js');
7+
const normalizeAnimation = require('../src/rules/animation.js');
78

89
test('border order handles max', () => {
910
assert.strictEqual(
@@ -27,3 +28,17 @@ test('ordering box shadows handles functions in box shadows', () => {
2728
'inset 0 min(1em, 1px) 0 1px red'
2829
);
2930
});
31+
32+
test('animation order handles calc', () => {
33+
assert.strictEqual(
34+
normalizeAnimation(valueParser('0ms opacity calc(1ms)')),
35+
'opacity 0ms calc(1ms)'
36+
);
37+
});
38+
39+
test('animation order handles max', () => {
40+
assert.strictEqual(
41+
normalizeAnimation(valueParser('0ms opacity max(-1 * 1ms, 1ms)')),
42+
'opacity 0ms max(-1 * 1ms, 1ms)'
43+
);
44+
});

0 commit comments

Comments
 (0)