@tbela99/css-parser 0.9.1 → 1.0.0
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/LICENSE.md +1 -1
- package/README.md +15 -8
- package/dist/index-umd-web.js +1815 -498
- package/dist/index.cjs +1816 -499
- package/dist/index.d.ts +46 -14
- package/dist/lib/ast/features/calc.js +7 -10
- package/dist/lib/ast/features/index.js +1 -0
- package/dist/lib/ast/features/inlinecssvariables.js +0 -5
- package/dist/lib/ast/features/prefix.js +2 -7
- package/dist/lib/ast/features/shorthand.js +6 -9
- package/dist/lib/ast/features/transform.js +60 -0
- package/dist/lib/ast/math/expression.js +14 -10
- package/dist/lib/ast/math/math.js +14 -2
- package/dist/lib/ast/minify.js +46 -5
- package/dist/lib/ast/transform/compute.js +336 -0
- package/dist/lib/ast/transform/convert.js +33 -0
- package/dist/lib/ast/transform/matrix.js +111 -0
- package/dist/lib/ast/transform/minify.js +296 -0
- package/dist/lib/ast/transform/perspective.js +10 -0
- package/dist/lib/ast/transform/rotate.js +40 -0
- package/dist/lib/ast/transform/scale.js +32 -0
- package/dist/lib/ast/transform/skew.js +23 -0
- package/dist/lib/ast/transform/translate.js +32 -0
- package/dist/lib/ast/transform/utils.js +198 -0
- package/dist/lib/ast/types.js +1 -0
- package/dist/lib/ast/walk.js +23 -17
- package/dist/lib/parser/parse.js +109 -88
- package/dist/lib/parser/utils/declaration.js +1 -1
- package/dist/lib/renderer/color/{colormix.js → color-mix.js} +6 -0
- package/dist/lib/renderer/color/color.js +94 -18
- package/dist/lib/renderer/color/hex.js +17 -7
- package/dist/lib/renderer/color/hsl.js +7 -2
- package/dist/lib/renderer/color/lab.js +8 -0
- package/dist/lib/renderer/color/lch.js +8 -0
- package/dist/lib/renderer/color/oklab.js +8 -0
- package/dist/lib/renderer/color/oklch.js +8 -0
- package/dist/lib/renderer/color/relativecolor.js +10 -21
- package/dist/lib/renderer/color/rgb.js +10 -7
- package/dist/lib/renderer/color/srgb.js +30 -6
- package/dist/lib/renderer/color/utils/components.js +13 -2
- package/dist/lib/renderer/render.js +67 -30
- package/dist/lib/syntax/syntax.js +74 -56
- package/dist/lib/validation/at-rules/container.js +6 -6
- package/dist/lib/validation/at-rules/document.js +1 -1
- package/dist/lib/validation/at-rules/keyframes.js +1 -1
- package/dist/lib/validation/at-rules/media.js +0 -1
- package/dist/lib/validation/atrule.js +0 -4
- package/dist/lib/validation/selector.js +5 -2
- package/dist/lib/validation/syntaxes/keyframe-block-list.js +2 -2
- package/dist/lib/validation/syntaxes/keyframe-selector.js +11 -90
- package/dist/lib/validation/syntaxes/relative-selector.js +15 -14
- package/dist/lib/validation/utils/list.js +18 -1
- package/dist/node/load.js +1 -1
- package/package.json +12 -12
- package/dist/lib/renderer/color/prophotoRgb.js +0 -56
- package/dist/lib/validation/declaration.js +0 -94
- package/dist/lib/validation/syntax.js +0 -1509
- package/dist/lib/validation/syntaxes/image.js +0 -29
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { multiply, identity, epsilon, decompose, round, toZero } from './utils.js';
|
|
2
|
+
import { EnumToken } from '../types.js';
|
|
3
|
+
import { computeMatrix } from './compute.js';
|
|
4
|
+
import { parseMatrix } from './matrix.js';
|
|
5
|
+
|
|
6
|
+
// translate → rotate → skew → scale
|
|
7
|
+
function minify(matrix) {
|
|
8
|
+
const decomposed = decompose(matrix);
|
|
9
|
+
if (decomposed == null) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const transforms = new Set(['translate', 'scale', 'skew', 'perspective', 'rotate']);
|
|
13
|
+
const scales = new Set(['x', 'y', 'z']);
|
|
14
|
+
const skew = new Set(['x', 'y']);
|
|
15
|
+
let result = [];
|
|
16
|
+
// check identity
|
|
17
|
+
if (round(decomposed.translate[0]) == 0 && round(decomposed.translate[1]) == 0 && round(decomposed.translate[2]) == 0) {
|
|
18
|
+
transforms.delete('translate');
|
|
19
|
+
}
|
|
20
|
+
if (round(decomposed.scale[0]) == 1 && round(decomposed.scale[1]) == 1 && round(decomposed.scale[2]) == 1) {
|
|
21
|
+
transforms.delete('scale');
|
|
22
|
+
}
|
|
23
|
+
if (round(decomposed.skew[0]) == 0 && round(decomposed.skew[1]) == 0) {
|
|
24
|
+
transforms.delete('skew');
|
|
25
|
+
}
|
|
26
|
+
if (round(decomposed.perspective[2]) == 0) {
|
|
27
|
+
transforms.delete('perspective');
|
|
28
|
+
}
|
|
29
|
+
if (round(decomposed.rotate[3]) == 0) {
|
|
30
|
+
transforms.delete('rotate');
|
|
31
|
+
}
|
|
32
|
+
if (transforms.has('translate')) {
|
|
33
|
+
let coordinates = new Set(['x', 'y', 'z']);
|
|
34
|
+
for (let i = 0; i < 3; i++) {
|
|
35
|
+
if (round(decomposed.translate[i]) == 0) {
|
|
36
|
+
coordinates.delete(i == 0 ? 'x' : i == 1 ? 'y' : 'z');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (coordinates.size == 3) {
|
|
40
|
+
result.push({
|
|
41
|
+
typ: EnumToken.FunctionTokenType,
|
|
42
|
+
val: 'translate3d',
|
|
43
|
+
chi: [
|
|
44
|
+
{ typ: EnumToken.LengthTokenType, val: round(decomposed.translate[0]) + '', unit: 'px' },
|
|
45
|
+
{ typ: EnumToken.CommaTokenType },
|
|
46
|
+
{ typ: EnumToken.LengthTokenType, val: round(decomposed.translate[1]) + '', unit: 'px' },
|
|
47
|
+
{ typ: EnumToken.CommaTokenType },
|
|
48
|
+
{ typ: EnumToken.LengthTokenType, val: round(decomposed.translate[2]) + '', unit: 'px' }
|
|
49
|
+
]
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
else if (coordinates.size == 1) {
|
|
53
|
+
if (coordinates.has('x')) {
|
|
54
|
+
result.push({
|
|
55
|
+
typ: EnumToken.FunctionTokenType,
|
|
56
|
+
val: 'translate',
|
|
57
|
+
chi: [{ typ: EnumToken.LengthTokenType, val: round(decomposed.translate[0]) + '', unit: 'px' }]
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
let axis = coordinates.has('y') ? 'y' : 'z';
|
|
62
|
+
let index = axis == 'y' ? 1 : 2;
|
|
63
|
+
result.push({
|
|
64
|
+
typ: EnumToken.FunctionTokenType,
|
|
65
|
+
val: 'translate' + axis.toUpperCase(),
|
|
66
|
+
chi: [{ typ: EnumToken.LengthTokenType, val: round(decomposed.translate[index]) + '', unit: 'px' }]
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else if (coordinates.has('z')) {
|
|
71
|
+
result.push({
|
|
72
|
+
typ: EnumToken.FunctionTokenType,
|
|
73
|
+
val: 'translate3d',
|
|
74
|
+
chi: [
|
|
75
|
+
decomposed.translate[0] == 0 ? {
|
|
76
|
+
typ: EnumToken.NumberTokenType,
|
|
77
|
+
'val': '0'
|
|
78
|
+
} : { typ: EnumToken.LengthTokenType, val: round(decomposed.translate[0]) + '', unit: 'px' },
|
|
79
|
+
{ typ: EnumToken.CommaTokenType },
|
|
80
|
+
decomposed.translate[1] == 0 ? {
|
|
81
|
+
typ: EnumToken.NumberTokenType,
|
|
82
|
+
'val': '0'
|
|
83
|
+
} : { typ: EnumToken.LengthTokenType, val: round(decomposed.translate[1]) + '', unit: 'px' },
|
|
84
|
+
{ typ: EnumToken.CommaTokenType },
|
|
85
|
+
{ typ: EnumToken.LengthTokenType, val: round(decomposed.translate[2]) + '', unit: 'px' }
|
|
86
|
+
]
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
result.push({
|
|
91
|
+
typ: EnumToken.FunctionTokenType,
|
|
92
|
+
val: 'translate',
|
|
93
|
+
chi: [
|
|
94
|
+
decomposed.translate[0] == 0 ? {
|
|
95
|
+
typ: EnumToken.NumberTokenType,
|
|
96
|
+
'val': '0'
|
|
97
|
+
} : { typ: EnumToken.LengthTokenType, val: round(decomposed.translate[0]) + '', unit: 'px' },
|
|
98
|
+
{ typ: EnumToken.CommaTokenType },
|
|
99
|
+
decomposed.translate[1] == 0 ? {
|
|
100
|
+
typ: EnumToken.NumberTokenType,
|
|
101
|
+
'val': '0'
|
|
102
|
+
} : { typ: EnumToken.LengthTokenType, val: round(decomposed.translate[1]) + '', unit: 'px' }
|
|
103
|
+
]
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (transforms.has('rotate')) {
|
|
108
|
+
const [x, y, z, angle] = decomposed.rotate;
|
|
109
|
+
if (y == 0 && z == 0) {
|
|
110
|
+
result.push({
|
|
111
|
+
typ: EnumToken.FunctionTokenType,
|
|
112
|
+
val: 'rotateX',
|
|
113
|
+
chi: [
|
|
114
|
+
{
|
|
115
|
+
typ: EnumToken.AngleTokenType,
|
|
116
|
+
val: '' + round(angle),
|
|
117
|
+
unit: 'deg'
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
else if (x == 0 && z == 0) {
|
|
123
|
+
result.push({
|
|
124
|
+
typ: EnumToken.FunctionTokenType,
|
|
125
|
+
val: 'rotateY',
|
|
126
|
+
chi: [
|
|
127
|
+
{
|
|
128
|
+
typ: EnumToken.AngleTokenType,
|
|
129
|
+
val: '' + round(angle),
|
|
130
|
+
unit: 'deg'
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
else if (x == 0 && y == 0) {
|
|
136
|
+
result.push({
|
|
137
|
+
typ: EnumToken.FunctionTokenType,
|
|
138
|
+
val: 'rotate',
|
|
139
|
+
chi: [
|
|
140
|
+
{
|
|
141
|
+
typ: EnumToken.AngleTokenType,
|
|
142
|
+
val: '' + round(angle),
|
|
143
|
+
unit: 'deg'
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
result.push({
|
|
150
|
+
typ: EnumToken.FunctionTokenType,
|
|
151
|
+
val: 'rotate3d',
|
|
152
|
+
chi: [
|
|
153
|
+
{
|
|
154
|
+
typ: EnumToken.NumberTokenType,
|
|
155
|
+
val: '' + round(x)
|
|
156
|
+
},
|
|
157
|
+
{ typ: EnumToken.CommaTokenType },
|
|
158
|
+
{
|
|
159
|
+
typ: EnumToken.NumberTokenType,
|
|
160
|
+
val: '' + round(y)
|
|
161
|
+
},
|
|
162
|
+
{ typ: EnumToken.CommaTokenType },
|
|
163
|
+
{
|
|
164
|
+
typ: EnumToken.NumberTokenType,
|
|
165
|
+
val: '' + round(z)
|
|
166
|
+
},
|
|
167
|
+
{ typ: EnumToken.CommaTokenType },
|
|
168
|
+
{
|
|
169
|
+
typ: EnumToken.AngleTokenType,
|
|
170
|
+
val: '' + round(angle),
|
|
171
|
+
unit: 'deg'
|
|
172
|
+
}
|
|
173
|
+
]
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (transforms.has('skew')) {
|
|
178
|
+
if (round(decomposed.skew[0]) == 0) {
|
|
179
|
+
skew.delete('x');
|
|
180
|
+
}
|
|
181
|
+
if (round(decomposed.skew[1]) == 0) {
|
|
182
|
+
skew.delete('y');
|
|
183
|
+
}
|
|
184
|
+
for (let i = 0; i < 2; i++) {
|
|
185
|
+
decomposed.skew[i] = round(Math.atan(decomposed.skew[i]) * 180 / Math.PI);
|
|
186
|
+
}
|
|
187
|
+
if (skew.size == 1) {
|
|
188
|
+
result.push({
|
|
189
|
+
typ: EnumToken.FunctionTokenType,
|
|
190
|
+
val: 'skew' + (skew.has('x') ? '' : 'Y'),
|
|
191
|
+
chi: [
|
|
192
|
+
{ typ: EnumToken.AngleTokenType, val: '' + round(decomposed.skew[0]), unit: 'deg' }
|
|
193
|
+
]
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
result.push({
|
|
198
|
+
typ: EnumToken.FunctionTokenType,
|
|
199
|
+
val: 'skew',
|
|
200
|
+
chi: [
|
|
201
|
+
{ typ: EnumToken.AngleTokenType, val: '' + round(decomposed.skew[0]), unit: 'deg' },
|
|
202
|
+
{ typ: EnumToken.CommaTokenType },
|
|
203
|
+
{ typ: EnumToken.AngleTokenType, val: '' + round(decomposed.skew[1]), unit: 'deg' }
|
|
204
|
+
]
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (transforms.has('scale')) {
|
|
209
|
+
const [sx, sy, sz] = toZero(decomposed.scale);
|
|
210
|
+
if (sz == 1) {
|
|
211
|
+
scales.delete('z');
|
|
212
|
+
}
|
|
213
|
+
if (sy == 1) {
|
|
214
|
+
scales.delete('y');
|
|
215
|
+
}
|
|
216
|
+
if (sx == 1) {
|
|
217
|
+
scales.delete('x');
|
|
218
|
+
}
|
|
219
|
+
if (scales.size == 1) {
|
|
220
|
+
let prefix = scales.has('x') ? '' : scales.has('y') ? 'Y' : 'Z';
|
|
221
|
+
result.push({
|
|
222
|
+
typ: EnumToken.FunctionTokenType,
|
|
223
|
+
val: 'scale' + prefix,
|
|
224
|
+
chi: [
|
|
225
|
+
{ typ: EnumToken.NumberTokenType, val: '' + round(prefix == 'Z' ? sz : prefix == 'Y' ? sy : sx) }
|
|
226
|
+
]
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
else if (!scales.has('z')) {
|
|
230
|
+
result.push({
|
|
231
|
+
typ: EnumToken.FunctionTokenType,
|
|
232
|
+
val: 'scale',
|
|
233
|
+
chi: [
|
|
234
|
+
{ typ: EnumToken.NumberTokenType, val: '' + round(sx) },
|
|
235
|
+
{ typ: EnumToken.CommaTokenType },
|
|
236
|
+
{ typ: EnumToken.NumberTokenType, val: '' + round(sy) },
|
|
237
|
+
]
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
result.push({
|
|
242
|
+
typ: EnumToken.FunctionTokenType,
|
|
243
|
+
val: 'scale3d',
|
|
244
|
+
chi: [
|
|
245
|
+
{ typ: EnumToken.NumberTokenType, val: '' + round(sx) },
|
|
246
|
+
{ typ: EnumToken.CommaTokenType },
|
|
247
|
+
{ typ: EnumToken.NumberTokenType, val: '' + round(sy) },
|
|
248
|
+
{ typ: EnumToken.CommaTokenType },
|
|
249
|
+
{ typ: EnumToken.NumberTokenType, val: '' + round(sz) }
|
|
250
|
+
]
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (transforms.has('perspective')) {
|
|
255
|
+
result.push({
|
|
256
|
+
typ: EnumToken.FunctionTokenType,
|
|
257
|
+
val: 'perspective',
|
|
258
|
+
chi: [
|
|
259
|
+
{ typ: EnumToken.Length, val: '' + round(1 / decomposed.perspective[2]), unit: 'px' },
|
|
260
|
+
]
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
// identity
|
|
264
|
+
return result.length == 0 || (result.length == 1 && eqMatrix(identity(), result)) ? [
|
|
265
|
+
{
|
|
266
|
+
typ: EnumToken.IdenTokenType,
|
|
267
|
+
val: 'none'
|
|
268
|
+
}
|
|
269
|
+
] : result;
|
|
270
|
+
}
|
|
271
|
+
function eqMatrix(a, b) {
|
|
272
|
+
let mat = identity();
|
|
273
|
+
let tmp = identity();
|
|
274
|
+
// @ts-ignore
|
|
275
|
+
const data = Array.isArray(a) ? a : parseMatrix(a);
|
|
276
|
+
for (const transform of b) {
|
|
277
|
+
tmp = computeMatrix([transform], identity());
|
|
278
|
+
if (tmp == null) {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
mat = multiply(mat, tmp);
|
|
282
|
+
}
|
|
283
|
+
if (mat == null) {
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
for (let i = 0; i < 4; i++) {
|
|
287
|
+
for (let j = 0; j < 4; j++) {
|
|
288
|
+
if (Math.abs(mat[i][j] - data[i][j]) > epsilon) {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return true;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export { eqMatrix, minify };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { identity, multiply } from './utils.js';
|
|
2
|
+
|
|
3
|
+
function perspective(x, from) {
|
|
4
|
+
const matrix = identity();
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
matrix[2][3] = typeof x == 'object' && x.val == 'none' ? 0 : x == 0 ? Number.NEGATIVE_INFINITY : -1 / x;
|
|
7
|
+
return multiply(from, matrix);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export { perspective };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { identity, multiply } from './utils.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* angle in radian
|
|
5
|
+
* @param angle
|
|
6
|
+
* @param x
|
|
7
|
+
* @param y
|
|
8
|
+
* @param z
|
|
9
|
+
* @param from
|
|
10
|
+
*/
|
|
11
|
+
function rotate3D(angle, x, y, z, from) {
|
|
12
|
+
const matrix = identity();
|
|
13
|
+
const sc = Math.sin(angle / 2) * Math.cos(angle / 2);
|
|
14
|
+
const sq = Math.sin(angle / 2) * Math.sin(angle / 2);
|
|
15
|
+
const norm = Math.sqrt(x * x + y * y + z * z);
|
|
16
|
+
const unit = norm === 0 ? 0 : 1 / norm;
|
|
17
|
+
x *= unit;
|
|
18
|
+
y *= unit;
|
|
19
|
+
z *= unit;
|
|
20
|
+
matrix[0][0] = 1 - 2 * (y * y + z * z) * sq;
|
|
21
|
+
matrix[0][1] = 2 * (x * y * sq + z * sc);
|
|
22
|
+
matrix[0][2] = 2 * (x * z * sq - y * sc);
|
|
23
|
+
matrix[1][0] = 2 * (x * y * sq - z * sc);
|
|
24
|
+
matrix[1][1] = 1 - 2 * (x * x + z * z) * sq;
|
|
25
|
+
matrix[1][2] = 2 * (y * z * sq + x * sc);
|
|
26
|
+
matrix[2][0] = 2 * (x * z * sq + y * sc);
|
|
27
|
+
matrix[2][1] = 2 * (y * z * sq - x * sc);
|
|
28
|
+
matrix[2][2] = 1 - 2 * (x * x + y * y) * sq;
|
|
29
|
+
return multiply(from, matrix);
|
|
30
|
+
}
|
|
31
|
+
function rotate(angle, from) {
|
|
32
|
+
const matrix = identity();
|
|
33
|
+
matrix[0][0] = Math.cos(angle);
|
|
34
|
+
matrix[0][1] = Math.sin(angle);
|
|
35
|
+
matrix[1][0] = -Math.sin(angle);
|
|
36
|
+
matrix[1][1] = Math.cos(angle);
|
|
37
|
+
return multiply(from, matrix);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export { rotate, rotate3D };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { identity, multiply } from './utils.js';
|
|
2
|
+
|
|
3
|
+
function scaleX(x, from) {
|
|
4
|
+
const matrix = identity();
|
|
5
|
+
matrix[0][0] = x;
|
|
6
|
+
return multiply(from, matrix);
|
|
7
|
+
}
|
|
8
|
+
function scaleY(y, from) {
|
|
9
|
+
const matrix = identity();
|
|
10
|
+
matrix[1][1] = y;
|
|
11
|
+
return multiply(from, matrix);
|
|
12
|
+
}
|
|
13
|
+
function scaleZ(z, from) {
|
|
14
|
+
const matrix = identity();
|
|
15
|
+
matrix[2][2] = z;
|
|
16
|
+
return multiply(from, matrix);
|
|
17
|
+
}
|
|
18
|
+
function scale(x, y, from) {
|
|
19
|
+
const matrix = identity();
|
|
20
|
+
matrix[0][0] = x;
|
|
21
|
+
matrix[1][1] = y;
|
|
22
|
+
return multiply(from, matrix);
|
|
23
|
+
}
|
|
24
|
+
function scale3d(x, y, z, from) {
|
|
25
|
+
const matrix = identity();
|
|
26
|
+
matrix[0][0] = x;
|
|
27
|
+
matrix[1][1] = y;
|
|
28
|
+
matrix[2][2] = z;
|
|
29
|
+
return multiply(from, matrix);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { scale, scale3d, scaleX, scaleY, scaleZ };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { identity, multiply } from './utils.js';
|
|
2
|
+
|
|
3
|
+
function skewX(x, from) {
|
|
4
|
+
const matrix = identity();
|
|
5
|
+
matrix[1][0] = Math.tan(x);
|
|
6
|
+
return multiply(from, matrix);
|
|
7
|
+
}
|
|
8
|
+
function skewY(y, from) {
|
|
9
|
+
const matrix = identity();
|
|
10
|
+
matrix[0][1] = Math.tan(y);
|
|
11
|
+
return multiply(from, matrix);
|
|
12
|
+
}
|
|
13
|
+
// convert angle to radian
|
|
14
|
+
function skew(values, from) {
|
|
15
|
+
const matrix = identity();
|
|
16
|
+
matrix[1][0] = Math.tan(values[0]);
|
|
17
|
+
if (values.length > 1) {
|
|
18
|
+
matrix[0][1] = Math.tan(values[1]);
|
|
19
|
+
}
|
|
20
|
+
return multiply(from, matrix);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { skew, skewX, skewY };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { identity, multiply } from './utils.js';
|
|
2
|
+
|
|
3
|
+
function translateX(x, from) {
|
|
4
|
+
const matrix = identity();
|
|
5
|
+
matrix[3][0] = x;
|
|
6
|
+
return multiply(from, matrix);
|
|
7
|
+
}
|
|
8
|
+
function translateY(y, from) {
|
|
9
|
+
const matrix = identity();
|
|
10
|
+
matrix[3][1] = y;
|
|
11
|
+
return multiply(from, matrix);
|
|
12
|
+
}
|
|
13
|
+
function translateZ(z, from) {
|
|
14
|
+
const matrix = identity();
|
|
15
|
+
matrix[3][2] = z;
|
|
16
|
+
return multiply(from, matrix);
|
|
17
|
+
}
|
|
18
|
+
function translate(translate, from) {
|
|
19
|
+
const matrix = identity();
|
|
20
|
+
matrix[3][0] = translate[0];
|
|
21
|
+
matrix[3][1] = translate[1] ?? 0;
|
|
22
|
+
return multiply(from, matrix);
|
|
23
|
+
}
|
|
24
|
+
function translate3d(translate, from) {
|
|
25
|
+
const matrix = identity();
|
|
26
|
+
matrix[3][0] = translate[0];
|
|
27
|
+
matrix[3][1] = translate[1];
|
|
28
|
+
matrix[3][2] = translate[2];
|
|
29
|
+
return multiply(from, matrix);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { translate, translate3d, translateX, translateY, translateZ };
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
const epsilon = 1e-5;
|
|
2
|
+
function identity() {
|
|
3
|
+
return [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]];
|
|
4
|
+
}
|
|
5
|
+
function pLength(point) {
|
|
6
|
+
// Calcul de la norme euclidienne
|
|
7
|
+
return Math.sqrt(point[0] * point[0] + point[1] * point[1] + point[2] * point[2]);
|
|
8
|
+
}
|
|
9
|
+
function normalize(point) {
|
|
10
|
+
const [x, y, z] = point;
|
|
11
|
+
const norm = Math.sqrt(point[0] * point[0] + point[1] * point[1] + point[2] * point[2]);
|
|
12
|
+
return norm === 0 ? [0, 0, 0] : [x / norm, y / norm, z / norm];
|
|
13
|
+
}
|
|
14
|
+
function dot(point1, point2) {
|
|
15
|
+
if (point1.length === 4 && point2.length === 4) {
|
|
16
|
+
return point1[0] * point2[0] + point1[1] * point2[1] + point1[2] * point2[2] + point1[3] * point2[3];
|
|
17
|
+
}
|
|
18
|
+
return point1[0] * point2[0] + point1[1] * point2[1] + point1[2] * point2[2];
|
|
19
|
+
}
|
|
20
|
+
function multiply(matrixA, matrixB) {
|
|
21
|
+
let result = Array(4).fill(0).map(() => Array(4).fill(0));
|
|
22
|
+
for (let i = 0; i < 4; i++) {
|
|
23
|
+
for (let j = 0; j < 4; j++) {
|
|
24
|
+
for (let k = 0; k < 4; k++) {
|
|
25
|
+
result[j][i] += matrixA[k][i] * matrixB[j][k];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
function round(number) {
|
|
32
|
+
return Math.abs(number) < epsilon ? 0 : +number.toPrecision(6);
|
|
33
|
+
}
|
|
34
|
+
// translate3d(25.9808px, 0, 15px ) rotateY(60deg) skewX(49.9999deg) scale(1, 1.2)
|
|
35
|
+
// translate → rotate → skew → scale
|
|
36
|
+
function decompose(original) {
|
|
37
|
+
const matrix = original.flat();
|
|
38
|
+
// Normalize last row
|
|
39
|
+
if (matrix[15] === 0) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
for (let i = 0; i < 16; i++)
|
|
43
|
+
matrix[i] /= matrix[15];
|
|
44
|
+
// Perspective extraction
|
|
45
|
+
const perspective = [0, 0, 0, 1];
|
|
46
|
+
if (matrix[3] !== 0 || matrix[7] !== 0 || matrix[11] !== 0) {
|
|
47
|
+
const rightHandSide = [matrix[3], matrix[7], matrix[11], matrix[15]];
|
|
48
|
+
const perspectiveMatrix = matrix.slice();
|
|
49
|
+
perspectiveMatrix[3] = 0;
|
|
50
|
+
perspectiveMatrix[7] = 0;
|
|
51
|
+
perspectiveMatrix[11] = 0;
|
|
52
|
+
perspectiveMatrix[15] = 1;
|
|
53
|
+
const inverse = invertMatrix4(perspectiveMatrix);
|
|
54
|
+
if (!inverse) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
const transposedInverse = transposeMatrix4(inverse);
|
|
58
|
+
perspective[0] = dot(rightHandSide, transposedInverse.slice(0, 4));
|
|
59
|
+
perspective[1] = dot(rightHandSide, transposedInverse.slice(4, 8));
|
|
60
|
+
perspective[2] = dot(rightHandSide, transposedInverse.slice(8, 12));
|
|
61
|
+
perspective[3] = dot(rightHandSide, transposedInverse.slice(12, 16));
|
|
62
|
+
// Clear perspective from matrix
|
|
63
|
+
matrix[3] = 0;
|
|
64
|
+
matrix[7] = 0;
|
|
65
|
+
matrix[11] = 0;
|
|
66
|
+
matrix[15] = 1;
|
|
67
|
+
}
|
|
68
|
+
// Translation
|
|
69
|
+
const translate = [matrix[12], matrix[13], matrix[14]];
|
|
70
|
+
matrix[12] = matrix[13] = matrix[14] = 0;
|
|
71
|
+
// Build the 3x3 matrix
|
|
72
|
+
const row0 = [matrix[0], matrix[1], matrix[2]];
|
|
73
|
+
const row1 = [matrix[4], matrix[5], matrix[6]];
|
|
74
|
+
const row2 = [matrix[8], matrix[9], matrix[10]];
|
|
75
|
+
// Compute scale
|
|
76
|
+
const scaleX = pLength(row0);
|
|
77
|
+
const row0Norm = normalize(row0);
|
|
78
|
+
const skewXY = dot(row0Norm, row1);
|
|
79
|
+
const row1Proj = [
|
|
80
|
+
row1[0] - skewXY * row0Norm[0],
|
|
81
|
+
row1[1] - skewXY * row0Norm[1],
|
|
82
|
+
row1[2] - skewXY * row0Norm[2]
|
|
83
|
+
];
|
|
84
|
+
const scaleY = pLength(row1Proj);
|
|
85
|
+
const row1Norm = normalize(row1Proj);
|
|
86
|
+
const skewXZ = dot(row0Norm, row2);
|
|
87
|
+
const skewYZ = dot(row1Norm, row2);
|
|
88
|
+
const row2Proj = [
|
|
89
|
+
row2[0] - skewXZ * row0Norm[0] - skewYZ * row1Norm[0],
|
|
90
|
+
row2[1] - skewXZ * row0Norm[1] - skewYZ * row1Norm[1],
|
|
91
|
+
row2[2] - skewXZ * row0Norm[2] - skewYZ * row1Norm[2]
|
|
92
|
+
];
|
|
93
|
+
const scaleZ = pLength(row2Proj);
|
|
94
|
+
const row2Norm = normalize(row2Proj);
|
|
95
|
+
// Build rotation matrix from orthonormalized vectors
|
|
96
|
+
const r00 = row0Norm[0], r01 = row1Norm[0], r02 = row2Norm[0];
|
|
97
|
+
const r10 = row0Norm[1], r11 = row1Norm[1], r12 = row2Norm[1];
|
|
98
|
+
const r20 = row0Norm[2], r21 = row1Norm[2], r22 = row2Norm[2];
|
|
99
|
+
// Convert to quaternion
|
|
100
|
+
const trace = r00 + r11 + r22;
|
|
101
|
+
let qw, qx, qy, qz;
|
|
102
|
+
if (trace > 0) {
|
|
103
|
+
const s = 0.5 / Math.sqrt(trace + 1.0);
|
|
104
|
+
qw = 0.25 / s;
|
|
105
|
+
qx = (r21 - r12) * s;
|
|
106
|
+
qy = (r02 - r20) * s;
|
|
107
|
+
qz = (r10 - r01) * s;
|
|
108
|
+
}
|
|
109
|
+
else if (r00 > r11 && r00 > r22) {
|
|
110
|
+
const s = 2.0 * Math.sqrt(1.0 + r00 - r11 - r22);
|
|
111
|
+
qw = (r21 - r12) / s;
|
|
112
|
+
qx = 0.25 * s;
|
|
113
|
+
qy = (r01 + r10) / s;
|
|
114
|
+
qz = (r02 + r20) / s;
|
|
115
|
+
}
|
|
116
|
+
else if (r11 > r22) {
|
|
117
|
+
const s = 2.0 * Math.sqrt(1.0 + r11 - r00 - r22);
|
|
118
|
+
qw = (r02 - r20) / s;
|
|
119
|
+
qx = (r01 + r10) / s;
|
|
120
|
+
qy = 0.25 * s;
|
|
121
|
+
qz = (r12 + r21) / s;
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
const s = 2.0 * Math.sqrt(1.0 + r22 - r00 - r11);
|
|
125
|
+
qw = (r10 - r01) / s;
|
|
126
|
+
qx = (r02 + r20) / s;
|
|
127
|
+
qy = (r12 + r21) / s;
|
|
128
|
+
qz = 0.25 * s;
|
|
129
|
+
}
|
|
130
|
+
[qx, qy, qz] = toZero([qx, qy, qz]);
|
|
131
|
+
// const q = gcd(qx, gcd(qy, qz));
|
|
132
|
+
let q = [Math.abs(qx), Math.abs(qy), Math.abs(qz)].reduce((acc, curr) => {
|
|
133
|
+
if (acc == 0 || (curr > 0 && curr < acc)) {
|
|
134
|
+
acc = curr;
|
|
135
|
+
}
|
|
136
|
+
return acc;
|
|
137
|
+
}, 0);
|
|
138
|
+
if (q > 0) {
|
|
139
|
+
qx /= q;
|
|
140
|
+
qy /= q;
|
|
141
|
+
qz /= q;
|
|
142
|
+
}
|
|
143
|
+
const rotate = [qx, qy, qz, Object.is(qw, 0) ? 0 : 2 * Math.acos(qw) * 180 / Math.PI];
|
|
144
|
+
const scale = [scaleX, scaleY, scaleZ];
|
|
145
|
+
const skew = [skewXY, skewXZ, skewYZ];
|
|
146
|
+
return {
|
|
147
|
+
translate,
|
|
148
|
+
scale,
|
|
149
|
+
rotate,
|
|
150
|
+
skew,
|
|
151
|
+
perspective
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function transposeMatrix4(m) {
|
|
155
|
+
return [
|
|
156
|
+
m[0], m[4], m[8], m[12],
|
|
157
|
+
m[1], m[5], m[9], m[13],
|
|
158
|
+
m[2], m[6], m[10], m[14],
|
|
159
|
+
m[3], m[7], m[11], m[15],
|
|
160
|
+
];
|
|
161
|
+
}
|
|
162
|
+
function invertMatrix4(m) {
|
|
163
|
+
new Array(16);
|
|
164
|
+
const det = m[0] * m[5] * m[10] * m[15] + m[0] * m[9] * m[14] * m[7] + m[0] * m[13] * m[6] * m[11]
|
|
165
|
+
- m[0] * m[13] * m[10] * m[7] - m[0] * m[9] * m[6] * m[15] - m[0] * m[5] * m[14] * m[11];
|
|
166
|
+
if (det === 0)
|
|
167
|
+
return null;
|
|
168
|
+
// For brevity, not implementing full inverse here — you'd normally use gl-matrix or similar.
|
|
169
|
+
// Just use a trusted library or expand this if needed.
|
|
170
|
+
return null; // placeholder
|
|
171
|
+
}
|
|
172
|
+
function toZero(v) {
|
|
173
|
+
for (let i = 0; i < v.length; i++) {
|
|
174
|
+
if (Math.abs(v[i]) <= epsilon) {
|
|
175
|
+
v[i] = 0;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
v[i] = +v[i].toPrecision(6);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return v;
|
|
182
|
+
}
|
|
183
|
+
// https://drafts.csswg.org/css-transforms-1/#2d-matrix
|
|
184
|
+
function is2DMatrix(matrix) {
|
|
185
|
+
// m13,m14, m23, m24, m31, m32, m34, m43 are all 0
|
|
186
|
+
return matrix[0][2] === 0 &&
|
|
187
|
+
matrix[0][3] === 0 &&
|
|
188
|
+
matrix[1][2] === 0 &&
|
|
189
|
+
matrix[1][3] === 0 &&
|
|
190
|
+
matrix[2][0] === 0 &&
|
|
191
|
+
matrix[2][1] === 0 &&
|
|
192
|
+
matrix[2][3] === 0 &&
|
|
193
|
+
matrix[3][2] === 0 &&
|
|
194
|
+
matrix[2][2] === 1 &&
|
|
195
|
+
matrix[3][3] === 1;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export { decompose, epsilon, identity, is2DMatrix, multiply, round, toZero };
|
package/dist/lib/ast/types.js
CHANGED
|
@@ -102,6 +102,7 @@ var EnumToken;
|
|
|
102
102
|
EnumToken[EnumToken["MediaFeatureOrTokenType"] = 90] = "MediaFeatureOrTokenType";
|
|
103
103
|
EnumToken[EnumToken["PseudoPageTokenType"] = 91] = "PseudoPageTokenType";
|
|
104
104
|
EnumToken[EnumToken["PseudoElementTokenType"] = 92] = "PseudoElementTokenType";
|
|
105
|
+
EnumToken[EnumToken["KeyframeAtRuleNodeType"] = 93] = "KeyframeAtRuleNodeType";
|
|
105
106
|
/* aliases */
|
|
106
107
|
EnumToken[EnumToken["Time"] = 25] = "Time";
|
|
107
108
|
EnumToken[EnumToken["Iden"] = 7] = "Iden";
|