@cssxjs/css-to-react-native 3.2.0-1 → 3.2.0-2
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/index.js +58 -39
- package/package.json +1 -1
- package/src/__tests__/textShadow.js +23 -0
- package/src/__tests__/varComplex.js +385 -0
- package/src/tokenTypes.js +2 -1
- package/src/transforms/animation.js +17 -15
- package/src/transforms/index.js +1 -1
- package/src/transforms/transform.js +15 -7
- package/src/transforms/transition.js +16 -14
- package/src/transforms/util.js +24 -2
package/index.js
CHANGED
|
@@ -32,7 +32,7 @@ var matchColor = function matchColor(node) {
|
|
|
32
32
|
return null;
|
|
33
33
|
};
|
|
34
34
|
var matchVariable = function matchVariable(node) {
|
|
35
|
-
if (node.type !== 'function'
|
|
35
|
+
if (node.type !== 'function' || node.value !== 'var' || node.nodes.length === 0) return null;
|
|
36
36
|
var variableName = node.nodes[0].value;
|
|
37
37
|
if (node.nodes.length === 1) {
|
|
38
38
|
return "var(" + variableName + ")";
|
|
@@ -169,7 +169,7 @@ var parseCommaSeparatedValues = function parseCommaSeparatedValues(tokenStream,
|
|
|
169
169
|
// Transform for animation-name property
|
|
170
170
|
var animationName = function animationName(tokenStream) {
|
|
171
171
|
var names = parseCommaSeparatedValues(tokenStream, function (ts) {
|
|
172
|
-
return ts.expect(IDENT, NONE);
|
|
172
|
+
return ts.expect(IDENT, NONE, VARIABLE);
|
|
173
173
|
});
|
|
174
174
|
return {
|
|
175
175
|
animationName: names
|
|
@@ -179,7 +179,7 @@ var animationName = function animationName(tokenStream) {
|
|
|
179
179
|
// Transform for animation-duration property
|
|
180
180
|
var animationDuration = function animationDuration(tokenStream) {
|
|
181
181
|
var durations = parseCommaSeparatedValues(tokenStream, function (ts) {
|
|
182
|
-
return ts.expect(TIME);
|
|
182
|
+
return ts.expect(TIME, VARIABLE);
|
|
183
183
|
});
|
|
184
184
|
return {
|
|
185
185
|
animationDuration: durations
|
|
@@ -216,7 +216,7 @@ var animationTimingFunction = function animationTimingFunction(tokenStream) {
|
|
|
216
216
|
// Transform for animation-delay property
|
|
217
217
|
var animationDelay = function animationDelay(tokenStream) {
|
|
218
218
|
var delays = parseCommaSeparatedValues(tokenStream, function (ts) {
|
|
219
|
-
return ts.expect(TIME);
|
|
219
|
+
return ts.expect(TIME, VARIABLE);
|
|
220
220
|
});
|
|
221
221
|
return {
|
|
222
222
|
animationDelay: delays
|
|
@@ -336,6 +336,17 @@ var animation = function animation(tokenStream) {
|
|
|
336
336
|
continue;
|
|
337
337
|
}
|
|
338
338
|
|
|
339
|
+
// Match time or variable (for duration/delay) - check before functions
|
|
340
|
+
if (tokenStream.matches(TIME) || tokenStream.matches(VARIABLE)) {
|
|
341
|
+
var value = tokenStream.lastValue;
|
|
342
|
+
if (duration === null) {
|
|
343
|
+
duration = value;
|
|
344
|
+
} else {
|
|
345
|
+
delay = value;
|
|
346
|
+
}
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
|
|
339
350
|
// Check for timing function (cubic-bezier or steps)
|
|
340
351
|
var funcStream = tokenStream.matchesFunction();
|
|
341
352
|
if (funcStream) {
|
|
@@ -361,17 +372,6 @@ var animation = function animation(tokenStream) {
|
|
|
361
372
|
continue;
|
|
362
373
|
}
|
|
363
374
|
|
|
364
|
-
// Match time
|
|
365
|
-
if (tokenStream.matches(TIME)) {
|
|
366
|
-
var value = tokenStream.lastValue;
|
|
367
|
-
if (duration === null) {
|
|
368
|
-
duration = value;
|
|
369
|
-
} else {
|
|
370
|
-
delay = value;
|
|
371
|
-
}
|
|
372
|
-
continue;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
375
|
// Match identifier
|
|
376
376
|
if (tokenStream.matches(IDENT)) {
|
|
377
377
|
var _value = tokenStream.lastValue;
|
|
@@ -727,7 +727,7 @@ var textDecorationLine = function textDecorationLine(tokenStream) {
|
|
|
727
727
|
};
|
|
728
728
|
var directionFactory = function directionFactory(_ref) {
|
|
729
729
|
var _ref$types = _ref.types,
|
|
730
|
-
types = _ref$types === void 0 ? [LENGTH, UNSUPPORTED_LENGTH_UNIT, PERCENT] : _ref$types,
|
|
730
|
+
types = _ref$types === void 0 ? [LENGTH, UNSUPPORTED_LENGTH_UNIT, PERCENT, VARIABLE] : _ref$types,
|
|
731
731
|
_ref$directions = _ref.directions,
|
|
732
732
|
directions = _ref$directions === void 0 ? ['Top', 'Right', 'Bottom', 'Left'] : _ref$directions,
|
|
733
733
|
_ref$prefix = _ref.prefix,
|
|
@@ -787,15 +787,33 @@ var parseShadow = function parseShadow(tokenStream) {
|
|
|
787
787
|
while (tokenStream.hasTokens()) {
|
|
788
788
|
if (didParseFirst) tokenStream.expect(SPACE);
|
|
789
789
|
if (offsetX === undefined && tokenStream.matches(LENGTH, UNSUPPORTED_LENGTH_UNIT)) {
|
|
790
|
+
// First offset must be a concrete LENGTH to distinguish from color
|
|
790
791
|
offsetX = tokenStream.lastValue;
|
|
791
792
|
tokenStream.expect(SPACE);
|
|
792
|
-
|
|
793
|
+
// Second offset and radius can be VARIABLE
|
|
794
|
+
offsetY = tokenStream.expect(LENGTH, UNSUPPORTED_LENGTH_UNIT, VARIABLE);
|
|
795
|
+
|
|
796
|
+
// Try to match optional blur-radius (concrete LENGTH only here)
|
|
793
797
|
tokenStream.saveRewindPoint();
|
|
794
798
|
if (tokenStream.matches(SPACE) && tokenStream.matches(LENGTH, UNSUPPORTED_LENGTH_UNIT)) {
|
|
795
799
|
radius = tokenStream.lastValue;
|
|
796
800
|
} else {
|
|
797
801
|
tokenStream.rewind();
|
|
798
802
|
}
|
|
803
|
+
} else if (offsetX !== undefined && radius === undefined && color === undefined && tokenStream.matches(VARIABLE)) {
|
|
804
|
+
// VARIABLE after offsets - could be radius or color
|
|
805
|
+
// Peek ahead to determine which
|
|
806
|
+
var potentialValue = tokenStream.lastValue;
|
|
807
|
+
tokenStream.saveRewindPoint();
|
|
808
|
+
if (tokenStream.matches(SPACE) && tokenStream.hasTokens()) {
|
|
809
|
+
// There's more content - this VARIABLE is the radius
|
|
810
|
+
tokenStream.rewind();
|
|
811
|
+
radius = potentialValue;
|
|
812
|
+
} else {
|
|
813
|
+
// No more content - this VARIABLE is the color
|
|
814
|
+
tokenStream.rewind();
|
|
815
|
+
color = potentialValue;
|
|
816
|
+
}
|
|
799
817
|
} else if (color === undefined && (tokenStream.matches(COLOR) || tokenStream.matches(VARIABLE))) {
|
|
800
818
|
color = tokenStream.lastValue;
|
|
801
819
|
} else {
|
|
@@ -831,9 +849,9 @@ var oneOfTypes = function oneOfTypes(tokenTypes) {
|
|
|
831
849
|
return value;
|
|
832
850
|
};
|
|
833
851
|
};
|
|
834
|
-
var singleNumber = oneOfTypes([NUMBER]);
|
|
835
|
-
var singleLengthOrPercent = oneOfTypes([LENGTH, PERCENT]);
|
|
836
|
-
var singleAngle = oneOfTypes([ANGLE]);
|
|
852
|
+
var singleNumber = oneOfTypes([NUMBER, VARIABLE]);
|
|
853
|
+
var singleLengthOrPercent = oneOfTypes([LENGTH, PERCENT, VARIABLE]);
|
|
854
|
+
var singleAngle = oneOfTypes([ANGLE, VARIABLE]);
|
|
837
855
|
var xyTransformFactory = function xyTransformFactory(tokenTypes) {
|
|
838
856
|
return function (key, valueIfOmitted) {
|
|
839
857
|
return function (functionStream) {
|
|
@@ -855,9 +873,9 @@ var xyTransformFactory = function xyTransformFactory(tokenTypes) {
|
|
|
855
873
|
};
|
|
856
874
|
};
|
|
857
875
|
};
|
|
858
|
-
var xyNumber = xyTransformFactory([NUMBER]);
|
|
859
|
-
var xyLengthOrPercent = xyTransformFactory([LENGTH, PERCENT]);
|
|
860
|
-
var xyAngle = xyTransformFactory([ANGLE]);
|
|
876
|
+
var xyNumber = xyTransformFactory([NUMBER, VARIABLE]);
|
|
877
|
+
var xyLengthOrPercent = xyTransformFactory([LENGTH, PERCENT, VARIABLE]);
|
|
878
|
+
var xyAngle = xyTransformFactory([ANGLE, VARIABLE]);
|
|
861
879
|
var partTransforms = {
|
|
862
880
|
perspective: singleNumber,
|
|
863
881
|
scale: xyNumber('scale'),
|
|
@@ -944,7 +962,7 @@ var transitionProperty = function transitionProperty(tokenStream) {
|
|
|
944
962
|
// Transform for transition-duration
|
|
945
963
|
var transitionDuration = function transitionDuration(tokenStream) {
|
|
946
964
|
var durations = parseCommaSeparatedValues$1(tokenStream, function (ts) {
|
|
947
|
-
return ts.expect(TIME);
|
|
965
|
+
return ts.expect(TIME, VARIABLE);
|
|
948
966
|
});
|
|
949
967
|
return {
|
|
950
968
|
transitionDuration: durations
|
|
@@ -981,7 +999,7 @@ var transitionTimingFunction = function transitionTimingFunction(tokenStream) {
|
|
|
981
999
|
// Transform for transition-delay
|
|
982
1000
|
var transitionDelay = function transitionDelay(tokenStream) {
|
|
983
1001
|
var delays = parseCommaSeparatedValues$1(tokenStream, function (ts) {
|
|
984
|
-
return ts.expect(TIME);
|
|
1002
|
+
return ts.expect(TIME, VARIABLE);
|
|
985
1003
|
});
|
|
986
1004
|
return {
|
|
987
1005
|
transitionDelay: delays
|
|
@@ -1039,10 +1057,20 @@ var transition = function transition(tokenStream) {
|
|
|
1039
1057
|
continue;
|
|
1040
1058
|
}
|
|
1041
1059
|
|
|
1060
|
+
// Match time or variable (for duration/delay) - check before functions
|
|
1061
|
+
if (tokenStream.matches(TIME) || tokenStream.matches(VARIABLE)) {
|
|
1062
|
+
var value = tokenStream.lastValue;
|
|
1063
|
+
if (duration === null) {
|
|
1064
|
+
duration = value;
|
|
1065
|
+
} else {
|
|
1066
|
+
delay = value;
|
|
1067
|
+
}
|
|
1068
|
+
continue;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1042
1071
|
// Check for timing function (cubic-bezier or steps)
|
|
1043
1072
|
var funcStream = tokenStream.matchesFunction();
|
|
1044
1073
|
if (funcStream) {
|
|
1045
|
-
// It's a function like cubic-bezier() or steps()
|
|
1046
1074
|
var funcName = funcStream.functionName;
|
|
1047
1075
|
var args = [];
|
|
1048
1076
|
while (funcStream.hasTokens()) {
|
|
@@ -1061,20 +1089,11 @@ var transition = function transition(tokenStream) {
|
|
|
1061
1089
|
|
|
1062
1090
|
// Match word or time
|
|
1063
1091
|
if (tokenStream.matches(IDENT)) {
|
|
1064
|
-
var value = tokenStream.lastValue;
|
|
1065
|
-
if (isTimingFunction$1(value)) {
|
|
1066
|
-
timingFunction = value;
|
|
1067
|
-
} else {
|
|
1068
|
-
property = value;
|
|
1069
|
-
}
|
|
1070
|
-
continue;
|
|
1071
|
-
}
|
|
1072
|
-
if (tokenStream.matches(TIME)) {
|
|
1073
1092
|
var _value2 = tokenStream.lastValue;
|
|
1074
|
-
if (
|
|
1075
|
-
|
|
1093
|
+
if (isTimingFunction$1(_value2)) {
|
|
1094
|
+
timingFunction = _value2;
|
|
1076
1095
|
} else {
|
|
1077
|
-
|
|
1096
|
+
property = _value2;
|
|
1078
1097
|
}
|
|
1079
1098
|
continue;
|
|
1080
1099
|
}
|
|
@@ -1135,7 +1154,7 @@ var borderWidth = directionFactory({
|
|
|
1135
1154
|
suffix: 'Width'
|
|
1136
1155
|
});
|
|
1137
1156
|
var margin = directionFactory({
|
|
1138
|
-
types: [LENGTH, UNSUPPORTED_LENGTH_UNIT, PERCENT, AUTO],
|
|
1157
|
+
types: [LENGTH, UNSUPPORTED_LENGTH_UNIT, PERCENT, AUTO, VARIABLE],
|
|
1139
1158
|
prefix: 'margin'
|
|
1140
1159
|
});
|
|
1141
1160
|
var padding = directionFactory({
|
package/package.json
CHANGED
|
@@ -105,3 +105,26 @@ it('textShadow with var() color before offset', () => {
|
|
|
105
105
|
textShadowColor: 'var(--primary-color)',
|
|
106
106
|
})
|
|
107
107
|
})
|
|
108
|
+
|
|
109
|
+
// Note: var() for offset-x is not supported because it's ambiguous with color-first syntax
|
|
110
|
+
// e.g., 'var(--x) 20px red' could be interpreted as color=var(--x), offsets=20px red (invalid)
|
|
111
|
+
// To use var() for offsets, offset-x must be a concrete value like '10px var(--y) red'
|
|
112
|
+
|
|
113
|
+
it('textShadow with var() for offset-y', () => {
|
|
114
|
+
expect(transformCss([['text-shadow', '10px var(--y) red']])).toEqual({
|
|
115
|
+
textShadowOffset: { width: 10, height: 'var(--y)' },
|
|
116
|
+
textShadowRadius: 0,
|
|
117
|
+
textShadowColor: 'red',
|
|
118
|
+
})
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('textShadow with var() for blur-radius', () => {
|
|
122
|
+
expect(transformCss([['text-shadow', '10px 20px var(--blur) red']])).toEqual({
|
|
123
|
+
textShadowOffset: { width: 10, height: 20 },
|
|
124
|
+
textShadowRadius: 'var(--blur)',
|
|
125
|
+
textShadowColor: 'red',
|
|
126
|
+
})
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
// Note: 'var(--x) var(--y) var(--blur) var(--color)' is not supported
|
|
130
|
+
// because offset-x must be a concrete value to distinguish from color-first syntax
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import transformCss from '..'
|
|
2
|
+
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Transform functions with var()
|
|
5
|
+
// =============================================================================
|
|
6
|
+
|
|
7
|
+
describe('transform with var()', () => {
|
|
8
|
+
it('transforms translateX with var()', () => {
|
|
9
|
+
expect(transformCss([['transform', 'translateX(var(--x))']])).toEqual({
|
|
10
|
+
transform: [{ translateX: 'var(--x)' }],
|
|
11
|
+
})
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('transforms translateX with var() and fallback', () => {
|
|
15
|
+
expect(transformCss([['transform', 'translateX(var(--x, 10px))']])).toEqual({
|
|
16
|
+
transform: [{ translateX: 'var(--x, 10px)' }],
|
|
17
|
+
})
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('transforms multiple transform functions with var()', () => {
|
|
21
|
+
expect(
|
|
22
|
+
transformCss([
|
|
23
|
+
['transform', 'translateX(var(--x, 10px)) translateY(var(--y, 20px))'],
|
|
24
|
+
])
|
|
25
|
+
).toEqual({
|
|
26
|
+
transform: [
|
|
27
|
+
{ translateY: 'var(--y, 20px)' },
|
|
28
|
+
{ translateX: 'var(--x, 10px)' },
|
|
29
|
+
],
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('transforms rotate with var()', () => {
|
|
34
|
+
expect(transformCss([['transform', 'rotate(var(--angle, 45deg))']])).toEqual(
|
|
35
|
+
{
|
|
36
|
+
transform: [{ rotate: 'var(--angle, 45deg)' }],
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('transforms scale with var()', () => {
|
|
42
|
+
expect(transformCss([['transform', 'scale(var(--scale, 1.5))']])).toEqual({
|
|
43
|
+
transform: [{ scale: 'var(--scale, 1.5)' }],
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('transforms mixed concrete and var() values', () => {
|
|
48
|
+
expect(
|
|
49
|
+
transformCss([['transform', 'translateX(10px) rotate(var(--angle))']])
|
|
50
|
+
).toEqual({
|
|
51
|
+
transform: [{ rotate: 'var(--angle)' }, { translateX: 10 }],
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('transforms translate with two var() args', () => {
|
|
56
|
+
expect(
|
|
57
|
+
transformCss([['transform', 'translate(var(--x, 10px), var(--y, 20px))']])
|
|
58
|
+
).toEqual({
|
|
59
|
+
transform: [
|
|
60
|
+
{ translateY: 'var(--y, 20px)' },
|
|
61
|
+
{ translateX: 'var(--x, 10px)' },
|
|
62
|
+
],
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('transforms scale with two var() args', () => {
|
|
67
|
+
expect(
|
|
68
|
+
transformCss([['transform', 'scale(var(--sx, 1), var(--sy, 2))']])
|
|
69
|
+
).toEqual({
|
|
70
|
+
transform: [{ scaleY: 'var(--sy, 2)' }, { scaleX: 'var(--sx, 1)' }],
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('transforms skew with var()', () => {
|
|
75
|
+
expect(
|
|
76
|
+
transformCss([['transform', 'skew(var(--skew-x, 10deg), var(--skew-y, 5deg))']])
|
|
77
|
+
).toEqual({
|
|
78
|
+
transform: [
|
|
79
|
+
{ skewY: 'var(--skew-y, 5deg)' },
|
|
80
|
+
{ skewX: 'var(--skew-x, 10deg)' },
|
|
81
|
+
],
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
// =============================================================================
|
|
87
|
+
// Box-shadow with multiple var() values and comma-separated shadows
|
|
88
|
+
// =============================================================================
|
|
89
|
+
|
|
90
|
+
describe('box-shadow with complex var()', () => {
|
|
91
|
+
it('transforms box-shadow with var() for offset-x', () => {
|
|
92
|
+
expect(
|
|
93
|
+
transformCss([['box-shadow', 'var(--x) 10px 5px red']])
|
|
94
|
+
).toEqual({
|
|
95
|
+
boxShadow: 'var(--x) 10px 5px red',
|
|
96
|
+
})
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('transforms box-shadow with var() for offset-y', () => {
|
|
100
|
+
expect(
|
|
101
|
+
transformCss([['box-shadow', '10px var(--y) 5px red']])
|
|
102
|
+
).toEqual({
|
|
103
|
+
boxShadow: '10px var(--y) 5px red',
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('transforms box-shadow with var() for blur', () => {
|
|
108
|
+
expect(
|
|
109
|
+
transformCss([['box-shadow', '10px 20px var(--blur) red']])
|
|
110
|
+
).toEqual({
|
|
111
|
+
boxShadow: '10px 20px var(--blur) red',
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('transforms box-shadow with multiple var() values', () => {
|
|
116
|
+
expect(
|
|
117
|
+
transformCss([['box-shadow', 'var(--x) var(--y) var(--blur) var(--color)']])
|
|
118
|
+
).toEqual({
|
|
119
|
+
boxShadow: 'var(--x) var(--y) var(--blur) var(--color)',
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('transforms multiple box-shadows with var()', () => {
|
|
124
|
+
expect(
|
|
125
|
+
transformCss([
|
|
126
|
+
[
|
|
127
|
+
'box-shadow',
|
|
128
|
+
'var(--x) var(--y) var(--color, rgba(0, 0, 0, 0.2)), var(--x-2) var(--y-2) var(--color-2, rgba(0, 0, 0, 0.5))',
|
|
129
|
+
],
|
|
130
|
+
])
|
|
131
|
+
).toEqual({
|
|
132
|
+
boxShadow:
|
|
133
|
+
'var(--x) var(--y) var(--color, rgba(0, 0, 0, 0.2)), var(--x-2) var(--y-2) var(--color-2, rgba(0, 0, 0, 0.5))',
|
|
134
|
+
})
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('transforms multiple box-shadows with mixed concrete and var() values', () => {
|
|
138
|
+
expect(
|
|
139
|
+
transformCss([
|
|
140
|
+
['box-shadow', '10px 20px red, var(--x-2) var(--y-2) blue'],
|
|
141
|
+
])
|
|
142
|
+
).toEqual({
|
|
143
|
+
boxShadow: '10px 20px red, var(--x-2) var(--y-2) blue',
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
it('transforms box-shadow with var() having rgba fallback', () => {
|
|
148
|
+
expect(
|
|
149
|
+
transformCss([
|
|
150
|
+
['box-shadow', '10px 20px var(--blur, 5px) var(--color, rgba(0, 0, 0, 0.2))'],
|
|
151
|
+
])
|
|
152
|
+
).toEqual({
|
|
153
|
+
boxShadow: '10px 20px var(--blur, 5px) var(--color, rgba(0, 0, 0, 0.2))',
|
|
154
|
+
})
|
|
155
|
+
})
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
// =============================================================================
|
|
159
|
+
// Shorthand properties with multiple var() values
|
|
160
|
+
// =============================================================================
|
|
161
|
+
|
|
162
|
+
describe('shorthand properties with var()', () => {
|
|
163
|
+
it('transforms padding with multiple var() values', () => {
|
|
164
|
+
expect(
|
|
165
|
+
transformCss([
|
|
166
|
+
['padding', 'var(--top) var(--right) var(--bottom) var(--left)'],
|
|
167
|
+
])
|
|
168
|
+
).toEqual({
|
|
169
|
+
paddingTop: 'var(--top)',
|
|
170
|
+
paddingRight: 'var(--right)',
|
|
171
|
+
paddingBottom: 'var(--bottom)',
|
|
172
|
+
paddingLeft: 'var(--left)',
|
|
173
|
+
})
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
it('transforms padding with var() and fallbacks', () => {
|
|
177
|
+
expect(
|
|
178
|
+
transformCss([
|
|
179
|
+
['padding', 'var(--top, 10px) var(--right, 20px) var(--bottom, 10px) var(--left, 20px)'],
|
|
180
|
+
])
|
|
181
|
+
).toEqual({
|
|
182
|
+
paddingTop: 'var(--top, 10px)',
|
|
183
|
+
paddingRight: 'var(--right, 20px)',
|
|
184
|
+
paddingBottom: 'var(--bottom, 10px)',
|
|
185
|
+
paddingLeft: 'var(--left, 20px)',
|
|
186
|
+
})
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
it('transforms padding with two var() values', () => {
|
|
190
|
+
expect(
|
|
191
|
+
transformCss([['padding', 'var(--vertical) var(--horizontal)']])
|
|
192
|
+
).toEqual({
|
|
193
|
+
paddingTop: 'var(--vertical)',
|
|
194
|
+
paddingRight: 'var(--horizontal)',
|
|
195
|
+
paddingBottom: 'var(--vertical)',
|
|
196
|
+
paddingLeft: 'var(--horizontal)',
|
|
197
|
+
})
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
it('transforms margin with multiple var() values', () => {
|
|
201
|
+
expect(
|
|
202
|
+
transformCss([
|
|
203
|
+
['margin', 'var(--top) var(--right) var(--bottom) var(--left)'],
|
|
204
|
+
])
|
|
205
|
+
).toEqual({
|
|
206
|
+
marginTop: 'var(--top)',
|
|
207
|
+
marginRight: 'var(--right)',
|
|
208
|
+
marginBottom: 'var(--bottom)',
|
|
209
|
+
marginLeft: 'var(--left)',
|
|
210
|
+
})
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
it('transforms margin with mixed concrete and var() values', () => {
|
|
214
|
+
expect(
|
|
215
|
+
transformCss([['margin', '10px var(--horizontal) 20px']])
|
|
216
|
+
).toEqual({
|
|
217
|
+
marginTop: 10,
|
|
218
|
+
marginRight: 'var(--horizontal)',
|
|
219
|
+
marginBottom: 20,
|
|
220
|
+
marginLeft: 'var(--horizontal)',
|
|
221
|
+
})
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
it('transforms border-radius with multiple var() values', () => {
|
|
225
|
+
expect(
|
|
226
|
+
transformCss([
|
|
227
|
+
['border-radius', 'var(--tl) var(--tr) var(--br) var(--bl)'],
|
|
228
|
+
])
|
|
229
|
+
).toEqual({
|
|
230
|
+
borderTopLeftRadius: 'var(--tl)',
|
|
231
|
+
borderTopRightRadius: 'var(--tr)',
|
|
232
|
+
borderBottomRightRadius: 'var(--br)',
|
|
233
|
+
borderBottomLeftRadius: 'var(--bl)',
|
|
234
|
+
})
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
it('transforms border-width with multiple var() values', () => {
|
|
238
|
+
expect(
|
|
239
|
+
transformCss([
|
|
240
|
+
['border-width', 'var(--top) var(--right) var(--bottom) var(--left)'],
|
|
241
|
+
])
|
|
242
|
+
).toEqual({
|
|
243
|
+
borderTopWidth: 'var(--top)',
|
|
244
|
+
borderRightWidth: 'var(--right)',
|
|
245
|
+
borderBottomWidth: 'var(--bottom)',
|
|
246
|
+
borderLeftWidth: 'var(--left)',
|
|
247
|
+
})
|
|
248
|
+
})
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
// =============================================================================
|
|
252
|
+
// Animation with var()
|
|
253
|
+
// =============================================================================
|
|
254
|
+
|
|
255
|
+
describe('animation with var()', () => {
|
|
256
|
+
it('transforms animation-duration with var()', () => {
|
|
257
|
+
expect(
|
|
258
|
+
transformCss([['animation-duration', 'var(--duration, 300ms)']])
|
|
259
|
+
).toEqual({
|
|
260
|
+
animationDuration: 'var(--duration, 300ms)',
|
|
261
|
+
})
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
it('transforms animation-delay with var()', () => {
|
|
265
|
+
expect(
|
|
266
|
+
transformCss([['animation-delay', 'var(--delay, 100ms)']])
|
|
267
|
+
).toEqual({
|
|
268
|
+
animationDelay: 'var(--delay, 100ms)',
|
|
269
|
+
})
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
it('transforms animation-name with var()', () => {
|
|
273
|
+
expect(transformCss([['animation-name', 'var(--animation)']])).toEqual({
|
|
274
|
+
animationName: 'var(--animation)',
|
|
275
|
+
})
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
it('transforms animation shorthand with var() for duration', () => {
|
|
279
|
+
expect(
|
|
280
|
+
transformCss([['animation', 'fadeIn var(--duration, 300ms) ease']])
|
|
281
|
+
).toEqual({
|
|
282
|
+
animationName: 'fadeIn',
|
|
283
|
+
animationDuration: 'var(--duration, 300ms)',
|
|
284
|
+
animationTimingFunction: 'ease',
|
|
285
|
+
animationDelay: '0s',
|
|
286
|
+
animationIterationCount: 1,
|
|
287
|
+
animationDirection: 'normal',
|
|
288
|
+
animationFillMode: 'none',
|
|
289
|
+
animationPlayState: 'running',
|
|
290
|
+
})
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
it('transforms multiple animation values with var()', () => {
|
|
294
|
+
expect(
|
|
295
|
+
transformCss([
|
|
296
|
+
['animation-duration', 'var(--dur1), var(--dur2)'],
|
|
297
|
+
])
|
|
298
|
+
).toEqual({
|
|
299
|
+
animationDuration: ['var(--dur1)', 'var(--dur2)'],
|
|
300
|
+
})
|
|
301
|
+
})
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
// =============================================================================
|
|
305
|
+
// Transition with var()
|
|
306
|
+
// =============================================================================
|
|
307
|
+
|
|
308
|
+
describe('transition with var()', () => {
|
|
309
|
+
it('transforms transition-duration with var()', () => {
|
|
310
|
+
expect(
|
|
311
|
+
transformCss([['transition-duration', 'var(--duration, 300ms)']])
|
|
312
|
+
).toEqual({
|
|
313
|
+
transitionDuration: 'var(--duration, 300ms)',
|
|
314
|
+
})
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
it('transforms transition-delay with var()', () => {
|
|
318
|
+
expect(
|
|
319
|
+
transformCss([['transition-delay', 'var(--delay, 100ms)']])
|
|
320
|
+
).toEqual({
|
|
321
|
+
transitionDelay: 'var(--delay, 100ms)',
|
|
322
|
+
})
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
it('transforms transition shorthand with var() for duration', () => {
|
|
326
|
+
expect(
|
|
327
|
+
transformCss([['transition', 'opacity var(--duration, 300ms) ease']])
|
|
328
|
+
).toEqual({
|
|
329
|
+
transitionProperty: 'opacity',
|
|
330
|
+
transitionDuration: 'var(--duration, 300ms)',
|
|
331
|
+
transitionTimingFunction: 'ease',
|
|
332
|
+
transitionDelay: '0s',
|
|
333
|
+
})
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
it('transforms multiple transition values with var()', () => {
|
|
337
|
+
expect(
|
|
338
|
+
transformCss([['transition-duration', 'var(--dur1), var(--dur2)']])
|
|
339
|
+
).toEqual({
|
|
340
|
+
transitionDuration: ['var(--dur1)', 'var(--dur2)'],
|
|
341
|
+
})
|
|
342
|
+
})
|
|
343
|
+
|
|
344
|
+
it('transforms transition with var() for delay', () => {
|
|
345
|
+
expect(
|
|
346
|
+
transformCss([['transition', 'opacity 300ms ease var(--delay)']])
|
|
347
|
+
).toEqual({
|
|
348
|
+
transitionProperty: 'opacity',
|
|
349
|
+
transitionDuration: '300ms',
|
|
350
|
+
transitionTimingFunction: 'ease',
|
|
351
|
+
transitionDelay: 'var(--delay)',
|
|
352
|
+
})
|
|
353
|
+
})
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
// =============================================================================
|
|
357
|
+
// Edge cases with var() fallbacks containing commas
|
|
358
|
+
// =============================================================================
|
|
359
|
+
|
|
360
|
+
describe('var() with complex fallbacks', () => {
|
|
361
|
+
it('handles var() with rgba fallback containing commas', () => {
|
|
362
|
+
expect(
|
|
363
|
+
transformCss([['color', 'var(--color, rgba(100, 100, 100, 0.5))']])
|
|
364
|
+
).toEqual({
|
|
365
|
+
color: 'var(--color, rgba(100, 100, 100, 0.5))',
|
|
366
|
+
})
|
|
367
|
+
})
|
|
368
|
+
|
|
369
|
+
it('handles var() with rgb fallback containing commas', () => {
|
|
370
|
+
expect(
|
|
371
|
+
transformCss([['color', 'var(--color, rgb(100, 100, 100))']])
|
|
372
|
+
).toEqual({
|
|
373
|
+
color: 'var(--color, rgb(100, 100, 100))',
|
|
374
|
+
})
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
it('handles nested var() fallbacks', () => {
|
|
378
|
+
// This might not work but let's test it
|
|
379
|
+
expect(
|
|
380
|
+
transformCss([['color', 'var(--primary, var(--fallback, red))']])
|
|
381
|
+
).toEqual({
|
|
382
|
+
color: 'var(--primary, var(--fallback, red))',
|
|
383
|
+
})
|
|
384
|
+
})
|
|
385
|
+
})
|
package/src/tokenTypes.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SPACE, COMMA, IDENT, TIME, NUMBER, NONE } from '../tokenTypes'
|
|
1
|
+
import { SPACE, COMMA, IDENT, TIME, NUMBER, NONE, VARIABLE } from '../tokenTypes'
|
|
2
2
|
|
|
3
3
|
// Timing function keywords
|
|
4
4
|
const timingFunctionKeywords = [
|
|
@@ -67,7 +67,7 @@ const parseCommaSeparatedValues = (tokenStream, parseValue) => {
|
|
|
67
67
|
// Transform for animation-name property
|
|
68
68
|
export const animationName = tokenStream => {
|
|
69
69
|
const names = parseCommaSeparatedValues(tokenStream, ts =>
|
|
70
|
-
ts.expect(IDENT, NONE)
|
|
70
|
+
ts.expect(IDENT, NONE, VARIABLE)
|
|
71
71
|
)
|
|
72
72
|
return { animationName: names }
|
|
73
73
|
}
|
|
@@ -75,7 +75,7 @@ export const animationName = tokenStream => {
|
|
|
75
75
|
// Transform for animation-duration property
|
|
76
76
|
export const animationDuration = tokenStream => {
|
|
77
77
|
const durations = parseCommaSeparatedValues(tokenStream, ts =>
|
|
78
|
-
ts.expect(TIME)
|
|
78
|
+
ts.expect(TIME, VARIABLE)
|
|
79
79
|
)
|
|
80
80
|
return { animationDuration: durations }
|
|
81
81
|
}
|
|
@@ -107,7 +107,9 @@ export const animationTimingFunction = tokenStream => {
|
|
|
107
107
|
|
|
108
108
|
// Transform for animation-delay property
|
|
109
109
|
export const animationDelay = tokenStream => {
|
|
110
|
-
const delays = parseCommaSeparatedValues(tokenStream, ts =>
|
|
110
|
+
const delays = parseCommaSeparatedValues(tokenStream, ts =>
|
|
111
|
+
ts.expect(TIME, VARIABLE)
|
|
112
|
+
)
|
|
111
113
|
return { animationDelay: delays }
|
|
112
114
|
}
|
|
113
115
|
|
|
@@ -222,6 +224,17 @@ export default tokenStream => {
|
|
|
222
224
|
continue
|
|
223
225
|
}
|
|
224
226
|
|
|
227
|
+
// Match time or variable (for duration/delay) - check before functions
|
|
228
|
+
if (tokenStream.matches(TIME) || tokenStream.matches(VARIABLE)) {
|
|
229
|
+
const value = tokenStream.lastValue
|
|
230
|
+
if (duration === null) {
|
|
231
|
+
duration = value
|
|
232
|
+
} else {
|
|
233
|
+
delay = value
|
|
234
|
+
}
|
|
235
|
+
continue
|
|
236
|
+
}
|
|
237
|
+
|
|
225
238
|
// Check for timing function (cubic-bezier or steps)
|
|
226
239
|
const funcStream = tokenStream.matchesFunction()
|
|
227
240
|
if (funcStream) {
|
|
@@ -247,17 +260,6 @@ export default tokenStream => {
|
|
|
247
260
|
continue
|
|
248
261
|
}
|
|
249
262
|
|
|
250
|
-
// Match time
|
|
251
|
-
if (tokenStream.matches(TIME)) {
|
|
252
|
-
const value = tokenStream.lastValue
|
|
253
|
-
if (duration === null) {
|
|
254
|
-
duration = value
|
|
255
|
-
} else {
|
|
256
|
-
delay = value
|
|
257
|
-
}
|
|
258
|
-
continue
|
|
259
|
-
}
|
|
260
|
-
|
|
261
263
|
// Match identifier
|
|
262
264
|
if (tokenStream.matches(IDENT)) {
|
|
263
265
|
const value = tokenStream.lastValue
|
package/src/transforms/index.js
CHANGED
|
@@ -53,7 +53,7 @@ const borderRadius = directionFactory({
|
|
|
53
53
|
})
|
|
54
54
|
const borderWidth = directionFactory({ prefix: 'border', suffix: 'Width' })
|
|
55
55
|
const margin = directionFactory({
|
|
56
|
-
types: [LENGTH, UNSUPPORTED_LENGTH_UNIT, PERCENT, AUTO],
|
|
56
|
+
types: [LENGTH, UNSUPPORTED_LENGTH_UNIT, PERCENT, AUTO, VARIABLE],
|
|
57
57
|
prefix: 'margin',
|
|
58
58
|
})
|
|
59
59
|
const padding = directionFactory({ prefix: 'padding' })
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
SPACE,
|
|
3
|
+
COMMA,
|
|
4
|
+
LENGTH,
|
|
5
|
+
NUMBER,
|
|
6
|
+
ANGLE,
|
|
7
|
+
PERCENT,
|
|
8
|
+
VARIABLE,
|
|
9
|
+
} from '../tokenTypes'
|
|
2
10
|
|
|
3
11
|
const oneOfTypes = tokenTypes => functionStream => {
|
|
4
12
|
const value = functionStream.expect(...tokenTypes)
|
|
@@ -6,9 +14,9 @@ const oneOfTypes = tokenTypes => functionStream => {
|
|
|
6
14
|
return value
|
|
7
15
|
}
|
|
8
16
|
|
|
9
|
-
const singleNumber = oneOfTypes([NUMBER])
|
|
10
|
-
const singleLengthOrPercent = oneOfTypes([LENGTH, PERCENT])
|
|
11
|
-
const singleAngle = oneOfTypes([ANGLE])
|
|
17
|
+
const singleNumber = oneOfTypes([NUMBER, VARIABLE])
|
|
18
|
+
const singleLengthOrPercent = oneOfTypes([LENGTH, PERCENT, VARIABLE])
|
|
19
|
+
const singleAngle = oneOfTypes([ANGLE, VARIABLE])
|
|
12
20
|
const xyTransformFactory = tokenTypes => (
|
|
13
21
|
key,
|
|
14
22
|
valueIfOmitted
|
|
@@ -31,9 +39,9 @@ const xyTransformFactory = tokenTypes => (
|
|
|
31
39
|
|
|
32
40
|
return [{ [`${key}Y`]: y }, { [`${key}X`]: x }]
|
|
33
41
|
}
|
|
34
|
-
const xyNumber = xyTransformFactory([NUMBER])
|
|
35
|
-
const xyLengthOrPercent = xyTransformFactory([LENGTH, PERCENT])
|
|
36
|
-
const xyAngle = xyTransformFactory([ANGLE])
|
|
42
|
+
const xyNumber = xyTransformFactory([NUMBER, VARIABLE])
|
|
43
|
+
const xyLengthOrPercent = xyTransformFactory([LENGTH, PERCENT, VARIABLE])
|
|
44
|
+
const xyAngle = xyTransformFactory([ANGLE, VARIABLE])
|
|
37
45
|
|
|
38
46
|
const partTransforms = {
|
|
39
47
|
perspective: singleNumber,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import camelizeStyleName from 'camelize'
|
|
2
|
-
import { SPACE, COMMA, IDENT, TIME, NONE } from '../tokenTypes'
|
|
2
|
+
import { SPACE, COMMA, IDENT, TIME, NONE, VARIABLE } from '../tokenTypes'
|
|
3
3
|
|
|
4
4
|
// Timing function keywords
|
|
5
5
|
const timingFunctionKeywords = [
|
|
@@ -65,7 +65,7 @@ export const transitionProperty = tokenStream => {
|
|
|
65
65
|
// Transform for transition-duration
|
|
66
66
|
export const transitionDuration = tokenStream => {
|
|
67
67
|
const durations = parseCommaSeparatedValues(tokenStream, ts =>
|
|
68
|
-
ts.expect(TIME)
|
|
68
|
+
ts.expect(TIME, VARIABLE)
|
|
69
69
|
)
|
|
70
70
|
return { transitionDuration: durations }
|
|
71
71
|
}
|
|
@@ -97,7 +97,9 @@ export const transitionTimingFunction = tokenStream => {
|
|
|
97
97
|
|
|
98
98
|
// Transform for transition-delay
|
|
99
99
|
export const transitionDelay = tokenStream => {
|
|
100
|
-
const delays = parseCommaSeparatedValues(tokenStream, ts =>
|
|
100
|
+
const delays = parseCommaSeparatedValues(tokenStream, ts =>
|
|
101
|
+
ts.expect(TIME, VARIABLE)
|
|
102
|
+
)
|
|
101
103
|
return { transitionDelay: delays }
|
|
102
104
|
}
|
|
103
105
|
|
|
@@ -158,10 +160,20 @@ export default tokenStream => {
|
|
|
158
160
|
continue
|
|
159
161
|
}
|
|
160
162
|
|
|
163
|
+
// Match time or variable (for duration/delay) - check before functions
|
|
164
|
+
if (tokenStream.matches(TIME) || tokenStream.matches(VARIABLE)) {
|
|
165
|
+
const value = tokenStream.lastValue
|
|
166
|
+
if (duration === null) {
|
|
167
|
+
duration = value
|
|
168
|
+
} else {
|
|
169
|
+
delay = value
|
|
170
|
+
}
|
|
171
|
+
continue
|
|
172
|
+
}
|
|
173
|
+
|
|
161
174
|
// Check for timing function (cubic-bezier or steps)
|
|
162
175
|
const funcStream = tokenStream.matchesFunction()
|
|
163
176
|
if (funcStream) {
|
|
164
|
-
// It's a function like cubic-bezier() or steps()
|
|
165
177
|
const funcName = funcStream.functionName
|
|
166
178
|
const args = []
|
|
167
179
|
while (funcStream.hasTokens()) {
|
|
@@ -189,16 +201,6 @@ export default tokenStream => {
|
|
|
189
201
|
continue
|
|
190
202
|
}
|
|
191
203
|
|
|
192
|
-
if (tokenStream.matches(TIME)) {
|
|
193
|
-
const value = tokenStream.lastValue
|
|
194
|
-
if (duration === null) {
|
|
195
|
-
duration = value
|
|
196
|
-
} else {
|
|
197
|
-
delay = value
|
|
198
|
-
}
|
|
199
|
-
continue
|
|
200
|
-
}
|
|
201
|
-
|
|
202
204
|
// Try to match as word for property names like 'all', 'opacity', etc.
|
|
203
205
|
const wordMatch = tokenStream.expect(node => {
|
|
204
206
|
if (node.type === 'word') return node.value
|
package/src/transforms/util.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from '../tokenTypes'
|
|
10
10
|
|
|
11
11
|
export const directionFactory = ({
|
|
12
|
-
types = [LENGTH, UNSUPPORTED_LENGTH_UNIT, PERCENT],
|
|
12
|
+
types = [LENGTH, UNSUPPORTED_LENGTH_UNIT, PERCENT, VARIABLE],
|
|
13
13
|
directions = ['Top', 'Right', 'Bottom', 'Left'],
|
|
14
14
|
prefix = '',
|
|
15
15
|
suffix = '',
|
|
@@ -68,10 +68,13 @@ export const parseShadow = tokenStream => {
|
|
|
68
68
|
offsetX === undefined &&
|
|
69
69
|
tokenStream.matches(LENGTH, UNSUPPORTED_LENGTH_UNIT)
|
|
70
70
|
) {
|
|
71
|
+
// First offset must be a concrete LENGTH to distinguish from color
|
|
71
72
|
offsetX = tokenStream.lastValue
|
|
72
73
|
tokenStream.expect(SPACE)
|
|
73
|
-
|
|
74
|
+
// Second offset and radius can be VARIABLE
|
|
75
|
+
offsetY = tokenStream.expect(LENGTH, UNSUPPORTED_LENGTH_UNIT, VARIABLE)
|
|
74
76
|
|
|
77
|
+
// Try to match optional blur-radius (concrete LENGTH only here)
|
|
75
78
|
tokenStream.saveRewindPoint()
|
|
76
79
|
if (
|
|
77
80
|
tokenStream.matches(SPACE) &&
|
|
@@ -81,6 +84,25 @@ export const parseShadow = tokenStream => {
|
|
|
81
84
|
} else {
|
|
82
85
|
tokenStream.rewind()
|
|
83
86
|
}
|
|
87
|
+
} else if (
|
|
88
|
+
offsetX !== undefined &&
|
|
89
|
+
radius === undefined &&
|
|
90
|
+
color === undefined &&
|
|
91
|
+
tokenStream.matches(VARIABLE)
|
|
92
|
+
) {
|
|
93
|
+
// VARIABLE after offsets - could be radius or color
|
|
94
|
+
// Peek ahead to determine which
|
|
95
|
+
const potentialValue = tokenStream.lastValue
|
|
96
|
+
tokenStream.saveRewindPoint()
|
|
97
|
+
if (tokenStream.matches(SPACE) && tokenStream.hasTokens()) {
|
|
98
|
+
// There's more content - this VARIABLE is the radius
|
|
99
|
+
tokenStream.rewind()
|
|
100
|
+
radius = potentialValue
|
|
101
|
+
} else {
|
|
102
|
+
// No more content - this VARIABLE is the color
|
|
103
|
+
tokenStream.rewind()
|
|
104
|
+
color = potentialValue
|
|
105
|
+
}
|
|
84
106
|
} else if (
|
|
85
107
|
color === undefined &&
|
|
86
108
|
(tokenStream.matches(COLOR) || tokenStream.matches(VARIABLE))
|