@tamagui/static 3.0.0-beta.889.1 → 3.0.0-beta.901.1
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/dist/cjs/compilerHost.cjs +151 -66
- package/dist/esm/compilerHost.mjs +151 -66
- package/dist/esm/compilerHost.mjs.map +1 -1
- package/package.json +17 -17
- package/src/compilerHost.ts +278 -114
- package/types/compilerHost.d.ts.map +1 -1
|
@@ -963,7 +963,17 @@ function createTamaguiCompilerHost(options) {
|
|
|
963
963
|
"animatedBy",
|
|
964
964
|
"render"
|
|
965
965
|
]);
|
|
966
|
-
const
|
|
966
|
+
const isFrontendClassName = (name, component) => name === "className" && !!component.staticConfig.styleFrontend;
|
|
967
|
+
const canLowerConditionalStyleProp = (name, component) => isStyleProp(name, component) && (!runtimeOnlyStyleProps.has(name) || isFrontendClassName(name, component));
|
|
968
|
+
const frontendClassDomain = (entry, component) => {
|
|
969
|
+
if (entry.kind !== "prop" || entry.value.kind !== "bailout" || !isFrontendClassName(entry.name, component)) {
|
|
970
|
+
return null;
|
|
971
|
+
}
|
|
972
|
+
const dynamic = entry.value.dynamic;
|
|
973
|
+
if (dynamic?.type !== "string" || !dynamic.values?.length) return null;
|
|
974
|
+
return dynamic.values.map(String);
|
|
975
|
+
};
|
|
976
|
+
const conditionalClassEntry = (entry, component) => entry.value.kind === "conditional" && canLowerConditionalStyleProp(entry.name, component) || frontendClassDomain(entry, component) !== null;
|
|
967
977
|
const isInvalidHostStyleProp = (name, component) => {
|
|
968
978
|
const staticConfig = component.staticConfig;
|
|
969
979
|
const validStyles = staticConfig.validStyles || (staticConfig.isInput ? import_helpers.stylePropsInput : staticConfig.isText ? import_helpers.stylePropsText : import_helpers.validStyles);
|
|
@@ -1115,6 +1125,9 @@ function createTamaguiCompilerHost(options) {
|
|
|
1115
1125
|
if (component.staticConfig.resolvers?.length) {
|
|
1116
1126
|
return false;
|
|
1117
1127
|
}
|
|
1128
|
+
if (!options.disablePartialExtraction && platform === "web" && isFrontendClassName(name, component)) {
|
|
1129
|
+
return true;
|
|
1130
|
+
}
|
|
1118
1131
|
return !options.disablePartialExtraction && (platform === "web" && !!directStyleName(name, component) || platform === "native" && directStyleName(name, component) === "opacity");
|
|
1119
1132
|
},
|
|
1120
1133
|
developmentDebugInstrumentation,
|
|
@@ -1182,7 +1195,33 @@ function createTamaguiCompilerHost(options) {
|
|
|
1182
1195
|
if (platform === "native" && component.domTag === "input" && typeof props.type === "string" && !import_dom.NATIVE_INPUT_TYPES.includes(props.type)) {
|
|
1183
1196
|
return bailout(input, "local/unsupported-target", `input type ${props.type} has no native text-entry control`);
|
|
1184
1197
|
}
|
|
1185
|
-
|
|
1198
|
+
let styleObjectStatic = null;
|
|
1199
|
+
const styleMemberEntries = [];
|
|
1200
|
+
for (const entry of input.element.entries) {
|
|
1201
|
+
if (entry.kind !== "prop" || entry.name !== "style" || entry.value.kind !== "object") {
|
|
1202
|
+
continue;
|
|
1203
|
+
}
|
|
1204
|
+
styleObjectStatic = {};
|
|
1205
|
+
for (const member of entry.value.members) {
|
|
1206
|
+
if (member.value.kind === "static") {
|
|
1207
|
+
styleObjectStatic[member.name] = member.value.value;
|
|
1208
|
+
continue;
|
|
1209
|
+
}
|
|
1210
|
+
if (!isStyleProp(member.name, component)) {
|
|
1211
|
+
return bailout(input, "local/dynamic-style-value", `Style prop ${member.name} could not be evaluated`, member.span);
|
|
1212
|
+
}
|
|
1213
|
+
styleMemberEntries.push({
|
|
1214
|
+
kind: "prop",
|
|
1215
|
+
name: member.name,
|
|
1216
|
+
span: member.span,
|
|
1217
|
+
value: member.value,
|
|
1218
|
+
styleMember: true
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
if (Object.keys(styleObjectStatic).length === 0) styleObjectStatic = null;
|
|
1222
|
+
}
|
|
1223
|
+
if (styleObjectStatic) props.style = styleObjectStatic;
|
|
1224
|
+
const dynamicStyleEntries = [...input.element.entries.filter((entry) => entry.kind === "prop" && (entry.value.kind === "bailout" || entry.value.kind === "conditional") && isStyleProp(entry.name, component)), ...styleMemberEntries];
|
|
1186
1225
|
{
|
|
1187
1226
|
const needsRuntimeMapping = (name) => runtimeEventProps.has(name) || platform === "native" && !component.domTag && nativePointerEventProps.has(name);
|
|
1188
1227
|
const directRuntimeEvent = input.element.entries.find((entry) => entry.kind === "prop" && needsRuntimeMapping(entry.name));
|
|
@@ -1213,66 +1252,92 @@ function createTamaguiCompilerHost(options) {
|
|
|
1213
1252
|
const animatedByNeedsRuntime = animationNames.has("animatedBy") && !animationNames.has("transition") && (dynamicStyleEntries.length > 0 || Object.keys(animationProps).some((name) => name !== "animatedBy" && (isStyleProp(name, component) && typeof animationProps[name] === "string" && animationProps[name].includes(":") || name === "animationConfig" || name === "forceStyle" || name === "onTransition")));
|
|
1214
1253
|
const runtimeAnimationRequired = animationNames.has("transition") && resolvedCssTransition === null || [...animationNames].some((name) => name !== "transition" && name !== "animatedBy" && name !== "animateOnly") || animatedByNeedsRuntime;
|
|
1215
1254
|
let dynamicHostStyleProperties = null;
|
|
1255
|
+
let laneAEntries = [];
|
|
1256
|
+
const laneAOwners = /* @__PURE__ */ new Set();
|
|
1257
|
+
const laneAMemberOwners = /* @__PURE__ */ new Set();
|
|
1258
|
+
const conflictsWithInline = (owners, dynamicOwners, memberOwners) => [...owners].some((owner) => !memberOwners.has(owner) && cssOwnersConflict(/* @__PURE__ */ new Set([owner]), dynamicOwners));
|
|
1259
|
+
const laneAAttempts = [dynamicStyleEntries];
|
|
1260
|
+
{
|
|
1261
|
+
const rest2 = dynamicStyleEntries.filter((entry) => !conditionalClassEntry(entry, component));
|
|
1262
|
+
if (rest2.length > 0 && rest2.length < dynamicStyleEntries.length) {
|
|
1263
|
+
laneAAttempts.push(rest2);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1216
1266
|
if (platform === "web" && !options.disablePartialExtraction && (input.element.form === "jsx" || input.element.propsSpan !== null) && dynamicStyleEntries.length > 0 && !input.element.entries.some((entry) => entry.kind === "spread" && entry.value.kind !== "static")) {
|
|
1217
|
-
const
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
if (
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
let valuesStayLiteral = true;
|
|
1244
|
-
for (const value of dynamic.values) {
|
|
1245
|
-
const split2 = resolveSplitStyles({ [entry.name]: value }, partialStaticConfig(component.staticConfig));
|
|
1246
|
-
const atomics = Object.values(split2?.rulesToInsert ?? {});
|
|
1247
|
-
if (atomics.length !== 1 || atomics[0]?.[import_helpers.StyleObjectProperty] !== name || atomics[0]?.[import_helpers.StyleObjectValue] !== value) {
|
|
1248
|
-
valuesStayLiteral = false;
|
|
1249
|
-
break;
|
|
1250
|
-
}
|
|
1251
|
-
}
|
|
1252
|
-
if (valuesStayLiteral) {
|
|
1267
|
+
for (const attempt of laneAAttempts) {
|
|
1268
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1269
|
+
const properties = [];
|
|
1270
|
+
const dynamicOwners = /* @__PURE__ */ new Set();
|
|
1271
|
+
const memberOwners = /* @__PURE__ */ new Set();
|
|
1272
|
+
for (const entry of attempt) {
|
|
1273
|
+
if (entry.kind !== "prop" || entry.value.kind !== "bailout" && entry.value.kind !== "conditional") {
|
|
1274
|
+
continue;
|
|
1275
|
+
}
|
|
1276
|
+
const name = directStyleName(entry.name, component);
|
|
1277
|
+
if (!name || seen.has(name)) {
|
|
1278
|
+
properties.length = 0;
|
|
1279
|
+
break;
|
|
1280
|
+
}
|
|
1281
|
+
const owners = dynamicStyleOwners(name, component.staticConfig);
|
|
1282
|
+
if (!owners) {
|
|
1283
|
+
properties.length = 0;
|
|
1284
|
+
break;
|
|
1285
|
+
}
|
|
1286
|
+
let property = null;
|
|
1287
|
+
const expression = input.source.slice(entry.value.span.start, entry.value.span.end);
|
|
1288
|
+
if (resolvedCssTransition !== null && (name === "opacity" || name === "scale")) {
|
|
1289
|
+
property = name === "opacity" ? `opacity: (${expression})` : `transform: "scale(" + (${expression}) + ")"`;
|
|
1290
|
+
} else if (entry.value.kind === "bailout" && owners.has(name)) {
|
|
1291
|
+
const dynamic = entry.value.dynamic;
|
|
1292
|
+
if (dynamic?.type === "number") {
|
|
1253
1293
|
property = `${JSON.stringify(name)}: (${expression})`;
|
|
1294
|
+
} else if (dynamic?.type === "string" && dynamic.values?.length) {
|
|
1295
|
+
let valuesStayLiteral = true;
|
|
1296
|
+
for (const value of dynamic.values) {
|
|
1297
|
+
const split2 = resolveSplitStyles({ [entry.name]: value }, partialStaticConfig(component.staticConfig));
|
|
1298
|
+
const atomics = Object.values(split2?.rulesToInsert ?? {});
|
|
1299
|
+
if (atomics.length !== 1 || atomics[0]?.[import_helpers.StyleObjectProperty] !== name || atomics[0]?.[import_helpers.StyleObjectValue] !== value) {
|
|
1300
|
+
valuesStayLiteral = false;
|
|
1301
|
+
break;
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
if (valuesStayLiteral) {
|
|
1305
|
+
property = `${JSON.stringify(name)}: (${expression})`;
|
|
1306
|
+
}
|
|
1254
1307
|
}
|
|
1255
1308
|
}
|
|
1309
|
+
if (!property) {
|
|
1310
|
+
properties.length = 0;
|
|
1311
|
+
break;
|
|
1312
|
+
}
|
|
1313
|
+
seen.add(name);
|
|
1314
|
+
for (const owner of owners) {
|
|
1315
|
+
dynamicOwners.add(owner);
|
|
1316
|
+
if (entry.styleMember) memberOwners.add(owner);
|
|
1317
|
+
}
|
|
1318
|
+
properties.push(property);
|
|
1256
1319
|
}
|
|
1257
|
-
if (!
|
|
1258
|
-
|
|
1320
|
+
if (properties.length === attempt.length && !input.element.entries.some((entry) => {
|
|
1321
|
+
if (entry.kind !== "prop" || entry.value.kind !== "static") return false;
|
|
1322
|
+
const name = directStyleName(entry.name, component);
|
|
1323
|
+
if (!name) return false;
|
|
1324
|
+
const owners = styleOwners(name, entry.value.value, component.staticConfig);
|
|
1325
|
+
return !!owners && conflictsWithInline(owners, dynamicOwners, memberOwners);
|
|
1326
|
+
}) && !Object.entries(staticObject(props.style) ? props.style : {}).some(([name, value]) => {
|
|
1327
|
+
const owners = styleOwners(name, value, component.staticConfig);
|
|
1328
|
+
return !!owners && cssOwnersConflict(owners, dynamicOwners);
|
|
1329
|
+
})) {
|
|
1330
|
+
dynamicHostStyleProperties = properties;
|
|
1331
|
+
laneAEntries = attempt;
|
|
1332
|
+
for (const owner of dynamicOwners) laneAOwners.add(owner);
|
|
1333
|
+
for (const owner of memberOwners) laneAMemberOwners.add(owner);
|
|
1259
1334
|
break;
|
|
1260
1335
|
}
|
|
1261
|
-
seen.add(name);
|
|
1262
|
-
for (const owner of owners) dynamicOwners.add(owner);
|
|
1263
|
-
properties.push(property);
|
|
1264
|
-
}
|
|
1265
|
-
if (properties.length === dynamicStyleEntries.length && !input.element.entries.some((entry) => {
|
|
1266
|
-
if (entry.kind !== "prop" || entry.value.kind !== "static") return false;
|
|
1267
|
-
const name = directStyleName(entry.name, component);
|
|
1268
|
-
if (!name) return false;
|
|
1269
|
-
const owners = styleOwners(name, entry.value.value, component.staticConfig);
|
|
1270
|
-
return !!owners && cssOwnersConflict(owners, dynamicOwners);
|
|
1271
|
-
})) {
|
|
1272
|
-
dynamicHostStyleProperties = properties;
|
|
1273
1336
|
}
|
|
1274
1337
|
}
|
|
1275
|
-
const
|
|
1338
|
+
const laneACoversAll = dynamicHostStyleProperties !== null && laneAEntries.length === dynamicStyleEntries.length;
|
|
1339
|
+
const webClassEntries = dynamicHostStyleProperties === null ? dynamicStyleEntries : dynamicStyleEntries.filter((entry) => !laneAEntries.includes(entry));
|
|
1340
|
+
const supportsWebConditionalClasses = platform === "web" && !options.disablePartialExtraction && (input.element.form === "jsx" || input.element.propsSpan !== null) && !laneACoversAll && webClassEntries.length > 0 && webClassEntries.every((entry) => conditionalClassEntry(entry, component));
|
|
1276
1341
|
const themeEntry = componentOnlyProp("theme");
|
|
1277
1342
|
const themeInverseEntry = componentOnlyProp("themeInverse");
|
|
1278
1343
|
const themeBoundary = themeEntry.unknown || "theme" in props;
|
|
@@ -1296,7 +1361,7 @@ function createTamaguiCompilerHost(options) {
|
|
|
1296
1361
|
message: (0, import_compiler_core.zeroRuleMessage)(5, { detail: `the animation configured on ${input.element.component.name}` })
|
|
1297
1362
|
});
|
|
1298
1363
|
}
|
|
1299
|
-
if (platform === "web" && (dynamicStyleEntries.length > 0 || runtimeAnimationRequired) &&
|
|
1364
|
+
if (platform === "web" && (dynamicStyleEntries.length > 0 || runtimeAnimationRequired) && !laneACoversAll && !supportsWebConditionalClasses && component.partialRuntimeSafe) {
|
|
1300
1365
|
const hasSpread = input.element.entries.some((entry) => entry.kind === "spread" && entry.value.kind !== "static");
|
|
1301
1366
|
const unsupportedRuntimeStyle = input.element.entries.find((entry) => entry.kind === "prop" && isStyleProp(entry.name, component) && !runtimeAnimationProps.has(entry.name) && !directStyleName(entry.name, component));
|
|
1302
1367
|
if (!hasSpread && !unsupportedRuntimeStyle) {
|
|
@@ -1380,7 +1445,7 @@ function createTamaguiCompilerHost(options) {
|
|
|
1380
1445
|
});
|
|
1381
1446
|
}
|
|
1382
1447
|
const supportsNativeDynamicStyles = platform === "native" && !options.disablePartialExtraction && (input.element.form === "jsx" || input.element.propsSpan !== null) && dynamicStyleEntries.every((entry) => entry.kind === "prop" && (directStyleName(entry.name, component) === "opacity" || entry.value.kind === "conditional" && canLowerConditionalStyleProp(entry.name, component)));
|
|
1383
|
-
if (dynamicStyleEntries.length > 0 &&
|
|
1448
|
+
if (dynamicStyleEntries.length > 0 && !laneACoversAll && !supportsNativeDynamicStyles && !supportsWebConditionalClasses) {
|
|
1384
1449
|
const entry = dynamicStyleEntries[0];
|
|
1385
1450
|
return bailout(input, "local/dynamic-style-value", `Style prop ${entry.kind === "prop" ? entry.name : "unknown"} could not be safely extracted`, entry.span);
|
|
1386
1451
|
}
|
|
@@ -1397,6 +1462,13 @@ function createTamaguiCompilerHost(options) {
|
|
|
1397
1462
|
}
|
|
1398
1463
|
const propsForConditional = (target, value) => {
|
|
1399
1464
|
const branchProps = {};
|
|
1465
|
+
if (styleObjectStatic) branchProps.style = styleObjectStatic;
|
|
1466
|
+
if (target.styleMember) {
|
|
1467
|
+
branchProps.style = {
|
|
1468
|
+
...styleObjectStatic,
|
|
1469
|
+
[target.name]: value
|
|
1470
|
+
};
|
|
1471
|
+
}
|
|
1400
1472
|
for (const entry of input.element.entries) {
|
|
1401
1473
|
if (entry === target) {
|
|
1402
1474
|
branchProps[target.name] = value;
|
|
@@ -2005,22 +2077,22 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
|
|
|
2005
2077
|
const staticClasses = new Set(baseStaticClasses);
|
|
2006
2078
|
const webConditionalCSS = [];
|
|
2007
2079
|
const webConditionalKeys = /* @__PURE__ */ new Set();
|
|
2008
|
-
const webConditionalEntries = supportsWebConditionalClasses ?
|
|
2080
|
+
const webConditionalEntries = supportsWebConditionalClasses ? webClassEntries : [];
|
|
2009
2081
|
for (const entry of webConditionalEntries) {
|
|
2010
2082
|
let serializeWebTree = function(node) {
|
|
2011
|
-
if (node.kind === "leaf")
|
|
2012
|
-
const artifacts2 = leafArtifactsMap.get(node);
|
|
2013
|
-
const only = artifacts2 ? artifacts2.classes.filter((item) => !sharedInConditional.has(item)) : [];
|
|
2014
|
-
return JSON.stringify(only.join(" "));
|
|
2015
|
-
}
|
|
2083
|
+
if (node.kind === "leaf") return JSON.stringify(leafClasses(node));
|
|
2016
2084
|
const test = input.source.slice(node.test.start, node.test.end);
|
|
2017
2085
|
const truePart = serializeWebTree(node.whenTrue);
|
|
2018
2086
|
const falsePart = serializeWebTree(node.whenFalse);
|
|
2019
2087
|
return `(${test}) ? ${truePart} : ${falsePart}`;
|
|
2020
2088
|
};
|
|
2021
|
-
|
|
2022
|
-
const
|
|
2023
|
-
|
|
2089
|
+
const tree = entry.value.kind === "conditional" ? entry.value.tree : null;
|
|
2090
|
+
const domain = frontendClassDomain(entry, component);
|
|
2091
|
+
if (!tree && !domain) continue;
|
|
2092
|
+
const leaves = tree ? (0, import_compiler_core.collectLeaves)(tree) : domain.map((value) => ({
|
|
2093
|
+
value,
|
|
2094
|
+
dependencies: []
|
|
2095
|
+
}));
|
|
2024
2096
|
const leafArtifactsMap = /* @__PURE__ */ new Map();
|
|
2025
2097
|
const entryConditionalKeys = /* @__PURE__ */ new Set();
|
|
2026
2098
|
for (const leaf of leaves) {
|
|
@@ -2056,6 +2128,9 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
|
|
|
2056
2128
|
}
|
|
2057
2129
|
entryConditionalKeys.add(key);
|
|
2058
2130
|
}
|
|
2131
|
+
if (conflictsWithInline(changedKeys, laneAOwners, laneAMemberOwners)) {
|
|
2132
|
+
return bailout(input, "local/dynamic-style-value", `${entry.name} and an inline dynamic style both contribute a CSS property; their precedence cannot be resolved per-branch`, entry.value.span);
|
|
2133
|
+
}
|
|
2059
2134
|
const branchArtifacts = extractedStyleArtifacts(branchSplit, branchProps, options.tamaguiConfig, !component.domTag, Boolean(component.staticConfig.styleFrontend));
|
|
2060
2135
|
leafArtifactsMap.set(leaf, {
|
|
2061
2136
|
classes: branchArtifacts.className.split(" ").filter(Boolean),
|
|
@@ -2074,8 +2149,18 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
|
|
|
2074
2149
|
for (const cls of sharedInConditional) {
|
|
2075
2150
|
if (!baseStaticClasses.has(cls)) staticClasses.add(cls);
|
|
2076
2151
|
}
|
|
2077
|
-
const
|
|
2078
|
-
|
|
2152
|
+
const leafClasses = (leaf) => {
|
|
2153
|
+
const artifacts2 = leafArtifactsMap.get(leaf);
|
|
2154
|
+
const only = artifacts2 ? artifacts2.classes.filter((item) => !sharedInConditional.has(item)) : [];
|
|
2155
|
+
return only.join(" ");
|
|
2156
|
+
};
|
|
2157
|
+
if (tree) {
|
|
2158
|
+
programClassSources.push(serializeWebTree(tree));
|
|
2159
|
+
} else {
|
|
2160
|
+
const table = Object.fromEntries(leaves.map((leaf) => [leaf.value, leafClasses(leaf)]));
|
|
2161
|
+
const key = input.source.slice(entry.value.span.start, entry.value.span.end);
|
|
2162
|
+
programClassSources.push(`(${JSON.stringify(table)})[${key}]`);
|
|
2163
|
+
}
|
|
2079
2164
|
}
|
|
2080
2165
|
const webClassName = [...staticClasses].join(" ");
|
|
2081
2166
|
const hasStyleProgram = programClassSources.length > 0;
|
|
@@ -938,7 +938,17 @@ function createTamaguiCompilerHost(options) {
|
|
|
938
938
|
"animatedBy",
|
|
939
939
|
"render"
|
|
940
940
|
]);
|
|
941
|
-
const
|
|
941
|
+
const isFrontendClassName = (name, component) => name === "className" && !!component.staticConfig.styleFrontend;
|
|
942
|
+
const canLowerConditionalStyleProp = (name, component) => isStyleProp(name, component) && (!runtimeOnlyStyleProps.has(name) || isFrontendClassName(name, component));
|
|
943
|
+
const frontendClassDomain = (entry, component) => {
|
|
944
|
+
if (entry.kind !== "prop" || entry.value.kind !== "bailout" || !isFrontendClassName(entry.name, component)) {
|
|
945
|
+
return null;
|
|
946
|
+
}
|
|
947
|
+
const dynamic = entry.value.dynamic;
|
|
948
|
+
if (dynamic?.type !== "string" || !dynamic.values?.length) return null;
|
|
949
|
+
return dynamic.values.map(String);
|
|
950
|
+
};
|
|
951
|
+
const conditionalClassEntry = (entry, component) => entry.value.kind === "conditional" && canLowerConditionalStyleProp(entry.name, component) || frontendClassDomain(entry, component) !== null;
|
|
942
952
|
const isInvalidHostStyleProp = (name, component) => {
|
|
943
953
|
const staticConfig = component.staticConfig;
|
|
944
954
|
const validStyles$1 = staticConfig.validStyles || (staticConfig.isInput ? stylePropsInput : staticConfig.isText ? stylePropsText : validStyles);
|
|
@@ -1090,6 +1100,9 @@ function createTamaguiCompilerHost(options) {
|
|
|
1090
1100
|
if (component.staticConfig.resolvers?.length) {
|
|
1091
1101
|
return false;
|
|
1092
1102
|
}
|
|
1103
|
+
if (!options.disablePartialExtraction && platform === "web" && isFrontendClassName(name, component)) {
|
|
1104
|
+
return true;
|
|
1105
|
+
}
|
|
1093
1106
|
return !options.disablePartialExtraction && (platform === "web" && !!directStyleName(name, component) || platform === "native" && directStyleName(name, component) === "opacity");
|
|
1094
1107
|
},
|
|
1095
1108
|
developmentDebugInstrumentation,
|
|
@@ -1157,7 +1170,33 @@ function createTamaguiCompilerHost(options) {
|
|
|
1157
1170
|
if (platform === "native" && component.domTag === "input" && typeof props.type === "string" && !NATIVE_INPUT_TYPES.includes(props.type)) {
|
|
1158
1171
|
return bailout(input, "local/unsupported-target", `input type ${props.type} has no native text-entry control`);
|
|
1159
1172
|
}
|
|
1160
|
-
|
|
1173
|
+
let styleObjectStatic = null;
|
|
1174
|
+
const styleMemberEntries = [];
|
|
1175
|
+
for (const entry of input.element.entries) {
|
|
1176
|
+
if (entry.kind !== "prop" || entry.name !== "style" || entry.value.kind !== "object") {
|
|
1177
|
+
continue;
|
|
1178
|
+
}
|
|
1179
|
+
styleObjectStatic = {};
|
|
1180
|
+
for (const member of entry.value.members) {
|
|
1181
|
+
if (member.value.kind === "static") {
|
|
1182
|
+
styleObjectStatic[member.name] = member.value.value;
|
|
1183
|
+
continue;
|
|
1184
|
+
}
|
|
1185
|
+
if (!isStyleProp(member.name, component)) {
|
|
1186
|
+
return bailout(input, "local/dynamic-style-value", `Style prop ${member.name} could not be evaluated`, member.span);
|
|
1187
|
+
}
|
|
1188
|
+
styleMemberEntries.push({
|
|
1189
|
+
kind: "prop",
|
|
1190
|
+
name: member.name,
|
|
1191
|
+
span: member.span,
|
|
1192
|
+
value: member.value,
|
|
1193
|
+
styleMember: true
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
if (Object.keys(styleObjectStatic).length === 0) styleObjectStatic = null;
|
|
1197
|
+
}
|
|
1198
|
+
if (styleObjectStatic) props.style = styleObjectStatic;
|
|
1199
|
+
const dynamicStyleEntries = [...input.element.entries.filter((entry) => entry.kind === "prop" && (entry.value.kind === "bailout" || entry.value.kind === "conditional") && isStyleProp(entry.name, component)), ...styleMemberEntries];
|
|
1161
1200
|
{
|
|
1162
1201
|
const needsRuntimeMapping = (name) => runtimeEventProps.has(name) || platform === "native" && !component.domTag && nativePointerEventProps.has(name);
|
|
1163
1202
|
const directRuntimeEvent = input.element.entries.find((entry) => entry.kind === "prop" && needsRuntimeMapping(entry.name));
|
|
@@ -1188,66 +1227,92 @@ function createTamaguiCompilerHost(options) {
|
|
|
1188
1227
|
const animatedByNeedsRuntime = animationNames.has("animatedBy") && !animationNames.has("transition") && (dynamicStyleEntries.length > 0 || Object.keys(animationProps).some((name) => name !== "animatedBy" && (isStyleProp(name, component) && typeof animationProps[name] === "string" && animationProps[name].includes(":") || name === "animationConfig" || name === "forceStyle" || name === "onTransition")));
|
|
1189
1228
|
const runtimeAnimationRequired = animationNames.has("transition") && resolvedCssTransition === null || [...animationNames].some((name) => name !== "transition" && name !== "animatedBy" && name !== "animateOnly") || animatedByNeedsRuntime;
|
|
1190
1229
|
let dynamicHostStyleProperties = null;
|
|
1230
|
+
let laneAEntries = [];
|
|
1231
|
+
const laneAOwners = /* @__PURE__ */ new Set();
|
|
1232
|
+
const laneAMemberOwners = /* @__PURE__ */ new Set();
|
|
1233
|
+
const conflictsWithInline = (owners, dynamicOwners, memberOwners) => [...owners].some((owner) => !memberOwners.has(owner) && cssOwnersConflict(/* @__PURE__ */ new Set([owner]), dynamicOwners));
|
|
1234
|
+
const laneAAttempts = [dynamicStyleEntries];
|
|
1235
|
+
{
|
|
1236
|
+
const rest2 = dynamicStyleEntries.filter((entry) => !conditionalClassEntry(entry, component));
|
|
1237
|
+
if (rest2.length > 0 && rest2.length < dynamicStyleEntries.length) {
|
|
1238
|
+
laneAAttempts.push(rest2);
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1191
1241
|
if (platform === "web" && !options.disablePartialExtraction && (input.element.form === "jsx" || input.element.propsSpan !== null) && dynamicStyleEntries.length > 0 && !input.element.entries.some((entry) => entry.kind === "spread" && entry.value.kind !== "static")) {
|
|
1192
|
-
const
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
if (
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
let valuesStayLiteral = true;
|
|
1219
|
-
for (const value of dynamic.values) {
|
|
1220
|
-
const split2 = resolveSplitStyles({ [entry.name]: value }, partialStaticConfig(component.staticConfig));
|
|
1221
|
-
const atomics = Object.values(split2?.rulesToInsert ?? {});
|
|
1222
|
-
if (atomics.length !== 1 || atomics[0]?.[StyleObjectProperty] !== name || atomics[0]?.[StyleObjectValue] !== value) {
|
|
1223
|
-
valuesStayLiteral = false;
|
|
1224
|
-
break;
|
|
1225
|
-
}
|
|
1226
|
-
}
|
|
1227
|
-
if (valuesStayLiteral) {
|
|
1242
|
+
for (const attempt of laneAAttempts) {
|
|
1243
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1244
|
+
const properties = [];
|
|
1245
|
+
const dynamicOwners = /* @__PURE__ */ new Set();
|
|
1246
|
+
const memberOwners = /* @__PURE__ */ new Set();
|
|
1247
|
+
for (const entry of attempt) {
|
|
1248
|
+
if (entry.kind !== "prop" || entry.value.kind !== "bailout" && entry.value.kind !== "conditional") {
|
|
1249
|
+
continue;
|
|
1250
|
+
}
|
|
1251
|
+
const name = directStyleName(entry.name, component);
|
|
1252
|
+
if (!name || seen.has(name)) {
|
|
1253
|
+
properties.length = 0;
|
|
1254
|
+
break;
|
|
1255
|
+
}
|
|
1256
|
+
const owners = dynamicStyleOwners(name, component.staticConfig);
|
|
1257
|
+
if (!owners) {
|
|
1258
|
+
properties.length = 0;
|
|
1259
|
+
break;
|
|
1260
|
+
}
|
|
1261
|
+
let property = null;
|
|
1262
|
+
const expression = input.source.slice(entry.value.span.start, entry.value.span.end);
|
|
1263
|
+
if (resolvedCssTransition !== null && (name === "opacity" || name === "scale")) {
|
|
1264
|
+
property = name === "opacity" ? `opacity: (${expression})` : `transform: "scale(" + (${expression}) + ")"`;
|
|
1265
|
+
} else if (entry.value.kind === "bailout" && owners.has(name)) {
|
|
1266
|
+
const dynamic = entry.value.dynamic;
|
|
1267
|
+
if (dynamic?.type === "number") {
|
|
1228
1268
|
property = `${JSON.stringify(name)}: (${expression})`;
|
|
1269
|
+
} else if (dynamic?.type === "string" && dynamic.values?.length) {
|
|
1270
|
+
let valuesStayLiteral = true;
|
|
1271
|
+
for (const value of dynamic.values) {
|
|
1272
|
+
const split2 = resolveSplitStyles({ [entry.name]: value }, partialStaticConfig(component.staticConfig));
|
|
1273
|
+
const atomics = Object.values(split2?.rulesToInsert ?? {});
|
|
1274
|
+
if (atomics.length !== 1 || atomics[0]?.[StyleObjectProperty] !== name || atomics[0]?.[StyleObjectValue] !== value) {
|
|
1275
|
+
valuesStayLiteral = false;
|
|
1276
|
+
break;
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
if (valuesStayLiteral) {
|
|
1280
|
+
property = `${JSON.stringify(name)}: (${expression})`;
|
|
1281
|
+
}
|
|
1229
1282
|
}
|
|
1230
1283
|
}
|
|
1284
|
+
if (!property) {
|
|
1285
|
+
properties.length = 0;
|
|
1286
|
+
break;
|
|
1287
|
+
}
|
|
1288
|
+
seen.add(name);
|
|
1289
|
+
for (const owner of owners) {
|
|
1290
|
+
dynamicOwners.add(owner);
|
|
1291
|
+
if (entry.styleMember) memberOwners.add(owner);
|
|
1292
|
+
}
|
|
1293
|
+
properties.push(property);
|
|
1231
1294
|
}
|
|
1232
|
-
if (!
|
|
1233
|
-
|
|
1295
|
+
if (properties.length === attempt.length && !input.element.entries.some((entry) => {
|
|
1296
|
+
if (entry.kind !== "prop" || entry.value.kind !== "static") return false;
|
|
1297
|
+
const name = directStyleName(entry.name, component);
|
|
1298
|
+
if (!name) return false;
|
|
1299
|
+
const owners = styleOwners(name, entry.value.value, component.staticConfig);
|
|
1300
|
+
return !!owners && conflictsWithInline(owners, dynamicOwners, memberOwners);
|
|
1301
|
+
}) && !Object.entries(staticObject(props.style) ? props.style : {}).some(([name, value]) => {
|
|
1302
|
+
const owners = styleOwners(name, value, component.staticConfig);
|
|
1303
|
+
return !!owners && cssOwnersConflict(owners, dynamicOwners);
|
|
1304
|
+
})) {
|
|
1305
|
+
dynamicHostStyleProperties = properties;
|
|
1306
|
+
laneAEntries = attempt;
|
|
1307
|
+
for (const owner of dynamicOwners) laneAOwners.add(owner);
|
|
1308
|
+
for (const owner of memberOwners) laneAMemberOwners.add(owner);
|
|
1234
1309
|
break;
|
|
1235
1310
|
}
|
|
1236
|
-
seen.add(name);
|
|
1237
|
-
for (const owner of owners) dynamicOwners.add(owner);
|
|
1238
|
-
properties.push(property);
|
|
1239
|
-
}
|
|
1240
|
-
if (properties.length === dynamicStyleEntries.length && !input.element.entries.some((entry) => {
|
|
1241
|
-
if (entry.kind !== "prop" || entry.value.kind !== "static") return false;
|
|
1242
|
-
const name = directStyleName(entry.name, component);
|
|
1243
|
-
if (!name) return false;
|
|
1244
|
-
const owners = styleOwners(name, entry.value.value, component.staticConfig);
|
|
1245
|
-
return !!owners && cssOwnersConflict(owners, dynamicOwners);
|
|
1246
|
-
})) {
|
|
1247
|
-
dynamicHostStyleProperties = properties;
|
|
1248
1311
|
}
|
|
1249
1312
|
}
|
|
1250
|
-
const
|
|
1313
|
+
const laneACoversAll = dynamicHostStyleProperties !== null && laneAEntries.length === dynamicStyleEntries.length;
|
|
1314
|
+
const webClassEntries = dynamicHostStyleProperties === null ? dynamicStyleEntries : dynamicStyleEntries.filter((entry) => !laneAEntries.includes(entry));
|
|
1315
|
+
const supportsWebConditionalClasses = platform === "web" && !options.disablePartialExtraction && (input.element.form === "jsx" || input.element.propsSpan !== null) && !laneACoversAll && webClassEntries.length > 0 && webClassEntries.every((entry) => conditionalClassEntry(entry, component));
|
|
1251
1316
|
const themeEntry = componentOnlyProp("theme");
|
|
1252
1317
|
const themeInverseEntry = componentOnlyProp("themeInverse");
|
|
1253
1318
|
const themeBoundary = themeEntry.unknown || "theme" in props;
|
|
@@ -1271,7 +1336,7 @@ function createTamaguiCompilerHost(options) {
|
|
|
1271
1336
|
message: zeroRuleMessage(5, { detail: `the animation configured on ${input.element.component.name}` })
|
|
1272
1337
|
});
|
|
1273
1338
|
}
|
|
1274
|
-
if (platform === "web" && (dynamicStyleEntries.length > 0 || runtimeAnimationRequired) &&
|
|
1339
|
+
if (platform === "web" && (dynamicStyleEntries.length > 0 || runtimeAnimationRequired) && !laneACoversAll && !supportsWebConditionalClasses && component.partialRuntimeSafe) {
|
|
1275
1340
|
const hasSpread = input.element.entries.some((entry) => entry.kind === "spread" && entry.value.kind !== "static");
|
|
1276
1341
|
const unsupportedRuntimeStyle = input.element.entries.find((entry) => entry.kind === "prop" && isStyleProp(entry.name, component) && !runtimeAnimationProps.has(entry.name) && !directStyleName(entry.name, component));
|
|
1277
1342
|
if (!hasSpread && !unsupportedRuntimeStyle) {
|
|
@@ -1355,7 +1420,7 @@ function createTamaguiCompilerHost(options) {
|
|
|
1355
1420
|
});
|
|
1356
1421
|
}
|
|
1357
1422
|
const supportsNativeDynamicStyles = platform === "native" && !options.disablePartialExtraction && (input.element.form === "jsx" || input.element.propsSpan !== null) && dynamicStyleEntries.every((entry) => entry.kind === "prop" && (directStyleName(entry.name, component) === "opacity" || entry.value.kind === "conditional" && canLowerConditionalStyleProp(entry.name, component)));
|
|
1358
|
-
if (dynamicStyleEntries.length > 0 &&
|
|
1423
|
+
if (dynamicStyleEntries.length > 0 && !laneACoversAll && !supportsNativeDynamicStyles && !supportsWebConditionalClasses) {
|
|
1359
1424
|
const entry = dynamicStyleEntries[0];
|
|
1360
1425
|
return bailout(input, "local/dynamic-style-value", `Style prop ${entry.kind === "prop" ? entry.name : "unknown"} could not be safely extracted`, entry.span);
|
|
1361
1426
|
}
|
|
@@ -1372,6 +1437,13 @@ function createTamaguiCompilerHost(options) {
|
|
|
1372
1437
|
}
|
|
1373
1438
|
const propsForConditional = (target, value) => {
|
|
1374
1439
|
const branchProps = {};
|
|
1440
|
+
if (styleObjectStatic) branchProps.style = styleObjectStatic;
|
|
1441
|
+
if (target.styleMember) {
|
|
1442
|
+
branchProps.style = {
|
|
1443
|
+
...styleObjectStatic,
|
|
1444
|
+
[target.name]: value
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1375
1447
|
for (const entry of input.element.entries) {
|
|
1376
1448
|
if (entry === target) {
|
|
1377
1449
|
branchProps[target.name] = value;
|
|
@@ -1980,22 +2052,22 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
|
|
|
1980
2052
|
const staticClasses = new Set(baseStaticClasses);
|
|
1981
2053
|
const webConditionalCSS = [];
|
|
1982
2054
|
const webConditionalKeys = /* @__PURE__ */ new Set();
|
|
1983
|
-
const webConditionalEntries = supportsWebConditionalClasses ?
|
|
2055
|
+
const webConditionalEntries = supportsWebConditionalClasses ? webClassEntries : [];
|
|
1984
2056
|
for (const entry of webConditionalEntries) {
|
|
1985
2057
|
let serializeWebTree = function(node) {
|
|
1986
|
-
if (node.kind === "leaf")
|
|
1987
|
-
const artifacts2 = leafArtifactsMap.get(node);
|
|
1988
|
-
const only = artifacts2 ? artifacts2.classes.filter((item) => !sharedInConditional.has(item)) : [];
|
|
1989
|
-
return JSON.stringify(only.join(" "));
|
|
1990
|
-
}
|
|
2058
|
+
if (node.kind === "leaf") return JSON.stringify(leafClasses(node));
|
|
1991
2059
|
const test = input.source.slice(node.test.start, node.test.end);
|
|
1992
2060
|
const truePart = serializeWebTree(node.whenTrue);
|
|
1993
2061
|
const falsePart = serializeWebTree(node.whenFalse);
|
|
1994
2062
|
return `(${test}) ? ${truePart} : ${falsePart}`;
|
|
1995
2063
|
};
|
|
1996
|
-
|
|
1997
|
-
const
|
|
1998
|
-
|
|
2064
|
+
const tree = entry.value.kind === "conditional" ? entry.value.tree : null;
|
|
2065
|
+
const domain = frontendClassDomain(entry, component);
|
|
2066
|
+
if (!tree && !domain) continue;
|
|
2067
|
+
const leaves = tree ? collectLeaves(tree) : domain.map((value) => ({
|
|
2068
|
+
value,
|
|
2069
|
+
dependencies: []
|
|
2070
|
+
}));
|
|
1999
2071
|
const leafArtifactsMap = /* @__PURE__ */ new Map();
|
|
2000
2072
|
const entryConditionalKeys = /* @__PURE__ */ new Set();
|
|
2001
2073
|
for (const leaf of leaves) {
|
|
@@ -2031,6 +2103,9 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
|
|
|
2031
2103
|
}
|
|
2032
2104
|
entryConditionalKeys.add(key);
|
|
2033
2105
|
}
|
|
2106
|
+
if (conflictsWithInline(changedKeys, laneAOwners, laneAMemberOwners)) {
|
|
2107
|
+
return bailout(input, "local/dynamic-style-value", `${entry.name} and an inline dynamic style both contribute a CSS property; their precedence cannot be resolved per-branch`, entry.value.span);
|
|
2108
|
+
}
|
|
2034
2109
|
const branchArtifacts = extractedStyleArtifacts(branchSplit, branchProps, options.tamaguiConfig, !component.domTag, Boolean(component.staticConfig.styleFrontend));
|
|
2035
2110
|
leafArtifactsMap.set(leaf, {
|
|
2036
2111
|
classes: branchArtifacts.className.split(" ").filter(Boolean),
|
|
@@ -2049,8 +2124,18 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
|
|
|
2049
2124
|
for (const cls of sharedInConditional) {
|
|
2050
2125
|
if (!baseStaticClasses.has(cls)) staticClasses.add(cls);
|
|
2051
2126
|
}
|
|
2052
|
-
const
|
|
2053
|
-
|
|
2127
|
+
const leafClasses = (leaf) => {
|
|
2128
|
+
const artifacts2 = leafArtifactsMap.get(leaf);
|
|
2129
|
+
const only = artifacts2 ? artifacts2.classes.filter((item) => !sharedInConditional.has(item)) : [];
|
|
2130
|
+
return only.join(" ");
|
|
2131
|
+
};
|
|
2132
|
+
if (tree) {
|
|
2133
|
+
programClassSources.push(serializeWebTree(tree));
|
|
2134
|
+
} else {
|
|
2135
|
+
const table = Object.fromEntries(leaves.map((leaf) => [leaf.value, leafClasses(leaf)]));
|
|
2136
|
+
const key = input.source.slice(entry.value.span.start, entry.value.span.end);
|
|
2137
|
+
programClassSources.push(`(${JSON.stringify(table)})[${key}]`);
|
|
2138
|
+
}
|
|
2054
2139
|
}
|
|
2055
2140
|
const webClassName = [...staticClasses].join(" ");
|
|
2056
2141
|
const hasStyleProgram = programClassSources.length > 0;
|