postcss-minify-gradients 8.0.3 → 8.0.5
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/package.json +3 -3
- package/src/index.js +181 -65
- package/src/isColorStop.js +12 -2
- package/types/isColorStop.d.ts.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "postcss-minify-gradients",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.5",
|
|
4
4
|
"description": "Minify gradient parameters with PostCSS.",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
},
|
|
32
32
|
"repository": {
|
|
33
33
|
"type": "git",
|
|
34
|
-
"url": "cssnano/cssnano"
|
|
34
|
+
"url": "git+https://github.com/cssnano/cssnano.git"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@colordx/core": "^5.5.0",
|
|
38
38
|
"postcss-value-parser": "^4.2.0",
|
|
39
|
-
"cssnano-utils": "^6.0.
|
|
39
|
+
"cssnano-utils": "^6.0.4"
|
|
40
40
|
},
|
|
41
41
|
"bugs": {
|
|
42
42
|
"url": "https://github.com/cssnano/cssnano/issues"
|
package/src/index.js
CHANGED
|
@@ -11,7 +11,7 @@ const directionsToAngles = new Map([
|
|
|
11
11
|
]);
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Returns whether b is less than a.
|
|
14
|
+
* Returns whether b is less than or equal to a.
|
|
15
15
|
*
|
|
16
16
|
* @param {valueParser.Dimension} a
|
|
17
17
|
* @param {valueParser.Dimension} b
|
|
@@ -20,108 +20,217 @@ const directionsToAngles = new Map([
|
|
|
20
20
|
function isLessThan(a, b) {
|
|
21
21
|
return (
|
|
22
22
|
a.unit.toLowerCase() === b.unit.toLowerCase() &&
|
|
23
|
-
parseFloat(a.number) >= parseFloat(b.number)
|
|
23
|
+
Number.parseFloat(a.number) >= Number.parseFloat(b.number)
|
|
24
24
|
);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
28
|
+
* Compares positions when their ordering is independent of layout.
|
|
29
29
|
*
|
|
30
|
-
* @param {
|
|
31
|
-
* @
|
|
30
|
+
* @param {valueParser.Dimension} a
|
|
31
|
+
* @param {valueParser.Dimension} b
|
|
32
|
+
* @returns {boolean | undefined}
|
|
32
33
|
*/
|
|
33
|
-
function
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
function isLessThanOrEqual(a, b) {
|
|
35
|
+
if (a.unit.toLowerCase() === b.unit.toLowerCase()) {
|
|
36
|
+
return isLessThan(a, b);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const aNumber = Number.parseFloat(a.number);
|
|
40
|
+
const bNumber = Number.parseFloat(b.number);
|
|
41
|
+
|
|
42
|
+
if (aNumber === 0) {
|
|
43
|
+
return bNumber <= 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (bNumber === 0) {
|
|
47
|
+
return aNumber >= 0;
|
|
48
|
+
}
|
|
38
49
|
}
|
|
39
50
|
|
|
40
51
|
/**
|
|
41
|
-
*
|
|
52
|
+
* Returns whether a node is a literal color stop position.
|
|
42
53
|
*
|
|
43
|
-
* @param {import('postcss-value-parser').
|
|
44
|
-
* @returns {
|
|
54
|
+
* @param {import('postcss-value-parser').Node} node
|
|
55
|
+
* @returns {boolean}
|
|
45
56
|
*/
|
|
46
|
-
function
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
function isPosition(node) {
|
|
58
|
+
return node.type === 'word' && valueParser.unit(node.value) !== false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Returns whether an argument begins a color stop.
|
|
63
|
+
*
|
|
64
|
+
* @param {import('postcss-value-parser').Node[]} argument
|
|
65
|
+
* @returns {boolean}
|
|
66
|
+
*/
|
|
67
|
+
function isColorStopArgument(argument) {
|
|
68
|
+
const first = argument[0];
|
|
69
|
+
|
|
70
|
+
if (!first) {
|
|
71
|
+
return false;
|
|
50
72
|
}
|
|
51
|
-
/** @type {valueParser.Dimension | false | undefined} */
|
|
52
|
-
let previousStop = undefined;
|
|
53
73
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
74
|
+
if (first.type === 'function') {
|
|
75
|
+
return !new Set(['calc', 'clamp', 'max', 'min']).has(
|
|
76
|
+
first.value.toLowerCase()
|
|
77
|
+
);
|
|
78
|
+
}
|
|
59
79
|
|
|
60
|
-
|
|
61
|
-
|
|
80
|
+
return first.type === 'word' && isColorStop(first.value);
|
|
81
|
+
}
|
|
62
82
|
|
|
63
|
-
|
|
64
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Gets the position nodes from a color stop or transition hint.
|
|
85
|
+
*
|
|
86
|
+
* @param {import('postcss-value-parser').Node[]} argument
|
|
87
|
+
* @param {boolean} colorStopArgument
|
|
88
|
+
* @returns {import('postcss-value-parser').Node[]}
|
|
89
|
+
*/
|
|
90
|
+
function getPositions(argument, colorStopArgument) {
|
|
91
|
+
return argument.slice(colorStopArgument ? 1 : 0).filter((node) => {
|
|
92
|
+
return node.type !== 'space' && node.type !== 'comment';
|
|
93
|
+
});
|
|
94
|
+
}
|
|
65
95
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Updates the largest preceding position, replacing a position that will be
|
|
98
|
+
* fixed up with its shorter equivalent.
|
|
99
|
+
*
|
|
100
|
+
* @param {valueParser.Dimension | undefined} largestPosition
|
|
101
|
+
* @param {import('postcss-value-parser').Node} position
|
|
102
|
+
* @returns {valueParser.Dimension | undefined}
|
|
103
|
+
*/
|
|
104
|
+
function updateLargestPosition(largestPosition, position) {
|
|
105
|
+
if (!isPosition(position)) {
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
75
108
|
|
|
76
|
-
|
|
77
|
-
}
|
|
109
|
+
const currentPosition = valueParser.unit(position.value);
|
|
78
110
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
111
|
+
if (!currentPosition) {
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
82
114
|
|
|
83
|
-
|
|
115
|
+
if (!largestPosition) {
|
|
116
|
+
return currentPosition;
|
|
117
|
+
}
|
|
84
118
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
119
|
+
const isFixedUp = isLessThanOrEqual(largestPosition, currentPosition);
|
|
120
|
+
|
|
121
|
+
if (isFixedUp) {
|
|
122
|
+
position.value = '0';
|
|
123
|
+
return largestPosition;
|
|
88
124
|
}
|
|
89
125
|
|
|
90
|
-
return
|
|
126
|
+
return isFixedUp === undefined ? undefined : currentPosition;
|
|
91
127
|
}
|
|
92
128
|
|
|
93
129
|
/**
|
|
94
|
-
*
|
|
130
|
+
* Optimizes a standard gradient color stop list using the color stop fixup
|
|
131
|
+
* algorithm. A non-literal position prevents later comparisons because its
|
|
132
|
+
* used value can only be known during layout.
|
|
95
133
|
*
|
|
96
|
-
* @param {import('postcss-value-parser').
|
|
97
|
-
* @returns {
|
|
134
|
+
* @param {import('postcss-value-parser').Node[][]} args
|
|
135
|
+
* @returns {void}
|
|
98
136
|
*/
|
|
99
|
-
function
|
|
100
|
-
const
|
|
101
|
-
/** @type {valueParser.Dimension | false | undefined} */
|
|
102
|
-
let previousStop = undefined;
|
|
137
|
+
function optimizeColorStops(args) {
|
|
138
|
+
const firstStopIndex = args.findIndex(isColorStopArgument);
|
|
103
139
|
|
|
104
|
-
|
|
140
|
+
if (firstStopIndex === -1) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
105
143
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
144
|
+
const stops = [];
|
|
145
|
+
let largestPosition = /** @type {valueParser.Dimension | undefined} */ (
|
|
146
|
+
undefined
|
|
147
|
+
);
|
|
148
|
+
let hasSeenStop = false;
|
|
110
149
|
|
|
111
|
-
|
|
150
|
+
for (const argument of args.slice(firstStopIndex)) {
|
|
151
|
+
const colorStop = isColorStopArgument(argument);
|
|
152
|
+
const positions = getPositions(argument, colorStop);
|
|
112
153
|
|
|
113
|
-
if (
|
|
114
|
-
|
|
154
|
+
if (colorStop) {
|
|
155
|
+
stops.push({ argument, positions });
|
|
156
|
+
|
|
157
|
+
if (!hasSeenStop && positions.length === 0) {
|
|
158
|
+
largestPosition = /** @type {valueParser.Dimension} */ (
|
|
159
|
+
valueParser.unit('0%')
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
hasSeenStop = true;
|
|
164
|
+
}
|
|
115
165
|
|
|
166
|
+
if (positions.length === 0) {
|
|
116
167
|
continue;
|
|
117
168
|
}
|
|
118
169
|
|
|
119
|
-
|
|
120
|
-
|
|
170
|
+
for (const position of positions) {
|
|
171
|
+
largestPosition = updateLargestPosition(largestPosition, position);
|
|
121
172
|
}
|
|
173
|
+
}
|
|
122
174
|
|
|
123
|
-
|
|
175
|
+
const firstStop = stops[0];
|
|
176
|
+
const lastStop = stops.at(-1);
|
|
177
|
+
|
|
178
|
+
if (
|
|
179
|
+
firstStop &&
|
|
180
|
+
firstStop.positions.length === 1 &&
|
|
181
|
+
firstStop.argument.length === 3 &&
|
|
182
|
+
firstStop.positions[0].value === '0%'
|
|
183
|
+
) {
|
|
184
|
+
firstStop.argument[1].value = firstStop.positions[0].value = '';
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (
|
|
188
|
+
lastStop &&
|
|
189
|
+
lastStop.positions.length === 1 &&
|
|
190
|
+
lastStop.argument.length === 3 &&
|
|
191
|
+
lastStop.positions[0].value === '100%'
|
|
192
|
+
) {
|
|
193
|
+
lastStop.argument[1].value = lastStop.positions[0].value = '';
|
|
124
194
|
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Shortens a direction like `to left top` into an angle.
|
|
199
|
+
*
|
|
200
|
+
* @param {import('postcss-value-parser').FunctionNode} node
|
|
201
|
+
* @returns {void}
|
|
202
|
+
*/
|
|
203
|
+
function shortenDirection(node) {
|
|
204
|
+
node.nodes = node.nodes.slice(2);
|
|
205
|
+
node.nodes[0].value = /** @type {string} */ (
|
|
206
|
+
directionsToAngles.get(node.nodes[0].value.toLowerCase())
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Optimises a linear gradient.
|
|
212
|
+
*
|
|
213
|
+
* @param {import('postcss-value-parser').FunctionNode} node
|
|
214
|
+
* @returns {false}
|
|
215
|
+
*/
|
|
216
|
+
function optimizeLinearGradient(node) {
|
|
217
|
+
const args = getArguments(node);
|
|
218
|
+
if (node.nodes[0]?.value.toLowerCase() === 'to' && args[0].length === 3) {
|
|
219
|
+
shortenDirection(node);
|
|
220
|
+
}
|
|
221
|
+
optimizeColorStops(getArguments(node));
|
|
222
|
+
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Optimises a radial gradient.
|
|
228
|
+
*
|
|
229
|
+
* @param {import('postcss-value-parser').ParsedValue | import('postcss-value-parser').FunctionNode} node
|
|
230
|
+
* @returns {false}
|
|
231
|
+
*/
|
|
232
|
+
function optimizeRadialGradient(node) {
|
|
233
|
+
optimizeColorStops(getArguments(node));
|
|
125
234
|
|
|
126
235
|
return false;
|
|
127
236
|
}
|
|
@@ -242,6 +351,13 @@ function optimise(decl) {
|
|
|
242
351
|
) {
|
|
243
352
|
return optimizeWebkitRadialGradient(node);
|
|
244
353
|
}
|
|
354
|
+
|
|
355
|
+
if (
|
|
356
|
+
lowerCasedValue === 'conic-gradient' ||
|
|
357
|
+
lowerCasedValue === 'repeating-conic-gradient'
|
|
358
|
+
) {
|
|
359
|
+
optimizeColorStops(getArguments(node));
|
|
360
|
+
}
|
|
245
361
|
return false;
|
|
246
362
|
})
|
|
247
363
|
.toString();
|
package/src/isColorStop.js
CHANGED
|
@@ -4,7 +4,14 @@ const { colordx: colord, extend } = require('@colordx/core');
|
|
|
4
4
|
const hwbPlugin = require('@colordx/core/plugins/hwb');
|
|
5
5
|
const namesPlugin = require('@colordx/core/plugins/names');
|
|
6
6
|
|
|
7
|
-
extend([
|
|
7
|
+
extend([
|
|
8
|
+
/** @type {import('@colordx/core').Plugin} */ (
|
|
9
|
+
/** @type {unknown} */ (hwbPlugin)
|
|
10
|
+
),
|
|
11
|
+
/** @type {import('@colordx/core').Plugin} */ (
|
|
12
|
+
/** @type {unknown} */ (namesPlugin)
|
|
13
|
+
),
|
|
14
|
+
]);
|
|
8
15
|
|
|
9
16
|
/* Code derived from https://www.npmjs.com/package/is-color-stop Licensed under MIT license */
|
|
10
17
|
|
|
@@ -45,7 +52,10 @@ function isStop(str) {
|
|
|
45
52
|
const node = unit(str);
|
|
46
53
|
if (node) {
|
|
47
54
|
const number = Number(node.number);
|
|
48
|
-
if (
|
|
55
|
+
if (
|
|
56
|
+
number === 0 ||
|
|
57
|
+
(!Number.isNaN(number) && isCSSLengthUnit(node.unit))
|
|
58
|
+
) {
|
|
49
59
|
isColorStop = true;
|
|
50
60
|
}
|
|
51
61
|
} else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isColorStop.d.ts","sourceRoot":"","sources":["../src/isColorStop.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"isColorStop.d.ts","sourceRoot":"","sources":["../src/isColorStop.js"],"names":[],"mappings":";AAmEA;;;;GAIG;6BACmC,KAAK,EAJhC,MAIgC,EAAE,IAAI,AAH9C,CACA,EADQ,MAGsC,GAFrC,OAAO"}
|