@tamagui/static 3.0.0-beta.807.1 → 3.0.0-beta.881.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/compiler.cjs +17 -5
- package/dist/cjs/compilerHost.cjs +164 -50
- package/dist/cjs/componentDiscovery.cjs +90 -0
- package/dist/cjs/domStructuralPass.cjs +16 -6
- package/dist/cjs/exports.cjs +4 -1
- package/dist/cjs/extractor/bundleConfig.cjs +23 -0
- package/dist/cjs/staticEvaluationIgnoredModules.cjs +1 -1
- package/dist/cjs/zero/theme.cjs +5 -20
- package/dist/esm/compiler.mjs +18 -6
- package/dist/esm/compiler.mjs.map +1 -1
- package/dist/esm/compilerHost.mjs +162 -51
- package/dist/esm/compilerHost.mjs.map +1 -1
- package/dist/esm/componentDiscovery.mjs +65 -0
- package/dist/esm/componentDiscovery.mjs.map +1 -0
- package/dist/esm/domStructuralPass.mjs +16 -6
- package/dist/esm/domStructuralPass.mjs.map +1 -1
- package/dist/esm/exports.mjs +4 -1
- package/dist/esm/extractor/bundleConfig.mjs +23 -1
- package/dist/esm/extractor/bundleConfig.mjs.map +1 -1
- package/dist/esm/staticEvaluationIgnoredModules.mjs +1 -1
- package/dist/esm/staticEvaluationIgnoredModules.mjs.map +1 -1
- package/dist/esm/zero/theme.mjs +5 -20
- package/dist/esm/zero/theme.mjs.map +1 -1
- package/package.json +17 -17
- package/src/compiler.ts +27 -5
- package/src/compilerHost.ts +274 -105
- package/src/componentDiscovery.ts +95 -0
- package/src/domStructuralPass.ts +26 -6
- package/src/exports.ts +2 -0
- package/src/extractor/bundleConfig.ts +34 -0
- package/src/staticEvaluationIgnoredModules.ts +1 -1
- package/src/zero/theme.ts +12 -21
- package/types/compiler.d.ts +13 -0
- package/types/compiler.d.ts.map +1 -1
- package/types/compilerHost.d.ts +13 -0
- package/types/compilerHost.d.ts.map +1 -1
- package/types/componentDiscovery.d.ts +27 -0
- package/types/componentDiscovery.d.ts.map +1 -0
- package/types/domStructuralPass.d.ts.map +1 -1
- package/types/exports.d.ts +2 -0
- package/types/exports.d.ts.map +1 -1
- package/types/extractor/bundleConfig.d.ts +7 -0
- package/types/extractor/bundleConfig.d.ts.map +1 -1
- package/types/zero/theme.d.ts +0 -1
- package/types/zero/theme.d.ts.map +1 -1
package/src/compilerHost.ts
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
StyleObjectRules,
|
|
22
22
|
StyleObjectValue,
|
|
23
23
|
stylePropsAll,
|
|
24
|
+
stylePropsInput,
|
|
24
25
|
stylePropsText,
|
|
25
26
|
validStyles as validStylesView,
|
|
26
27
|
} from '@tamagui/helpers'
|
|
@@ -55,11 +56,38 @@ export interface CompilerComponentModule {
|
|
|
55
56
|
resolvedId: string
|
|
56
57
|
}
|
|
57
58
|
|
|
59
|
+
/**
|
|
60
|
+
* The components lowering can resolve, keyed the way element provenance names
|
|
61
|
+
* them. The frontend owns one per compile and grows it as it discovers component
|
|
62
|
+
* modules outside the configured `components` list.
|
|
63
|
+
*/
|
|
64
|
+
export interface CompilerComponentRegistry {
|
|
65
|
+
/** host-resolved module id -> the module name its components register under */
|
|
66
|
+
modulesById: Map<string, string>
|
|
67
|
+
componentsByModule: Map<string, LoadedComponents>
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function createComponentRegistry(
|
|
71
|
+
components: readonly LoadedComponents[],
|
|
72
|
+
componentModules: readonly CompilerComponentModule[]
|
|
73
|
+
): CompilerComponentRegistry {
|
|
74
|
+
return {
|
|
75
|
+
modulesById: new Map(
|
|
76
|
+
componentModules.map((module) => [module.resolvedId, module.moduleName])
|
|
77
|
+
),
|
|
78
|
+
componentsByModule: new Map(
|
|
79
|
+
components.map((component) => [component.moduleName, component])
|
|
80
|
+
),
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
58
84
|
export interface TamaguiCompilerHostOptions {
|
|
59
85
|
target: CompilerTarget
|
|
60
86
|
tamaguiConfig: TamaguiInternalConfig
|
|
61
87
|
components: LoadedComponents[]
|
|
62
88
|
componentModules: CompilerComponentModule[]
|
|
89
|
+
/** shared with the frontend so discovery during `prepare` is visible to this host */
|
|
90
|
+
registry?: CompilerComponentRegistry
|
|
63
91
|
/** Keep elements with dynamic style props fully on the runtime path. */
|
|
64
92
|
disablePartialExtraction?: boolean
|
|
65
93
|
/** emit native theme-token mappings for the native style engine */
|
|
@@ -390,6 +418,11 @@ const runtimeAnimationProps = new Set([
|
|
|
390
418
|
'animatedBy',
|
|
391
419
|
])
|
|
392
420
|
|
|
421
|
+
// createComponent reads these and never forwards them to the host element, so a
|
|
422
|
+
// flattened element has to drop them instead of emitting an unknown attribute.
|
|
423
|
+
// only the inert values reach the emit: an active one already bailed.
|
|
424
|
+
const componentOnlyProps = new Set(['asChild', 'disableOptimization', 'themeInverse'])
|
|
425
|
+
|
|
393
426
|
const cssShorthandConflicts: Record<string, readonly string[]> = {
|
|
394
427
|
background: [
|
|
395
428
|
'backgroundAttachment',
|
|
@@ -548,6 +581,12 @@ const cssShorthandConflicts: Record<string, readonly string[]> = {
|
|
|
548
581
|
}
|
|
549
582
|
|
|
550
583
|
const cssConflictFamilies = [
|
|
584
|
+
new Set(['width', 'inlineSize']),
|
|
585
|
+
new Set(['minWidth', 'minInlineSize']),
|
|
586
|
+
new Set(['maxWidth', 'maxInlineSize']),
|
|
587
|
+
new Set(['height', 'blockSize']),
|
|
588
|
+
new Set(['minHeight', 'minBlockSize']),
|
|
589
|
+
new Set(['maxHeight', 'maxBlockSize']),
|
|
551
590
|
new Set([
|
|
552
591
|
'marginInline',
|
|
553
592
|
'marginInlineEnd',
|
|
@@ -759,9 +798,9 @@ function nativeDOMProps(input: LoweringCandidateInput, tag: TagName) {
|
|
|
759
798
|
for (const entry of entries) {
|
|
760
799
|
const value = entrySource(input, entry)
|
|
761
800
|
const attribute =
|
|
762
|
-
(
|
|
801
|
+
(entry.name in ATTRIBUTES ? ATTRIBUTES[entry.name] : undefined) ??
|
|
763
802
|
(entry.name.startsWith('data-') ? ATTRIBUTES['data-*'] : undefined)
|
|
764
|
-
const event =
|
|
803
|
+
const event = entry.name in EVENTS ? EVENTS[entry.name] : undefined
|
|
765
804
|
if (event) {
|
|
766
805
|
if (event.native === 'none') {
|
|
767
806
|
return {
|
|
@@ -943,6 +982,8 @@ export function createTamaguiCompilerHost(
|
|
|
943
982
|
): CompilerLoweringHost {
|
|
944
983
|
const platform = options.target === 'native' ? 'native' : 'web'
|
|
945
984
|
const core = requireTamaguiCore(platform) as any
|
|
985
|
+
const compilerVariantStyleResolver = core.styled(core.View, {}).staticConfig
|
|
986
|
+
.variantStyleResolver
|
|
946
987
|
const firstThemeName = Object.keys(options.tamaguiConfig.themes ?? {})[0] ?? ''
|
|
947
988
|
const firstTheme = options.tamaguiConfig.themes?.[firstThemeName] ?? {}
|
|
948
989
|
const theme = firstTheme
|
|
@@ -968,6 +1009,39 @@ export function createTamaguiCompilerHost(
|
|
|
968
1009
|
}
|
|
969
1010
|
return false
|
|
970
1011
|
}
|
|
1012
|
+
// A native bundle knows one thing about its platform: it is not web. So a
|
|
1013
|
+
// `web:` clause can never match there and a bare `native:` clause always
|
|
1014
|
+
// does, which makes a value built only from those two resolvable at compile
|
|
1015
|
+
// time. Every other modifier is live at render: media and container queries
|
|
1016
|
+
// measure, theme and group clauses read context, state and lifecycle clauses
|
|
1017
|
+
// track the component, and the device platforms (ios, android, tv) are not
|
|
1018
|
+
// known until the bundle runs. One of those anywhere in the value keeps the
|
|
1019
|
+
// whole element on the runtime path.
|
|
1020
|
+
const platformModifiersRegistered =
|
|
1021
|
+
modifierRegistry.get('web') === 'platform' &&
|
|
1022
|
+
modifierRegistry.get('native') === 'platform'
|
|
1023
|
+
const nativeClauseValue = (
|
|
1024
|
+
value: unknown
|
|
1025
|
+
): 'live' | { payload: unknown; matched: boolean } | null => {
|
|
1026
|
+
if (typeof value !== 'string' || !flatClausePattern.test(value)) {
|
|
1027
|
+
return isClauseObjectValue(value) ? 'live' : null
|
|
1028
|
+
}
|
|
1029
|
+
if (!platformModifiersRegistered) return 'live'
|
|
1030
|
+
const parsed = parseValue(value, modifierRegistry)
|
|
1031
|
+
if (!parsed.ok || parsed.value.clauses.length === 0) return 'live'
|
|
1032
|
+
let payload: unknown = parsed.value.base
|
|
1033
|
+
let matched = parsed.value.base !== null
|
|
1034
|
+
for (const clause of parsed.value.clauses) {
|
|
1035
|
+
// a chain containing `web` is dead here whatever else it names
|
|
1036
|
+
if (clause.modifiers.includes('web')) continue
|
|
1037
|
+
if (clause.modifiers.length !== 1 || clause.modifiers[0] !== 'native') return 'live'
|
|
1038
|
+
// platform clauses all rank the same, so a later one wins and any of them
|
|
1039
|
+
// beats the unconditional base
|
|
1040
|
+
payload = clause.payload
|
|
1041
|
+
matched = true
|
|
1042
|
+
}
|
|
1043
|
+
return { payload, matched }
|
|
1044
|
+
}
|
|
971
1045
|
const configuredAnimationDriver = options.tamaguiConfig.animations as
|
|
972
1046
|
| AnimationDriver
|
|
973
1047
|
| undefined
|
|
@@ -1031,25 +1105,31 @@ export function createTamaguiCompilerHost(
|
|
|
1031
1105
|
}
|
|
1032
1106
|
return resolved.join(' ')
|
|
1033
1107
|
}
|
|
1034
|
-
const modulesById
|
|
1035
|
-
options.
|
|
1036
|
-
|
|
1037
|
-
const componentsByModule = new Map(
|
|
1038
|
-
options.components.map((component) => [component.moduleName, component])
|
|
1039
|
-
)
|
|
1108
|
+
const { modulesById, componentsByModule } =
|
|
1109
|
+
options.registry ??
|
|
1110
|
+
createComponentRegistry(options.components, options.componentModules)
|
|
1040
1111
|
|
|
1041
1112
|
// A component's import provenance chose its authoring syntax, and the frontend
|
|
1042
1113
|
// descriptor frozen onto its static config is the only thing that knows how to
|
|
1043
|
-
// resolve that syntax's static input (a class-string base, string variants
|
|
1044
|
-
//
|
|
1114
|
+
// resolve that syntax's static input (a class-string base, string variants) into
|
|
1115
|
+
// styles. Regular Tamagui components carry no descriptor
|
|
1045
1116
|
// because their static config is already the renderer's input shape. The compiler
|
|
1046
1117
|
// must never import a frontend package: `@tamagui/tailwind/vite` already depends on
|
|
1047
1118
|
// the static compiler, so reaching the other way would be a cycle.
|
|
1048
|
-
const
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1119
|
+
const normalizedStyleConfigs = new WeakMap<StaticConfig, any>()
|
|
1120
|
+
const normalizeStaticConfig = (staticConfig: StaticConfig): StaticConfig => {
|
|
1121
|
+
if (!staticConfig.styleFrontend) return staticConfig
|
|
1122
|
+
const normalized = core.getStyleStaticConfig(staticConfig, options.tamaguiConfig)
|
|
1123
|
+
const result = {
|
|
1124
|
+
...staticConfig,
|
|
1125
|
+
baseStyle: normalized.baseStyle,
|
|
1126
|
+
defaultProps: normalized.defaultProps,
|
|
1127
|
+
variants: normalized.variants,
|
|
1128
|
+
passthroughClassName: normalized.passthroughClassName,
|
|
1129
|
+
}
|
|
1130
|
+
normalizedStyleConfigs.set(result, normalized)
|
|
1131
|
+
return result
|
|
1132
|
+
}
|
|
1053
1133
|
|
|
1054
1134
|
const directStaticConfig = (
|
|
1055
1135
|
element: MaterializedElement
|
|
@@ -1081,7 +1161,7 @@ export function createTamaguiCompilerHost(
|
|
|
1081
1161
|
if (
|
|
1082
1162
|
identity?.importedName !== 'html' ||
|
|
1083
1163
|
!DOM_FRONTENDS.has(identity.specifier) ||
|
|
1084
|
-
!
|
|
1164
|
+
!(tag in TAGS)
|
|
1085
1165
|
) {
|
|
1086
1166
|
return null
|
|
1087
1167
|
}
|
|
@@ -1113,7 +1193,10 @@ export function createTamaguiCompilerHost(
|
|
|
1113
1193
|
isInput: row.backing === 'textinput',
|
|
1114
1194
|
// CSS text properties may be authored on any element and inherited by
|
|
1115
1195
|
// descendant text, including from a View-backed tag on native.
|
|
1116
|
-
validStyles: {
|
|
1196
|
+
validStyles: {
|
|
1197
|
+
...validStylesView,
|
|
1198
|
+
...(row.backing === 'textinput' ? stylePropsInput : stylePropsText),
|
|
1199
|
+
},
|
|
1117
1200
|
defaultProps: {
|
|
1118
1201
|
...base.defaultProps,
|
|
1119
1202
|
...platformDefaults,
|
|
@@ -1141,7 +1224,6 @@ export function createTamaguiCompilerHost(
|
|
|
1141
1224
|
const {
|
|
1142
1225
|
variants,
|
|
1143
1226
|
defaultVariants,
|
|
1144
|
-
compoundVariants,
|
|
1145
1227
|
displayName,
|
|
1146
1228
|
context,
|
|
1147
1229
|
contextProps,
|
|
@@ -1152,33 +1234,31 @@ export function createTamaguiCompilerHost(
|
|
|
1152
1234
|
typeof definition.baseClassName.value === 'string'
|
|
1153
1235
|
? definition.baseClassName.value
|
|
1154
1236
|
: undefined
|
|
1237
|
+
const localStaticConfig = {
|
|
1238
|
+
...base.staticConfig,
|
|
1239
|
+
variants: {
|
|
1240
|
+
...base.staticConfig.variants,
|
|
1241
|
+
...(variants as object | undefined),
|
|
1242
|
+
},
|
|
1243
|
+
defaultProps: {
|
|
1244
|
+
...base.staticConfig.defaultProps,
|
|
1245
|
+
...defaultProps,
|
|
1246
|
+
...(defaultVariants as object | undefined),
|
|
1247
|
+
},
|
|
1248
|
+
defaultVariants,
|
|
1249
|
+
baseClassName: [base.staticConfig.baseClassName, baseClassName]
|
|
1250
|
+
.filter(Boolean)
|
|
1251
|
+
.join(' '),
|
|
1252
|
+
context: context ?? base.staticConfig.context,
|
|
1253
|
+
contextProps: context
|
|
1254
|
+
? contextProps
|
|
1255
|
+
: (contextProps ?? base.staticConfig.contextProps),
|
|
1256
|
+
}
|
|
1257
|
+
;(localStaticConfig as any).variantStyleResolver = compilerVariantStyleResolver
|
|
1155
1258
|
return {
|
|
1156
1259
|
key: componentKey(definition.id, definition.name),
|
|
1157
1260
|
displayName: displayName || base.displayName,
|
|
1158
|
-
staticConfig: normalizeStaticConfig(
|
|
1159
|
-
...base.staticConfig,
|
|
1160
|
-
variants: {
|
|
1161
|
-
...base.staticConfig.variants,
|
|
1162
|
-
...(variants as object | undefined),
|
|
1163
|
-
},
|
|
1164
|
-
compoundVariants: [
|
|
1165
|
-
...(base.staticConfig.compoundVariants ?? []),
|
|
1166
|
-
...(compoundVariants ?? []),
|
|
1167
|
-
],
|
|
1168
|
-
defaultProps: {
|
|
1169
|
-
...base.staticConfig.defaultProps,
|
|
1170
|
-
...defaultProps,
|
|
1171
|
-
...(defaultVariants as object | undefined),
|
|
1172
|
-
},
|
|
1173
|
-
defaultVariants,
|
|
1174
|
-
baseClassName: [base.staticConfig.baseClassName, baseClassName]
|
|
1175
|
-
.filter(Boolean)
|
|
1176
|
-
.join(' '),
|
|
1177
|
-
context: context ?? base.staticConfig.context,
|
|
1178
|
-
contextProps: context
|
|
1179
|
-
? contextProps
|
|
1180
|
-
: (contextProps ?? base.staticConfig.contextProps),
|
|
1181
|
-
}),
|
|
1261
|
+
staticConfig: normalizeStaticConfig(localStaticConfig),
|
|
1182
1262
|
}
|
|
1183
1263
|
}
|
|
1184
1264
|
|
|
@@ -1190,7 +1270,7 @@ export function createTamaguiCompilerHost(
|
|
|
1190
1270
|
const resolved =
|
|
1191
1271
|
dom ?? styledStaticConfig(styledDefinition) ?? directStaticConfig(element)
|
|
1192
1272
|
if (!resolved) return null
|
|
1193
|
-
const defaultProps =
|
|
1273
|
+
const defaultProps = resolved.staticConfig.defaultProps ?? {}
|
|
1194
1274
|
return {
|
|
1195
1275
|
key: resolved.key,
|
|
1196
1276
|
canFlatten:
|
|
@@ -1209,8 +1289,7 @@ export function createTamaguiCompilerHost(
|
|
|
1209
1289
|
Object.keys(defaultProps).length === 0 &&
|
|
1210
1290
|
!resolved.staticConfig.defaultVariants &&
|
|
1211
1291
|
!resolved.staticConfig.baseClassName &&
|
|
1212
|
-
!resolved.staticConfig.baseStyle
|
|
1213
|
-
(resolved.staticConfig.compoundVariants?.length ?? 0) === 0,
|
|
1292
|
+
!resolved.staticConfig.baseStyle,
|
|
1214
1293
|
}
|
|
1215
1294
|
}
|
|
1216
1295
|
|
|
@@ -1251,10 +1330,12 @@ export function createTamaguiCompilerHost(
|
|
|
1251
1330
|
const staticConfig = component.staticConfig as StaticConfig
|
|
1252
1331
|
const validStyles =
|
|
1253
1332
|
staticConfig.validStyles ||
|
|
1254
|
-
(staticConfig.
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1333
|
+
(staticConfig.isInput
|
|
1334
|
+
? stylePropsInput
|
|
1335
|
+
: staticConfig.isText
|
|
1336
|
+
? stylePropsText
|
|
1337
|
+
: validStylesView)
|
|
1338
|
+
return name in stylePropsAll && !isValidStyleKey(name, validStyles)
|
|
1258
1339
|
}
|
|
1259
1340
|
|
|
1260
1341
|
const directStyleName = (name: string, component: LoweringComponent): string | null => {
|
|
@@ -1282,7 +1363,6 @@ export function createTamaguiCompilerHost(
|
|
|
1282
1363
|
}
|
|
1283
1364
|
process.env.TAMAGUI_TARGET = platform
|
|
1284
1365
|
try {
|
|
1285
|
-
core.prepareStyleStaticConfig(staticConfig)
|
|
1286
1366
|
return core.getSplitStyles(
|
|
1287
1367
|
props,
|
|
1288
1368
|
staticConfig,
|
|
@@ -1290,6 +1370,7 @@ export function createTamaguiCompilerHost(
|
|
|
1290
1370
|
firstThemeName,
|
|
1291
1371
|
componentState,
|
|
1292
1372
|
{
|
|
1373
|
+
isStatic: true,
|
|
1293
1374
|
resolveValues: platform === 'native' ? 'except-theme' : 'variable',
|
|
1294
1375
|
noClass: platform === 'native',
|
|
1295
1376
|
isAnimated: false,
|
|
@@ -1301,7 +1382,8 @@ export function createTamaguiCompilerHost(
|
|
|
1301
1382
|
undefined,
|
|
1302
1383
|
undefined,
|
|
1303
1384
|
undefined,
|
|
1304
|
-
animationDriver
|
|
1385
|
+
animationDriver,
|
|
1386
|
+
normalizedStyleConfigs.get(staticConfig)
|
|
1305
1387
|
)
|
|
1306
1388
|
} finally {
|
|
1307
1389
|
if (previousStatic === undefined) delete process.env.IS_STATIC
|
|
@@ -1316,7 +1398,6 @@ export function createTamaguiCompilerHost(
|
|
|
1316
1398
|
baseStyle: undefined,
|
|
1317
1399
|
defaultProps: {},
|
|
1318
1400
|
defaultVariants: undefined,
|
|
1319
|
-
compoundVariants: [],
|
|
1320
1401
|
variants: {},
|
|
1321
1402
|
})
|
|
1322
1403
|
|
|
@@ -1499,6 +1580,12 @@ export function createTamaguiCompilerHost(
|
|
|
1499
1580
|
) {
|
|
1500
1581
|
return true
|
|
1501
1582
|
}
|
|
1583
|
+
// A component resolver receives the complete props object. Without a
|
|
1584
|
+
// compiler-derived read set, resolving an opaque dynamic callsite would
|
|
1585
|
+
// execute the real resolver with an incomplete props snapshot.
|
|
1586
|
+
if ((component.staticConfig as StaticConfig).resolvers?.length) {
|
|
1587
|
+
return false
|
|
1588
|
+
}
|
|
1502
1589
|
return (
|
|
1503
1590
|
!options.disablePartialExtraction &&
|
|
1504
1591
|
((platform === 'web' && !!directStyleName(name, component)) ||
|
|
@@ -1554,15 +1641,56 @@ export function createTamaguiCompilerHost(
|
|
|
1554
1641
|
props[entry.name] = entry.value.value
|
|
1555
1642
|
}
|
|
1556
1643
|
}
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1644
|
+
if (component.staticConfig.resolvers?.length) {
|
|
1645
|
+
const unresolvedProps = input.element.entries.filter(
|
|
1646
|
+
(entry) => entry.kind === 'prop' && entry.value.kind !== 'static'
|
|
1647
|
+
)
|
|
1648
|
+
// One conditional with static leaves is still a complete prop set:
|
|
1649
|
+
// lowerCandidate evaluates the full resolver chain once per branch.
|
|
1650
|
+
// Multiple unknown props would require a cross-product/read set, so
|
|
1651
|
+
// they remain on the runtime path.
|
|
1652
|
+
const onlyStaticBranchConditional =
|
|
1653
|
+
unresolvedProps.length === 1 &&
|
|
1654
|
+
unresolvedProps[0]?.kind === 'prop' &&
|
|
1655
|
+
unresolvedProps[0].value.kind === 'conditional' &&
|
|
1656
|
+
canLowerConditionalStyleProp(unresolvedProps[0].name, component)
|
|
1657
|
+
const unresolvedProp = onlyStaticBranchConditional
|
|
1658
|
+
? undefined
|
|
1659
|
+
: unresolvedProps[0]
|
|
1660
|
+
if (unresolvedProp?.kind === 'prop') {
|
|
1661
|
+
return bailout(
|
|
1662
|
+
input,
|
|
1663
|
+
'local/dynamic-style-value',
|
|
1664
|
+
`Component resolver prop ${unresolvedProp.name} could not be evaluated`,
|
|
1665
|
+
unresolvedProp.span,
|
|
1666
|
+
undefined,
|
|
1667
|
+
unresolvedProp.name
|
|
1668
|
+
)
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
// asChild, disableOptimization and themeInverse each asked only whether the
|
|
1672
|
+
// prop was PRESENT, so a false value retained a component that requested
|
|
1673
|
+
// none of the runtime behavior the branch exists for. read the materialized
|
|
1674
|
+
// value instead, and treat a prop the compiler could not evaluate as active.
|
|
1675
|
+
// a later duplicate wins, so the last entry decides and any unevaluated
|
|
1676
|
+
// entry for that name makes the answer unknown.
|
|
1677
|
+
const componentOnlyProp = (name: string) => {
|
|
1678
|
+
let span: MaterializedElement['entries'][number]['span'] | undefined
|
|
1679
|
+
let unknown = false
|
|
1680
|
+
for (const entry of input.element.entries) {
|
|
1681
|
+
if (entry.kind !== 'prop' || entry.name !== name) continue
|
|
1682
|
+
span = entry.span
|
|
1683
|
+
if (entry.value.kind !== 'static') unknown = true
|
|
1684
|
+
}
|
|
1685
|
+
return { unknown, span }
|
|
1686
|
+
}
|
|
1687
|
+
const disableOptimization = componentOnlyProp('disableOptimization')
|
|
1688
|
+
if (disableOptimization.unknown || props.disableOptimization) {
|
|
1561
1689
|
return bailout(
|
|
1562
1690
|
input,
|
|
1563
1691
|
'local/unsupported-target',
|
|
1564
1692
|
'disableOptimization keeps the component on the runtime path',
|
|
1565
|
-
|
|
1693
|
+
disableOptimization.span
|
|
1566
1694
|
)
|
|
1567
1695
|
}
|
|
1568
1696
|
if (component.domTag && props.hidden) props.display = 'none'
|
|
@@ -1628,7 +1756,7 @@ export function createTamaguiCompilerHost(
|
|
|
1628
1756
|
// had never been written: the element flattened and the prop was dropped
|
|
1629
1757
|
// with no diagnostic. Same merge function and same precedence as
|
|
1630
1758
|
// completeProps, so there is one answer to "what is this prop's value".
|
|
1631
|
-
const animationDefaultProps =
|
|
1759
|
+
const animationDefaultProps = component.staticConfig.defaultProps ?? {}
|
|
1632
1760
|
const animationProps = core.mergeProps(animationDefaultProps, props)
|
|
1633
1761
|
const animationNames = new Set([
|
|
1634
1762
|
...input.element.entries.flatMap((entry) =>
|
|
@@ -1759,11 +1887,7 @@ export function createTamaguiCompilerHost(
|
|
|
1759
1887
|
name === 'opacity'
|
|
1760
1888
|
? `opacity: (${expression})`
|
|
1761
1889
|
: `transform: "scale(" + (${expression}) + ")"`
|
|
1762
|
-
} else if (
|
|
1763
|
-
entry.value.kind === 'bailout' &&
|
|
1764
|
-
owners.size === 1 &&
|
|
1765
|
-
owners.has(name)
|
|
1766
|
-
) {
|
|
1890
|
+
} else if (entry.value.kind === 'bailout' && owners.has(name)) {
|
|
1767
1891
|
const dynamic = entry.value.dynamic
|
|
1768
1892
|
if (dynamic?.type === 'number') {
|
|
1769
1893
|
property = `${JSON.stringify(name)}: (${expression})`
|
|
@@ -1829,8 +1953,13 @@ export function createTamaguiCompilerHost(
|
|
|
1829
1953
|
entry.value.kind === 'conditional' &&
|
|
1830
1954
|
canLowerConditionalStyleProp(entry.name, component)
|
|
1831
1955
|
)
|
|
1832
|
-
|
|
1833
|
-
|
|
1956
|
+
// a theme name of any value selects a theme, while themeInverse only opens a
|
|
1957
|
+
// boundary when it is on
|
|
1958
|
+
const themeEntry = componentOnlyProp('theme')
|
|
1959
|
+
const themeInverseEntry = componentOnlyProp('themeInverse')
|
|
1960
|
+
const themeBoundary = themeEntry.unknown || 'theme' in props
|
|
1961
|
+
if (themeBoundary || themeInverseEntry.unknown || props.themeInverse) {
|
|
1962
|
+
const themeProp = themeBoundary ? 'theme' : 'themeInverse'
|
|
1834
1963
|
return bailout(
|
|
1835
1964
|
input,
|
|
1836
1965
|
'local/unsupported-target',
|
|
@@ -1846,15 +1975,13 @@ export function createTamaguiCompilerHost(
|
|
|
1846
1975
|
// the single child and emits no element of its own. a flattened host view
|
|
1847
1976
|
// would add a wrapper the runtime never renders, and the child would
|
|
1848
1977
|
// never receive the merged props. both platforms.
|
|
1849
|
-
const
|
|
1850
|
-
|
|
1851
|
-
)
|
|
1852
|
-
if (asChildEntry || Object.hasOwn(props, 'asChild')) {
|
|
1978
|
+
const asChild = componentOnlyProp('asChild')
|
|
1979
|
+
if (asChild.unknown || props.asChild) {
|
|
1853
1980
|
return bailout(
|
|
1854
1981
|
input,
|
|
1855
1982
|
'local/unsupported-target',
|
|
1856
1983
|
'asChild renders a Slot, not a host view',
|
|
1857
|
-
|
|
1984
|
+
asChild.span
|
|
1858
1985
|
)
|
|
1859
1986
|
}
|
|
1860
1987
|
// group and container props publish separate keys in the same context:
|
|
@@ -2045,7 +2172,11 @@ export function createTamaguiCompilerHost(
|
|
|
2045
2172
|
entry.span
|
|
2046
2173
|
)
|
|
2047
2174
|
}
|
|
2048
|
-
const
|
|
2175
|
+
const resolvedStyleStaticConfig = core.getStyleStaticConfig(
|
|
2176
|
+
component.staticConfig,
|
|
2177
|
+
core.getConfig()
|
|
2178
|
+
)
|
|
2179
|
+
const staticDefaultProps = resolvedStyleStaticConfig.defaultProps ?? {}
|
|
2049
2180
|
const defaultProps =
|
|
2050
2181
|
platform === 'web' &&
|
|
2051
2182
|
!component.staticConfig.isText &&
|
|
@@ -2060,6 +2191,19 @@ export function createTamaguiCompilerHost(
|
|
|
2060
2191
|
props
|
|
2061
2192
|
)
|
|
2062
2193
|
}
|
|
2194
|
+
const domStyleProgram = input.element.entries.find(
|
|
2195
|
+
(entry) =>
|
|
2196
|
+
entry.kind === 'prop' &&
|
|
2197
|
+
entry.name === 'style' &&
|
|
2198
|
+
entry.value.kind === 'dom-style'
|
|
2199
|
+
)
|
|
2200
|
+
if (platform === 'native' && !component.domTag && domStyleProgram) {
|
|
2201
|
+
return bailout(
|
|
2202
|
+
input,
|
|
2203
|
+
'local/unsupported-target',
|
|
2204
|
+
'Native style() pieces remain on the runtime path'
|
|
2205
|
+
)
|
|
2206
|
+
}
|
|
2063
2207
|
const propsForConditional = (
|
|
2064
2208
|
target: Extract<MaterializedElement['entries'][number], { kind: 'prop' }>,
|
|
2065
2209
|
value: unknown
|
|
@@ -2097,22 +2241,35 @@ export function createTamaguiCompilerHost(
|
|
|
2097
2241
|
branchProps
|
|
2098
2242
|
)
|
|
2099
2243
|
: core.mergeProps(defaultProps, branchProps)
|
|
2244
|
+
// the same platform-clause reduction the unconditional props get: a
|
|
2245
|
+
// branch resolves through the full pipeline, so a clause left standing
|
|
2246
|
+
// here would be decided by the build machine instead of the bundle
|
|
2247
|
+
if (platform === 'native') {
|
|
2248
|
+
for (const [name, value] of Object.entries(branchCompleteProps)) {
|
|
2249
|
+
const clause = isStyleProp(name, component) ? nativeClauseValue(value) : null
|
|
2250
|
+
if (clause === null || clause === 'live') continue
|
|
2251
|
+
if (clause.matched) branchCompleteProps[name] = clause.payload
|
|
2252
|
+
else delete branchCompleteProps[name]
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2100
2255
|
return { branchProps, branchCompleteProps }
|
|
2101
2256
|
}
|
|
2102
|
-
//
|
|
2103
|
-
//
|
|
2104
|
-
//
|
|
2257
|
+
// native resolution evaluates clauses against the build machine's current
|
|
2258
|
+
// state, so folding a call-site, styled base, or variant clause would freeze
|
|
2259
|
+
// that state into the bundle.
|
|
2105
2260
|
if (platform === 'native') {
|
|
2106
2261
|
const isClauseValue = (name: string, value: unknown) =>
|
|
2107
2262
|
isStyleProp(name, component) &&
|
|
2108
2263
|
((typeof value === 'string' && flatClausePattern.test(value)) ||
|
|
2109
2264
|
isClauseObjectValue(value))
|
|
2110
2265
|
// a clause can also sit inside a variant definition, where it never
|
|
2111
|
-
// appears as a prop: variants: { big: { true: { width: 'gt-lg:999px' } } }
|
|
2266
|
+
// appears as a prop: variants: { big: { true: { width: 'gt-lg:999px' } } }.
|
|
2267
|
+
// those live in the styled definition, which this element cannot rewrite,
|
|
2268
|
+
// so a clause there retains whatever kind it is.
|
|
2112
2269
|
const defaultVariants = component.staticConfig.defaultVariants ?? {}
|
|
2113
|
-
const
|
|
2114
|
-
Object.entries(
|
|
2115
|
-
isClauseValue(name, value)
|
|
2270
|
+
const definitionCarriesClause =
|
|
2271
|
+
Object.entries(resolvedStyleStaticConfig.baseStyle ?? {}).some(
|
|
2272
|
+
([name, value]) => isClauseValue(name, value)
|
|
2116
2273
|
) ||
|
|
2117
2274
|
Object.entries(component.staticConfig.variants ?? {}).some(
|
|
2118
2275
|
([variantName, definitions]) =>
|
|
@@ -2126,24 +2283,44 @@ export function createTamaguiCompilerHost(
|
|
|
2126
2283
|
isClauseValue(name, value)
|
|
2127
2284
|
)
|
|
2128
2285
|
)
|
|
2129
|
-
) ||
|
|
2130
|
-
// compound variant styles are contributed by resolveSplitStyles too,
|
|
2131
|
-
// so a clause there would also freeze build-machine state if folded
|
|
2132
|
-
(component.staticConfig.compoundVariants ?? []).some(
|
|
2133
|
-
(compound) =>
|
|
2134
|
-
staticObject(compound) &&
|
|
2135
|
-
staticObject(compound.style) &&
|
|
2136
|
-
Object.entries(compound.style).some(([name, value]) =>
|
|
2137
|
-
isClauseValue(name, value)
|
|
2138
|
-
)
|
|
2139
2286
|
)
|
|
2140
|
-
if (
|
|
2287
|
+
if (definitionCarriesClause) {
|
|
2141
2288
|
return bailout(
|
|
2142
2289
|
input,
|
|
2143
2290
|
'local/unsupported-target',
|
|
2144
2291
|
'Native conditional value programs remain on the runtime path'
|
|
2145
2292
|
)
|
|
2146
2293
|
}
|
|
2294
|
+
const reducedProps: Record<string, unknown> = {}
|
|
2295
|
+
for (const [name, value] of Object.entries(completeProps)) {
|
|
2296
|
+
const clause = isStyleProp(name, component) ? nativeClauseValue(value) : null
|
|
2297
|
+
if (clause === 'live') {
|
|
2298
|
+
return bailout(
|
|
2299
|
+
input,
|
|
2300
|
+
'local/unsupported-target',
|
|
2301
|
+
'Native conditional value programs remain on the runtime path'
|
|
2302
|
+
)
|
|
2303
|
+
}
|
|
2304
|
+
if (clause === null) {
|
|
2305
|
+
reducedProps[name] = value
|
|
2306
|
+
continue
|
|
2307
|
+
}
|
|
2308
|
+
if (clause.matched) reducedProps[name] = clause.payload
|
|
2309
|
+
}
|
|
2310
|
+
completeProps = reducedProps
|
|
2311
|
+
// a conditional leaf is a clause program the same way a direct prop is,
|
|
2312
|
+
// and propsForConditional reduces the ones that fold
|
|
2313
|
+
for (const entry of dynamicStyleEntries) {
|
|
2314
|
+
if (entry.value.kind !== 'conditional') continue
|
|
2315
|
+
for (const leaf of collectLeaves(entry.value.tree)) {
|
|
2316
|
+
if (nativeClauseValue(leaf.value) !== 'live') continue
|
|
2317
|
+
return bailout(
|
|
2318
|
+
input,
|
|
2319
|
+
'local/unsupported-target',
|
|
2320
|
+
'Native conditional value programs remain on the runtime path'
|
|
2321
|
+
)
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2147
2324
|
}
|
|
2148
2325
|
const split = resolveSplitStyles(
|
|
2149
2326
|
completeProps,
|
|
@@ -2175,13 +2352,6 @@ export function createTamaguiCompilerHost(
|
|
|
2175
2352
|
}
|
|
2176
2353
|
)
|
|
2177
2354
|
}
|
|
2178
|
-
const domStyleProgram = input.element.entries.find(
|
|
2179
|
-
(entry) =>
|
|
2180
|
-
entry.kind === 'prop' &&
|
|
2181
|
-
entry.name === 'style' &&
|
|
2182
|
-
entry.value.kind === 'dom-style'
|
|
2183
|
-
)
|
|
2184
|
-
|
|
2185
2355
|
const flatTag =
|
|
2186
2356
|
component.domTag ??
|
|
2187
2357
|
(typeof props.render === 'string'
|
|
@@ -2201,7 +2371,9 @@ export function createTamaguiCompilerHost(
|
|
|
2201
2371
|
}))
|
|
2202
2372
|
|
|
2203
2373
|
const isPropIgnored = (name: string) =>
|
|
2204
|
-
isStyleProp(name, component) ||
|
|
2374
|
+
isStyleProp(name, component) ||
|
|
2375
|
+
isInvalidHostStyleProp(name, component) ||
|
|
2376
|
+
componentOnlyProps.has(name)
|
|
2205
2377
|
const spreadReplacement = (
|
|
2206
2378
|
form: MaterializedElement['form'],
|
|
2207
2379
|
entry: MaterializedElement['entries'][number]
|
|
@@ -2218,16 +2390,11 @@ export function createTamaguiCompilerHost(
|
|
|
2218
2390
|
|
|
2219
2391
|
let styleEntries = input.element.entries.filter(
|
|
2220
2392
|
(entry) =>
|
|
2221
|
-
(entry.kind === 'prop' &&
|
|
2222
|
-
(isStyleProp(entry.name, component) ||
|
|
2223
|
-
isInvalidHostStyleProp(entry.name, component))) ||
|
|
2393
|
+
(entry.kind === 'prop' && isPropIgnored(entry.name)) ||
|
|
2224
2394
|
(entry.kind === 'spread' &&
|
|
2225
2395
|
entry.value.kind === 'static' &&
|
|
2226
2396
|
staticObject(entry.value.value) &&
|
|
2227
|
-
Object.keys(entry.value.value).some(
|
|
2228
|
-
(name) =>
|
|
2229
|
-
isStyleProp(name, component) || isInvalidHostStyleProp(name, component)
|
|
2230
|
-
))
|
|
2397
|
+
Object.keys(entry.value.value).some(isPropIgnored))
|
|
2231
2398
|
)
|
|
2232
2399
|
let invalidHostStyle:
|
|
2233
2400
|
| { entry: MaterializedElement['entries'][number]; name: string }
|
|
@@ -3369,7 +3536,8 @@ function bailout(
|
|
|
3369
3536
|
| 'local/unsupported-child',
|
|
3370
3537
|
message: string,
|
|
3371
3538
|
span = input.element.span,
|
|
3372
|
-
zero?: { rule: ZeroRule; message?: string }
|
|
3539
|
+
zero?: { rule: ZeroRule; message?: string },
|
|
3540
|
+
prop?: string
|
|
3373
3541
|
): LoweringCandidateResult {
|
|
3374
3542
|
return {
|
|
3375
3543
|
ok: false,
|
|
@@ -3379,6 +3547,7 @@ function bailout(
|
|
|
3379
3547
|
message,
|
|
3380
3548
|
span,
|
|
3381
3549
|
component: input.element.component.name,
|
|
3550
|
+
...(prop && { prop }),
|
|
3382
3551
|
...(zero && { zeroRule: zero.rule, zeroMessage: zero.message }),
|
|
3383
3552
|
},
|
|
3384
3553
|
}
|