@colorye/react-native-css 0.3.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/README.md +198 -0
- package/crates/transformer/index.js +105 -0
- package/crates/transformer/transformer.darwin-arm64.node +0 -0
- package/crates/transformer/transformer.node +0 -0
- package/dist/babel.js +208 -0
- package/dist/exported-stylesheet.json +1 -0
- package/dist/features/build-transform.js +575 -0
- package/dist/features/css-calc.js +539 -0
- package/dist/features/css-media.js +77 -0
- package/dist/features/css-transform.js +426 -0
- package/dist/features/css-vars.js +153 -0
- package/dist/features/stylesheet.js +45 -0
- package/dist/index.d.ts +89 -0
- package/dist/index.js +60 -0
- package/dist/interop.js +260 -0
- package/dist/transformer-runtime.js +274 -0
- package/dist/transformer.js +100 -0
- package/dist/utils/babel.js +363 -0
- package/dist/utils/css.js +263 -0
- package/dist/utils/helper.js +11 -0
- package/package.json +51 -0
- package/src/babel.js +271 -0
- package/src/exported-stylesheet.json +1 -0
- package/src/features/build-transform.js +536 -0
- package/src/features/css-calc.js +490 -0
- package/src/features/css-media.js +78 -0
- package/src/features/css-transform.js +446 -0
- package/src/features/css-vars.js +138 -0
- package/src/features/stylesheet.js +29 -0
- package/src/index.d.ts +89 -0
- package/src/index.js +29 -0
- package/src/interop.js +269 -0
- package/src/transformer-runtime.js +241 -0
- package/src/transformer.js +87 -0
- package/src/utils/babel.js +425 -0
- package/src/utils/css.js +221 -0
- package/src/utils/helper.js +3 -0
- package/types.d.ts +47 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
const UNSUPPORTED_PROPERTIES = ["outline"];
|
|
2
|
+
const remOrEmUnitRe = /([\d.]+)(?:rem|em)\b/g;
|
|
3
|
+
|
|
4
|
+
export default function CssTransform() {
|
|
5
|
+
this.transformUnsafeValue = (property, value) => {
|
|
6
|
+
if (!this.isPropertySupported(property, value)) {
|
|
7
|
+
console.info("UNSUPPORTED", property, value);
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (typeof value === "string") {
|
|
12
|
+
value = value.trim();
|
|
13
|
+
value = this.transformImportant(property, value);
|
|
14
|
+
}
|
|
15
|
+
value = this.transformPosition(property, value);
|
|
16
|
+
value = this.transformBorderRadius(property, value);
|
|
17
|
+
value = this.transformOpacity(property, value);
|
|
18
|
+
|
|
19
|
+
property = this.getAliasedPropertyName(property);
|
|
20
|
+
|
|
21
|
+
return [property, value];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
this.transformUnsupportedUnit = (value) => {
|
|
25
|
+
if (value === undefined || typeof value !== "string") return value;
|
|
26
|
+
remOrEmUnitRe.lastIndex = 0;
|
|
27
|
+
return value.replace(remOrEmUnitRe, (_, rem) => {
|
|
28
|
+
return rem * 16;
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
this.transformViewportUnit = (value, { width, height } = {}) => {
|
|
33
|
+
if (value === undefined || typeof value !== "string") return value;
|
|
34
|
+
if (!width || !height) return value;
|
|
35
|
+
|
|
36
|
+
const viewportUnitRe = /([+-]?[0-9.]+)(vh|vw|vmin|vmax)\b/g;
|
|
37
|
+
const dimensionsMap = {
|
|
38
|
+
vw: width,
|
|
39
|
+
vh: height,
|
|
40
|
+
};
|
|
41
|
+
return value.replace(viewportUnitRe, (_, number, unit) => {
|
|
42
|
+
return (parseFloat(number) * dimensionsMap[unit]) / 100;
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
this.removeUnit = (value) => {
|
|
47
|
+
if (value === undefined || typeof value !== "string") return value;
|
|
48
|
+
return value.replace(/px/g, "");
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
this.isPropertySupported = (property, value) => {
|
|
52
|
+
if (UNSUPPORTED_PROPERTIES.includes(property)) return false;
|
|
53
|
+
if (value === undefined) return false;
|
|
54
|
+
if (!["number", "string"].includes(typeof value)) return false;
|
|
55
|
+
return true;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
this.transformImportant = (property, value) => {
|
|
59
|
+
if (typeof value !== "string") return value;
|
|
60
|
+
return value.replace(/!important/g, "");
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
this.transformPosition = (property, value) => {
|
|
64
|
+
if (property === "position" && value === "fixed") {
|
|
65
|
+
return "absolute";
|
|
66
|
+
}
|
|
67
|
+
return value;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
this.transformBorderRadius = (property, value) => {
|
|
71
|
+
if (property.toLowerCase().endsWith("radius") && typeof value === "string" && value.includes("%")) {
|
|
72
|
+
return 9999;
|
|
73
|
+
}
|
|
74
|
+
return value;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
this.transformOpacity = (property, value) => {
|
|
78
|
+
if (property === "opacity" && typeof value === "string" && value.endsWith("%")) {
|
|
79
|
+
const num = parseFloat(value);
|
|
80
|
+
if (!isNaN(num)) {
|
|
81
|
+
return num / 100;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return value;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
this.transformBorder = (property, value) => {
|
|
88
|
+
if (value === "none") {
|
|
89
|
+
return { [`${property}Width`]: 0 };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const borderRe = /(\S+)(?:\s+(solid|dashed|dotted)(?:\s+(\S+))?)?/g;
|
|
93
|
+
const [, width, style, color] = borderRe.exec(String(value)) || [];
|
|
94
|
+
|
|
95
|
+
const transformed = {};
|
|
96
|
+
|
|
97
|
+
if (width) {
|
|
98
|
+
const wStr = String(width).trim();
|
|
99
|
+
transformed[`${property}Width`] = wStr !== "" && !isNaN(Number(wStr)) ? Number(wStr) : width;
|
|
100
|
+
} else {
|
|
101
|
+
transformed[`${property}Width`] = 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (style) {
|
|
105
|
+
transformed.borderStyle = ["solid", "dotted", "dashed"].includes(style) ? style : "solid";
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (color) {
|
|
109
|
+
transformed[`${property}Color`] = color;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return transformed;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
this.transformSpacing = (property, value) => {
|
|
116
|
+
const strValue = String(value).trim();
|
|
117
|
+
const parts = [];
|
|
118
|
+
let current = "";
|
|
119
|
+
let depth = 0;
|
|
120
|
+
for (let i = 0; i < strValue.length; i++) {
|
|
121
|
+
const char = strValue[i];
|
|
122
|
+
if (char === "(") {
|
|
123
|
+
depth++;
|
|
124
|
+
current += char;
|
|
125
|
+
} else if (char === ")") {
|
|
126
|
+
depth--;
|
|
127
|
+
current += char;
|
|
128
|
+
} else if (char === " " && depth === 0) {
|
|
129
|
+
if (current) {
|
|
130
|
+
parts.push(current);
|
|
131
|
+
current = "";
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
current += char;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (current) {
|
|
138
|
+
parts.push(current);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const cleanedParts = parts.filter(Boolean);
|
|
142
|
+
|
|
143
|
+
const toNumberOrString = (val) => {
|
|
144
|
+
if (typeof val === "string" && val.trim() !== "" && !isNaN(Number(val))) {
|
|
145
|
+
return Number(val);
|
|
146
|
+
}
|
|
147
|
+
return val;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const transformed = {};
|
|
151
|
+
|
|
152
|
+
if (cleanedParts.length === 0) {
|
|
153
|
+
transformed[`${property}Top`] = 0;
|
|
154
|
+
transformed[`${property}Right`] = 0;
|
|
155
|
+
transformed[`${property}Bottom`] = 0;
|
|
156
|
+
transformed[`${property}Left`] = 0;
|
|
157
|
+
} else if (cleanedParts.length === 1) {
|
|
158
|
+
const top = cleanedParts[0];
|
|
159
|
+
transformed[`${property}Top`] = toNumberOrString(top);
|
|
160
|
+
transformed[`${property}Right`] = toNumberOrString(top);
|
|
161
|
+
transformed[`${property}Bottom`] = toNumberOrString(top);
|
|
162
|
+
transformed[`${property}Left`] = toNumberOrString(top);
|
|
163
|
+
} else if (cleanedParts.length === 2) {
|
|
164
|
+
const top = cleanedParts[0];
|
|
165
|
+
const right = cleanedParts[1];
|
|
166
|
+
transformed[`${property}Top`] = toNumberOrString(top);
|
|
167
|
+
transformed[`${property}Right`] = toNumberOrString(right);
|
|
168
|
+
transformed[`${property}Bottom`] = toNumberOrString(top);
|
|
169
|
+
transformed[`${property}Left`] = toNumberOrString(right);
|
|
170
|
+
} else if (cleanedParts.length === 3) {
|
|
171
|
+
const top = cleanedParts[0];
|
|
172
|
+
const right = cleanedParts[1];
|
|
173
|
+
const bottom = cleanedParts[2];
|
|
174
|
+
transformed[`${property}Top`] = toNumberOrString(top);
|
|
175
|
+
transformed[`${property}Right`] = toNumberOrString(right);
|
|
176
|
+
transformed[`${property}Bottom`] = toNumberOrString(bottom);
|
|
177
|
+
transformed[`${property}Left`] = toNumberOrString(right);
|
|
178
|
+
} else {
|
|
179
|
+
const top = cleanedParts[0];
|
|
180
|
+
const right = cleanedParts[1];
|
|
181
|
+
const bottom = cleanedParts[2];
|
|
182
|
+
const left = cleanedParts[3];
|
|
183
|
+
transformed[`${property}Top`] = toNumberOrString(top);
|
|
184
|
+
transformed[`${property}Right`] = toNumberOrString(right);
|
|
185
|
+
transformed[`${property}Bottom`] = toNumberOrString(bottom);
|
|
186
|
+
transformed[`${property}Left`] = toNumberOrString(left);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return transformed;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
this.transformFontWeight = (property, value) => {
|
|
193
|
+
const fontWeightRe = /(normal|bold|100|200|300|400|500|600|700|800|900)/g;
|
|
194
|
+
|
|
195
|
+
if (!fontWeightRe.test(String(value))) return;
|
|
196
|
+
return {
|
|
197
|
+
[property]: String(value),
|
|
198
|
+
};
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
this.transformTransform = (property, value) => {
|
|
202
|
+
const transformRe =
|
|
203
|
+
/(perspective|rotate|rotateX|rotateY|scale|scaleX|scaleY|translate|translateX|translateY|skew|skewX|skewY)\s*\(\s*([^,)]+)[,\s]*([^)]+)?\)/g;
|
|
204
|
+
|
|
205
|
+
const transforms = [];
|
|
206
|
+
let match;
|
|
207
|
+
const strValue = String(value);
|
|
208
|
+
do {
|
|
209
|
+
match = transformRe.exec(strValue);
|
|
210
|
+
if (!match) break;
|
|
211
|
+
|
|
212
|
+
const [, token, val1, val2] = match;
|
|
213
|
+
|
|
214
|
+
if (["translate", "skew"].includes(token)) {
|
|
215
|
+
const v1 = String(val1).trim();
|
|
216
|
+
const v2 = String(val2).trim();
|
|
217
|
+
transforms.push({ [`${token}X`]: v1 !== "" && !isNaN(Number(v1)) ? Number(v1) : val1 });
|
|
218
|
+
transforms.push({ [`${token}Y`]: v2 !== "" && !isNaN(Number(v2)) ? Number(v2) : val2 });
|
|
219
|
+
} else {
|
|
220
|
+
const v1 = String(val1).trim();
|
|
221
|
+
transforms.push({ [token]: v1 !== "" && !isNaN(Number(v1)) ? Number(v1) : val1 });
|
|
222
|
+
}
|
|
223
|
+
} while (match);
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
[property]: transforms,
|
|
227
|
+
};
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
this.transformFontScaling = (property, value, { width, roundFn }) => {
|
|
231
|
+
if (!["fontSize", "lineHeight"].includes(property)) return value;
|
|
232
|
+
|
|
233
|
+
// Base width for design (iPhone 6/7/8)
|
|
234
|
+
const baseWidth = 375;
|
|
235
|
+
|
|
236
|
+
// Calculate scaling factor based on device width
|
|
237
|
+
const scaleFactor = width ? width / baseWidth : 1;
|
|
238
|
+
if (typeof value === "string" && value.trim() !== "" && !isNaN(Number(value))) {
|
|
239
|
+
return roundFn(Number(value) * scaleFactor);
|
|
240
|
+
} else if (typeof value === "number") {
|
|
241
|
+
return roundFn(value * scaleFactor);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return value;
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
this.transformLogicalProperty = (property, value) => {
|
|
248
|
+
const strValue = String(value).trim();
|
|
249
|
+
const parts = [];
|
|
250
|
+
let current = "";
|
|
251
|
+
let depth = 0;
|
|
252
|
+
for (let i = 0; i < strValue.length; i++) {
|
|
253
|
+
const char = strValue[i];
|
|
254
|
+
if (char === "(") {
|
|
255
|
+
depth++;
|
|
256
|
+
current += char;
|
|
257
|
+
} else if (char === ")") {
|
|
258
|
+
depth--;
|
|
259
|
+
current += char;
|
|
260
|
+
} else if (char === " " && depth === 0) {
|
|
261
|
+
if (current) {
|
|
262
|
+
parts.push(current);
|
|
263
|
+
current = "";
|
|
264
|
+
}
|
|
265
|
+
} else {
|
|
266
|
+
current += char;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (current) {
|
|
270
|
+
parts.push(current);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const cleanedParts = parts.filter(Boolean);
|
|
274
|
+
|
|
275
|
+
const toNumberOrString = (val) => {
|
|
276
|
+
if (typeof val === "string" && val.trim() !== "" && !isNaN(Number(val))) {
|
|
277
|
+
return Number(val);
|
|
278
|
+
}
|
|
279
|
+
return val;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
if (property === "paddingInlineStart") return { paddingStart: toNumberOrString(value) };
|
|
283
|
+
if (property === "paddingInlineEnd") return { paddingEnd: toNumberOrString(value) };
|
|
284
|
+
if (property === "marginInlineStart") return { marginStart: toNumberOrString(value) };
|
|
285
|
+
if (property === "marginInlineEnd") return { marginEnd: toNumberOrString(value) };
|
|
286
|
+
if (property === "insetInlineStart") return { start: toNumberOrString(value) };
|
|
287
|
+
if (property === "insetInlineEnd") return { end: toNumberOrString(value) };
|
|
288
|
+
if (property === "insetBlockStart") return { top: toNumberOrString(value) };
|
|
289
|
+
if (property === "insetBlockEnd") return { bottom: toNumberOrString(value) };
|
|
290
|
+
|
|
291
|
+
if (property === "paddingInline") {
|
|
292
|
+
if (cleanedParts.length === 1) {
|
|
293
|
+
return { paddingHorizontal: toNumberOrString(cleanedParts[0]) };
|
|
294
|
+
}
|
|
295
|
+
if (cleanedParts.length >= 2) {
|
|
296
|
+
return {
|
|
297
|
+
paddingStart: toNumberOrString(cleanedParts[0]),
|
|
298
|
+
paddingEnd: toNumberOrString(cleanedParts[1]),
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (property === "marginInline") {
|
|
304
|
+
if (cleanedParts.length === 1) {
|
|
305
|
+
return { marginHorizontal: toNumberOrString(cleanedParts[0]) };
|
|
306
|
+
}
|
|
307
|
+
if (cleanedParts.length >= 2) {
|
|
308
|
+
return {
|
|
309
|
+
marginStart: toNumberOrString(cleanedParts[0]),
|
|
310
|
+
marginEnd: toNumberOrString(cleanedParts[1]),
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (property === "paddingBlock") {
|
|
316
|
+
if (cleanedParts.length === 1) {
|
|
317
|
+
return { paddingVertical: toNumberOrString(cleanedParts[0]) };
|
|
318
|
+
}
|
|
319
|
+
if (cleanedParts.length >= 2) {
|
|
320
|
+
return {
|
|
321
|
+
paddingTop: toNumberOrString(cleanedParts[0]),
|
|
322
|
+
paddingBottom: toNumberOrString(cleanedParts[1]),
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (property === "marginBlock") {
|
|
328
|
+
if (cleanedParts.length === 1) {
|
|
329
|
+
return { marginVertical: toNumberOrString(cleanedParts[0]) };
|
|
330
|
+
}
|
|
331
|
+
if (cleanedParts.length >= 2) {
|
|
332
|
+
return {
|
|
333
|
+
marginTop: toNumberOrString(cleanedParts[0]),
|
|
334
|
+
marginBottom: toNumberOrString(cleanedParts[1]),
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (property === "insetInline") {
|
|
340
|
+
if (cleanedParts.length === 1) {
|
|
341
|
+
return {
|
|
342
|
+
left: toNumberOrString(cleanedParts[0]),
|
|
343
|
+
right: toNumberOrString(cleanedParts[0]),
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
if (cleanedParts.length >= 2) {
|
|
347
|
+
return {
|
|
348
|
+
start: toNumberOrString(cleanedParts[0]),
|
|
349
|
+
end: toNumberOrString(cleanedParts[1]),
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (property === "insetBlock") {
|
|
355
|
+
if (cleanedParts.length === 1) {
|
|
356
|
+
return {
|
|
357
|
+
top: toNumberOrString(cleanedParts[0]),
|
|
358
|
+
bottom: toNumberOrString(cleanedParts[0]),
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
if (cleanedParts.length >= 2) {
|
|
362
|
+
return {
|
|
363
|
+
top: toNumberOrString(cleanedParts[0]),
|
|
364
|
+
bottom: toNumberOrString(cleanedParts[1]),
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return null;
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
this.transform = (property, value, { width, height }) => {
|
|
373
|
+
if (property.toLowerCase().endsWith("radius")) {
|
|
374
|
+
value = this.transformBorderRadius(property, value);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (property === "opacity") {
|
|
378
|
+
value = this.transformOpacity(property, value);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (
|
|
382
|
+
[
|
|
383
|
+
"paddingInline",
|
|
384
|
+
"marginInline",
|
|
385
|
+
"paddingBlock",
|
|
386
|
+
"marginBlock",
|
|
387
|
+
"paddingInlineStart",
|
|
388
|
+
"paddingInlineEnd",
|
|
389
|
+
"marginInlineStart",
|
|
390
|
+
"marginInlineEnd",
|
|
391
|
+
"insetInline",
|
|
392
|
+
"insetInlineStart",
|
|
393
|
+
"insetInlineEnd",
|
|
394
|
+
"insetBlock",
|
|
395
|
+
"insetBlockStart",
|
|
396
|
+
"insetBlockEnd",
|
|
397
|
+
].includes(property)
|
|
398
|
+
) {
|
|
399
|
+
return this.transformLogicalProperty(property, value);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if (["border", "borderTop", "borderBottom", "borderLeft", "borderRight"].includes(property)) {
|
|
403
|
+
return this.transformBorder(property, value);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (["padding", "margin"].includes(property)) {
|
|
407
|
+
return this.transformSpacing(property, value);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (["flex"].includes(property)) {
|
|
411
|
+
return { flex: parseInt(value) };
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
if (["fontWeight"].includes(property)) {
|
|
415
|
+
return this.transformFontWeight(property, value);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (["scale"].includes(property)) {
|
|
419
|
+
let scaleVal = value;
|
|
420
|
+
if (typeof scaleVal === "string") {
|
|
421
|
+
const first = scaleVal.trim().split(/\s+/)[0];
|
|
422
|
+
if (first.endsWith("%")) {
|
|
423
|
+
scaleVal = parseFloat(first) / 100;
|
|
424
|
+
} else {
|
|
425
|
+
scaleVal = parseFloat(first);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return {
|
|
429
|
+
transform: [{ scale: isNaN(scaleVal) ? 1 : Number(scaleVal) }],
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (["transform"].includes(property)) {
|
|
434
|
+
return this.transformTransform(property, value);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return { [property]: isNaN(value) ? value : Number(value) };
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
this.getAliasedPropertyName = (property) => {
|
|
441
|
+
if (property === "background") property = "backgroundColor";
|
|
442
|
+
return property;
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
return this;
|
|
446
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import CssMedia from "./css-media";
|
|
2
|
+
|
|
3
|
+
export default function CssVars() {
|
|
4
|
+
this.global = {};
|
|
5
|
+
this.data = {};
|
|
6
|
+
|
|
7
|
+
const media = new CssMedia();
|
|
8
|
+
|
|
9
|
+
this.setGlobal = (declarations, { width, height } = {}) => {
|
|
10
|
+
for (const property in declarations) {
|
|
11
|
+
const value = declarations[property];
|
|
12
|
+
|
|
13
|
+
const [isMedia, matchedMedia] = media.match(property, { width, height });
|
|
14
|
+
if (isMedia) {
|
|
15
|
+
if (matchedMedia) {
|
|
16
|
+
this.setGlobal(value);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (this.isVar(property)) {
|
|
23
|
+
this.global[property] = value;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
this.getGlobal = () => {
|
|
29
|
+
return this.global;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
this.set = (selector, declarations, { width, height } = {}) => {
|
|
33
|
+
for (const property in declarations) {
|
|
34
|
+
const value = declarations[property];
|
|
35
|
+
|
|
36
|
+
const [isMedia, matchedMedia] = media.match(property, { width, height });
|
|
37
|
+
if (isMedia) {
|
|
38
|
+
if (matchedMedia) {
|
|
39
|
+
this.set(selector, value);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (this.isVar(property)) {
|
|
46
|
+
if (!this.data[selector]) this.data[selector] = {};
|
|
47
|
+
this.data[selector][property] = value;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
this.get = (selector) => {
|
|
53
|
+
return {
|
|
54
|
+
...this.global,
|
|
55
|
+
...(this.data[selector] || {}),
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
this.isVar = (property) => {
|
|
60
|
+
return /^--[\w-]+/.test(property);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
this.injectVar = (selector, value) => {
|
|
64
|
+
if (value === undefined || typeof value !== "string") return value;
|
|
65
|
+
|
|
66
|
+
const variables = this.get(selector);
|
|
67
|
+
|
|
68
|
+
function resolveOnce(str) {
|
|
69
|
+
let result = "";
|
|
70
|
+
let i = 0;
|
|
71
|
+
let changed = false;
|
|
72
|
+
|
|
73
|
+
while (i < str.length) {
|
|
74
|
+
const varIndex = str.indexOf("var(", i);
|
|
75
|
+
if (varIndex === -1) {
|
|
76
|
+
result += str.slice(i);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
result += str.slice(i, varIndex);
|
|
81
|
+
let depth = 1;
|
|
82
|
+
let j = varIndex + 4;
|
|
83
|
+
let commaIndex = -1;
|
|
84
|
+
|
|
85
|
+
while (j < str.length && depth > 0) {
|
|
86
|
+
if (str[j] === "(") {
|
|
87
|
+
depth++;
|
|
88
|
+
} else if (str[j] === ")") {
|
|
89
|
+
depth--;
|
|
90
|
+
} else if (str[j] === "," && depth === 1 && commaIndex === -1) {
|
|
91
|
+
commaIndex = j;
|
|
92
|
+
}
|
|
93
|
+
j++;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (depth !== 0) {
|
|
97
|
+
result += str.slice(varIndex);
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
changed = true;
|
|
102
|
+
let varName, fallback;
|
|
103
|
+
if (commaIndex !== -1) {
|
|
104
|
+
varName = str.slice(varIndex + 4, commaIndex).trim();
|
|
105
|
+
fallback = str.slice(commaIndex + 1, j - 1).trim();
|
|
106
|
+
} else {
|
|
107
|
+
varName = str.slice(varIndex + 4, j - 1).trim();
|
|
108
|
+
fallback = undefined;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const val = variables[varName];
|
|
112
|
+
if (val !== undefined && val !== "initial" && val !== "") {
|
|
113
|
+
result += val;
|
|
114
|
+
} else if (fallback !== undefined) {
|
|
115
|
+
result += fallback;
|
|
116
|
+
} else {
|
|
117
|
+
result += "";
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
i = j;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return { result, changed };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
let current = value;
|
|
127
|
+
let iterations = 0;
|
|
128
|
+
while (iterations < 10) {
|
|
129
|
+
const { result, changed } = resolveOnce(current);
|
|
130
|
+
if (!changed || result === current) break;
|
|
131
|
+
current = result;
|
|
132
|
+
iterations++;
|
|
133
|
+
}
|
|
134
|
+
return current;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
return this;
|
|
138
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { precomputeDeclaration } from "./build-transform";
|
|
2
|
+
|
|
3
|
+
export default function Stylesheet() {
|
|
4
|
+
this.rawStylesheet = {};
|
|
5
|
+
this.stylesheet = {};
|
|
6
|
+
|
|
7
|
+
this.setRawStylesheet = (raw) => {
|
|
8
|
+
this.rawStylesheet = raw;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
this.finalize = () => {
|
|
12
|
+
for (const [selector, rawDecl] of Object.entries(this.rawStylesheet)) {
|
|
13
|
+
const { _static, _dynamic, _hasDynamic } = precomputeDeclaration(rawDecl);
|
|
14
|
+
|
|
15
|
+
if (_hasDynamic) {
|
|
16
|
+
this.stylesheet[selector] = { _static, _dynamic };
|
|
17
|
+
} else {
|
|
18
|
+
this.stylesheet[selector] = _static;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
this.toJSON = () => {
|
|
24
|
+
this.finalize();
|
|
25
|
+
return JSON.stringify(this.stylesheet);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return this;
|
|
29
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { StyleProp, ViewStyle, TextStyle, ImageStyle } from "react-native";
|
|
3
|
+
|
|
4
|
+
export interface StyleMapping {
|
|
5
|
+
className?: string;
|
|
6
|
+
contentContainerClassName?: string;
|
|
7
|
+
[key: string]: string | undefined;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface GroupState {
|
|
11
|
+
pressed: boolean;
|
|
12
|
+
hovered?: boolean;
|
|
13
|
+
focus?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const GroupContext: React.Context<GroupState>;
|
|
17
|
+
export const InheritContext: React.Context<Record<string, any> | undefined>;
|
|
18
|
+
|
|
19
|
+
export function setGlobalStylesheet(sheet: Record<string, any>): void;
|
|
20
|
+
export function getGlobalStylesheet(): Record<string, any>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Wraps any React Native or third-party component to support className mapping.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* import { FlashList } from "@shopify/flash-list";
|
|
28
|
+
* import { cssInterop } from "@colorye/react-native-css";
|
|
29
|
+
*
|
|
30
|
+
* const StyledFlashList = cssInterop(FlashList, {
|
|
31
|
+
* className: "style",
|
|
32
|
+
* contentContainerClassName: "contentContainerStyle",
|
|
33
|
+
* });
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export function cssInterop<P extends object>(
|
|
37
|
+
Component: React.ComponentType<P>,
|
|
38
|
+
mapping?: StyleMapping
|
|
39
|
+
): React.ForwardRefExoticComponent<
|
|
40
|
+
React.PropsWithoutRef<P> & {
|
|
41
|
+
className?: string;
|
|
42
|
+
contentContainerClassName?: string;
|
|
43
|
+
inheritStyle?: any;
|
|
44
|
+
} & React.RefAttributes<any>
|
|
45
|
+
>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Alias for cssInterop.
|
|
49
|
+
*/
|
|
50
|
+
export function remapProps<P extends object>(
|
|
51
|
+
Component: React.ComponentType<P>,
|
|
52
|
+
mapping: StyleMapping
|
|
53
|
+
): React.ForwardRefExoticComponent<
|
|
54
|
+
React.PropsWithoutRef<P> & {
|
|
55
|
+
className?: string;
|
|
56
|
+
contentContainerClassName?: string;
|
|
57
|
+
inheritStyle?: any;
|
|
58
|
+
} & React.RefAttributes<any>
|
|
59
|
+
>;
|
|
60
|
+
|
|
61
|
+
export namespace Runtime {
|
|
62
|
+
export function getFlattenStyle(declarations: any): any;
|
|
63
|
+
export function getStyle(
|
|
64
|
+
stylesheet: any,
|
|
65
|
+
args: [inheritStyle?: any, className?: string, style?: any, elementName?: string]
|
|
66
|
+
): any;
|
|
67
|
+
export function getInheritStyle(declarations: any): Record<string, any> | undefined;
|
|
68
|
+
export function mergeStyles(inheritStyle: any, staticStyles: any, inlineStyle: any): any;
|
|
69
|
+
export function clearCache(): void;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function getStylesheet(css: string, filename?: string): string;
|
|
73
|
+
export function writeStylesheetJSON(content: string, filename?: string): void;
|
|
74
|
+
export function transform(args: { src: string; filename: string; options?: any }): any;
|
|
75
|
+
|
|
76
|
+
declare const _default: {
|
|
77
|
+
cssInterop: typeof cssInterop;
|
|
78
|
+
remapProps: typeof remapProps;
|
|
79
|
+
setGlobalStylesheet: typeof setGlobalStylesheet;
|
|
80
|
+
getGlobalStylesheet: typeof getGlobalStylesheet;
|
|
81
|
+
GroupContext: typeof GroupContext;
|
|
82
|
+
InheritContext: typeof InheritContext;
|
|
83
|
+
Runtime: typeof Runtime;
|
|
84
|
+
getStylesheet: typeof getStylesheet;
|
|
85
|
+
transform: typeof transform;
|
|
86
|
+
writeStylesheetJSON: typeof writeStylesheetJSON;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export default _default;
|