@tamagui/web 3.0.0-beta.924.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (636) hide show
  1. package/dist/cjs/_withNativeStyle.cjs +3 -0
  2. package/dist/cjs/_withNativeStyle.native.cjs +3 -0
  3. package/dist/cjs/_withNativeStyle.native.js +3 -0
  4. package/dist/cjs/_withNativeStyle.native.js.map +1 -1
  5. package/dist/cjs/_withStableStyle.native.cjs +1 -5
  6. package/dist/cjs/_withStableStyle.native.js +1 -5
  7. package/dist/cjs/_withStableStyle.native.js.map +1 -1
  8. package/dist/cjs/config.cjs +6 -3
  9. package/dist/cjs/config.native.cjs +7 -5
  10. package/dist/cjs/config.native.js +7 -5
  11. package/dist/cjs/config.native.js.map +1 -1
  12. package/dist/cjs/contexts/ComponentContext.cjs +1 -0
  13. package/dist/cjs/contexts/ComponentContext.native.cjs +8 -0
  14. package/dist/cjs/contexts/ComponentContext.native.js +8 -0
  15. package/dist/cjs/contexts/ComponentContext.native.js.map +1 -1
  16. package/dist/cjs/createComponent.cjs +46 -32
  17. package/dist/cjs/createComponent.native.cjs +92 -72
  18. package/dist/cjs/createComponent.native.js +92 -72
  19. package/dist/cjs/createComponent.native.js.map +1 -1
  20. package/dist/cjs/createTamagui.cjs +32 -14
  21. package/dist/cjs/createTamagui.native.cjs +33 -19
  22. package/dist/cjs/createTamagui.native.js +33 -19
  23. package/dist/cjs/createTamagui.native.js.map +1 -1
  24. package/dist/cjs/createTokens.native.cjs +1 -5
  25. package/dist/cjs/createTokens.native.js +1 -5
  26. package/dist/cjs/createTokens.native.js.map +1 -1
  27. package/dist/cjs/createVariable.native.cjs +1 -5
  28. package/dist/cjs/createVariable.native.js +1 -5
  29. package/dist/cjs/createVariable.native.js.map +1 -1
  30. package/dist/cjs/createVariables.native.cjs +2 -6
  31. package/dist/cjs/createVariables.native.js +2 -6
  32. package/dist/cjs/createVariables.native.js.map +1 -1
  33. package/dist/cjs/dom/html.cjs +87 -329
  34. package/dist/cjs/dom/html.native.cjs +53 -2
  35. package/dist/cjs/dom/html.native.js +53 -2
  36. package/dist/cjs/dom/html.native.js.map +1 -1
  37. package/dist/cjs/{helpers/timer.native.js → dom/htmlReset.cjs} +6 -12
  38. package/dist/cjs/{helpers/timer.native.cjs → dom/htmlReset.native.cjs} +6 -8
  39. package/dist/cjs/dom/htmlReset.native.js +30 -0
  40. package/dist/cjs/dom/htmlReset.native.js.map +1 -0
  41. package/dist/cjs/dom/htmlRuntime.native.cjs +4 -0
  42. package/dist/cjs/dom/htmlRuntime.native.js +4 -0
  43. package/dist/cjs/dom/htmlRuntime.native.js.map +1 -1
  44. package/dist/cjs/dom/htmlStaticConfig.cjs +44 -0
  45. package/dist/cjs/dom/htmlStaticConfig.native.cjs +46 -0
  46. package/dist/cjs/dom/htmlStaticConfig.native.js +48 -0
  47. package/dist/cjs/dom/htmlStaticConfig.native.js.map +1 -0
  48. package/dist/cjs/dom/primitives.native.cjs +81 -34
  49. package/dist/cjs/dom/primitives.native.js +81 -34
  50. package/dist/cjs/dom/primitives.native.js.map +1 -1
  51. package/dist/cjs/eventHandling.cjs +10 -4
  52. package/dist/cjs/eventHandling.native.cjs +52 -16
  53. package/dist/cjs/eventHandling.native.js +52 -16
  54. package/dist/cjs/eventHandling.native.js.map +1 -1
  55. package/dist/cjs/helpers/NativeTextBinding.cjs +36 -0
  56. package/dist/cjs/helpers/NativeTextBinding.native.cjs +39 -0
  57. package/dist/cjs/helpers/NativeTextBinding.native.js +41 -0
  58. package/dist/cjs/helpers/NativeTextBinding.native.js.map +1 -0
  59. package/dist/cjs/helpers/configVariables.native.cjs +2 -6
  60. package/dist/cjs/helpers/configVariables.native.js +2 -6
  61. package/dist/cjs/helpers/configVariables.native.js.map +1 -1
  62. package/dist/cjs/helpers/createDesignSystem.cjs +14 -10
  63. package/dist/cjs/helpers/createDesignSystem.native.cjs +5 -4
  64. package/dist/cjs/helpers/createDesignSystem.native.js +5 -4
  65. package/dist/cjs/helpers/createDesignSystem.native.js.map +1 -1
  66. package/dist/cjs/helpers/createStyledContext.native.cjs +1 -5
  67. package/dist/cjs/helpers/createStyledContext.native.js +1 -5
  68. package/dist/cjs/helpers/createStyledContext.native.js.map +1 -1
  69. package/dist/cjs/helpers/expandStyle.cjs +45 -1
  70. package/dist/cjs/helpers/expandStyle.native.cjs +38 -2
  71. package/dist/cjs/helpers/expandStyle.native.js +38 -2
  72. package/dist/cjs/helpers/expandStyle.native.js.map +1 -1
  73. package/dist/cjs/helpers/expandStyles.cjs +15 -3
  74. package/dist/cjs/helpers/expandStyles.native.cjs +14 -8
  75. package/dist/cjs/helpers/expandStyles.native.js +14 -8
  76. package/dist/cjs/helpers/expandStyles.native.js.map +1 -1
  77. package/dist/cjs/helpers/fluid.cjs +56 -0
  78. package/dist/cjs/helpers/fluid.native.cjs +58 -0
  79. package/dist/cjs/helpers/fluid.native.js +60 -0
  80. package/dist/cjs/helpers/fluid.native.js.map +1 -0
  81. package/dist/cjs/helpers/formatDiagnostic.native.cjs +2 -6
  82. package/dist/cjs/helpers/formatDiagnostic.native.js +2 -6
  83. package/dist/cjs/helpers/formatDiagnostic.native.js.map +1 -1
  84. package/dist/cjs/helpers/getCSSStylesAtomic.cjs +6 -6
  85. package/dist/cjs/helpers/getSplitStyles.cjs +366 -150
  86. package/dist/cjs/helpers/getSplitStyles.native.cjs +584 -184
  87. package/dist/cjs/helpers/getSplitStyles.native.js +584 -184
  88. package/dist/cjs/helpers/getSplitStyles.native.js.map +1 -1
  89. package/dist/cjs/helpers/getThemeCSSRules.cjs +37 -25
  90. package/dist/cjs/helpers/grammarConfig.cjs +6 -14
  91. package/dist/cjs/helpers/grammarConfig.native.cjs +32 -22
  92. package/dist/cjs/helpers/grammarConfig.native.js +32 -22
  93. package/dist/cjs/helpers/grammarConfig.native.js.map +1 -1
  94. package/dist/cjs/helpers/insertStyleRule.cjs +11 -4
  95. package/dist/cjs/helpers/insertStyleRule.native.cjs +8 -11
  96. package/dist/cjs/helpers/insertStyleRule.native.js +8 -11
  97. package/dist/cjs/helpers/insertStyleRule.native.js.map +1 -1
  98. package/dist/cjs/helpers/isObj.native.cjs +1 -5
  99. package/dist/cjs/helpers/isObj.native.js +1 -5
  100. package/dist/cjs/helpers/isObj.native.js.map +1 -1
  101. package/dist/cjs/helpers/mainThreadPressEvents.native.cjs +48 -100
  102. package/dist/cjs/helpers/mainThreadPressEvents.native.js +48 -100
  103. package/dist/cjs/helpers/mainThreadPressEvents.native.js.map +1 -1
  104. package/dist/cjs/helpers/mergeProps.cjs +18 -21
  105. package/dist/cjs/helpers/mergeProps.native.cjs +20 -23
  106. package/dist/cjs/helpers/mergeProps.native.js +20 -23
  107. package/dist/cjs/helpers/mergeProps.native.js.map +1 -1
  108. package/dist/cjs/helpers/nativeOnlyProps.cjs +0 -1
  109. package/dist/cjs/helpers/nativeOnlyProps.native.cjs +0 -1
  110. package/dist/cjs/helpers/nativeOnlyProps.native.js +0 -1
  111. package/dist/cjs/helpers/nativeOnlyProps.native.js.map +1 -1
  112. package/dist/cjs/helpers/nativeTextMetrics.cjs +74 -0
  113. package/dist/cjs/helpers/nativeTextMetrics.native.cjs +77 -0
  114. package/dist/cjs/helpers/nativeTextMetrics.native.js +79 -0
  115. package/dist/cjs/helpers/nativeTextMetrics.native.js.map +1 -0
  116. package/dist/cjs/helpers/normalizeColor.native.cjs +17 -2
  117. package/dist/cjs/helpers/normalizeColor.native.js +17 -2
  118. package/dist/cjs/helpers/normalizeColor.native.js.map +1 -1
  119. package/dist/cjs/helpers/normalizeValueWithProperty.cjs +2 -1
  120. package/dist/cjs/helpers/normalizeValueWithProperty.native.cjs +3 -6
  121. package/dist/cjs/helpers/normalizeValueWithProperty.native.js +3 -6
  122. package/dist/cjs/helpers/normalizeValueWithProperty.native.js.map +1 -1
  123. package/dist/cjs/helpers/objectIdentityKey.native.cjs +1 -5
  124. package/dist/cjs/helpers/objectIdentityKey.native.js +1 -5
  125. package/dist/cjs/helpers/objectIdentityKey.native.js.map +1 -1
  126. package/dist/cjs/helpers/parseNativeStyle.cjs +187 -0
  127. package/dist/cjs/helpers/parseNativeStyle.native.cjs +6 -4
  128. package/dist/cjs/helpers/parseNativeStyle.native.js +6 -4
  129. package/dist/cjs/helpers/parseNativeStyle.native.js.map +1 -1
  130. package/dist/cjs/helpers/proxyThemeToParents.cjs +9 -2
  131. package/dist/cjs/helpers/proxyThemeToParents.native.cjs +28 -2
  132. package/dist/cjs/helpers/proxyThemeToParents.native.js +28 -2
  133. package/dist/cjs/helpers/proxyThemeToParents.native.js.map +1 -1
  134. package/dist/cjs/helpers/resolveAnimationDriver.native.cjs +1 -5
  135. package/dist/cjs/helpers/resolveAnimationDriver.native.js +1 -5
  136. package/dist/cjs/helpers/resolveAnimationDriver.native.js.map +1 -1
  137. package/dist/cjs/helpers/{timer.cjs → resolveNativeUnits.cjs} +12 -8
  138. package/dist/cjs/helpers/resolveNativeUnits.native.cjs +205 -0
  139. package/dist/cjs/helpers/resolveNativeUnits.native.js +207 -0
  140. package/dist/cjs/helpers/resolveNativeUnits.native.js.map +1 -0
  141. package/dist/cjs/helpers/resolveRem.native.cjs +18 -21
  142. package/dist/cjs/helpers/resolveRem.native.js +18 -21
  143. package/dist/cjs/helpers/resolveRem.native.js.map +1 -1
  144. package/dist/cjs/helpers/resolveSizing.cjs +124 -0
  145. package/dist/cjs/helpers/resolveSizing.native.cjs +133 -0
  146. package/dist/cjs/helpers/resolveSizing.native.js +135 -0
  147. package/dist/cjs/helpers/resolveSizing.native.js.map +1 -0
  148. package/dist/cjs/helpers/resolveVariableValue.cjs +7 -7
  149. package/dist/cjs/helpers/resolveVariableValue.native.cjs +7 -9
  150. package/dist/cjs/helpers/resolveVariableValue.native.js +7 -9
  151. package/dist/cjs/helpers/resolveVariableValue.native.js.map +1 -1
  152. package/dist/cjs/helpers/resolveVariantStyle.native.cjs +2 -6
  153. package/dist/cjs/helpers/resolveVariantStyle.native.js +2 -6
  154. package/dist/cjs/helpers/resolveVariantStyle.native.js.map +1 -1
  155. package/dist/cjs/helpers/skipProps.cjs +0 -1
  156. package/dist/cjs/helpers/skipProps.native.cjs +0 -1
  157. package/dist/cjs/helpers/skipProps.native.js +0 -1
  158. package/dist/cjs/helpers/skipProps.native.js.map +1 -1
  159. package/dist/cjs/helpers/styleFrontend.cjs +23 -1
  160. package/dist/cjs/helpers/styleFrontend.native.cjs +23 -1
  161. package/dist/cjs/helpers/styleFrontend.native.js +23 -1
  162. package/dist/cjs/helpers/styleFrontend.native.js.map +1 -1
  163. package/dist/cjs/helpers/styleStaticConfigCore.cjs +5 -4
  164. package/dist/cjs/helpers/styleStaticConfigCore.native.cjs +7 -4
  165. package/dist/cjs/helpers/styleStaticConfigCore.native.js +7 -4
  166. package/dist/cjs/helpers/styleStaticConfigCore.native.js.map +1 -1
  167. package/dist/cjs/helpers/styledDynamic.cjs +5 -0
  168. package/dist/cjs/helpers/styledDynamic.native.cjs +8 -7
  169. package/dist/cjs/helpers/styledDynamic.native.js +8 -7
  170. package/dist/cjs/helpers/styledDynamic.native.js.map +1 -1
  171. package/dist/cjs/helpers/subscribeToContextGroup.cjs +16 -7
  172. package/dist/cjs/helpers/subscribeToContextGroup.native.cjs +18 -8
  173. package/dist/cjs/helpers/subscribeToContextGroup.native.js +18 -8
  174. package/dist/cjs/helpers/subscribeToContextGroup.native.js.map +1 -1
  175. package/dist/cjs/helpers/themeRef.native.cjs +1 -5
  176. package/dist/cjs/helpers/themeRef.native.js +1 -5
  177. package/dist/cjs/helpers/themeRef.native.js.map +1 -1
  178. package/dist/cjs/helpers/themes.cjs +26 -11
  179. package/dist/cjs/helpers/themes.native.cjs +26 -11
  180. package/dist/cjs/helpers/themes.native.js +26 -11
  181. package/dist/cjs/helpers/themes.native.js.map +1 -1
  182. package/dist/cjs/helpers/tokenCategories.cjs +2 -2
  183. package/dist/cjs/helpers/tokenCategories.native.cjs +2 -2
  184. package/dist/cjs/helpers/tokenCategories.native.js +2 -2
  185. package/dist/cjs/helpers/tokenCategories.native.js.map +1 -1
  186. package/dist/cjs/helpers/variables.cjs +1 -1
  187. package/dist/cjs/helpers/variables.native.cjs +4 -8
  188. package/dist/cjs/helpers/variables.native.js +4 -8
  189. package/dist/cjs/helpers/variables.native.js.map +1 -1
  190. package/dist/cjs/helpers/warnOnce.cjs +6 -0
  191. package/dist/cjs/helpers/warnOnce.native.cjs +6 -0
  192. package/dist/cjs/helpers/warnOnce.native.js +6 -0
  193. package/dist/cjs/helpers/warnOnce.native.js.map +1 -1
  194. package/dist/cjs/helpers/webPropsToSkip.native.cjs +3 -3
  195. package/dist/cjs/helpers/webPropsToSkip.native.js +3 -3
  196. package/dist/cjs/helpers/webPropsToSkip.native.js.map +1 -1
  197. package/dist/cjs/helpers/wrapStyleTags.cjs +1 -1
  198. package/dist/cjs/helpers/wrapStyleTags.native.cjs +1 -1
  199. package/dist/cjs/helpers/wrapStyleTags.native.js +1 -1
  200. package/dist/cjs/helpers/wrapStyleTags.native.js.map +1 -1
  201. package/dist/cjs/hooks/useComponentState.native.cjs +1 -5
  202. package/dist/cjs/hooks/useComponentState.native.js +1 -5
  203. package/dist/cjs/hooks/useComponentState.native.js.map +1 -1
  204. package/dist/cjs/hooks/useMedia.cjs +27 -34
  205. package/dist/cjs/hooks/useMedia.native.cjs +45 -51
  206. package/dist/cjs/hooks/useMedia.native.js +45 -51
  207. package/dist/cjs/hooks/useMedia.native.js.map +1 -1
  208. package/dist/cjs/hooks/useSplitStyles.cjs +1 -1
  209. package/dist/cjs/hooks/useSplitStyles.native.cjs +1 -1
  210. package/dist/cjs/hooks/useSplitStyles.native.js +1 -1
  211. package/dist/cjs/hooks/useSplitStyles.native.js.map +1 -1
  212. package/dist/cjs/hooks/useThemeState.cjs +37 -47
  213. package/dist/cjs/hooks/useThemeState.native.cjs +44 -50
  214. package/dist/cjs/hooks/useThemeState.native.js +44 -50
  215. package/dist/cjs/hooks/useThemeState.native.js.map +1 -1
  216. package/dist/cjs/index.cjs +7 -0
  217. package/dist/cjs/index.native.cjs +7 -0
  218. package/dist/cjs/index.native.js +7 -0
  219. package/dist/cjs/index.native.js.map +1 -1
  220. package/dist/cjs/internal-runtime.cjs +22 -0
  221. package/dist/cjs/internal-runtime.native.cjs +22 -0
  222. package/dist/cjs/internal-runtime.native.js +22 -0
  223. package/dist/cjs/internal-runtime.native.js.map +1 -1
  224. package/dist/cjs/static-resolve.native.cjs +2 -9
  225. package/dist/cjs/static-resolve.native.js +2 -9
  226. package/dist/cjs/static-resolve.native.js.map +1 -1
  227. package/dist/cjs/style.cjs +1 -1
  228. package/dist/cjs/style.native.cjs +4 -7
  229. package/dist/cjs/style.native.js +4 -7
  230. package/dist/cjs/style.native.js.map +1 -1
  231. package/dist/cjs/views/Theme.cjs +10 -17
  232. package/dist/cjs/views/Theme.native.cjs +9 -11
  233. package/dist/cjs/views/Theme.native.js +9 -11
  234. package/dist/cjs/views/Theme.native.js.map +1 -1
  235. package/dist/cjs/views/ThemeDebug.cjs +1 -1
  236. package/dist/cjs/views/ThemeUpdate.cjs +1 -1
  237. package/dist/cjs/views/ThemeUpdate.native.cjs +1 -1
  238. package/dist/cjs/views/ThemeUpdate.native.js +1 -1
  239. package/dist/cjs/views/ThemeUpdate.native.js.map +1 -1
  240. package/dist/esm/_withNativeStyle.mjs +4 -1
  241. package/dist/esm/_withNativeStyle.mjs.map +1 -1
  242. package/dist/esm/_withNativeStyle.native.js +4 -1
  243. package/dist/esm/_withNativeStyle.native.js.map +1 -1
  244. package/dist/esm/_withStableStyle.native.js +1 -5
  245. package/dist/esm/_withStableStyle.native.js.map +1 -1
  246. package/dist/esm/config.mjs +6 -3
  247. package/dist/esm/config.mjs.map +1 -1
  248. package/dist/esm/config.native.js +7 -5
  249. package/dist/esm/config.native.js.map +1 -1
  250. package/dist/esm/contexts/ComponentContext.mjs +9 -9
  251. package/dist/esm/contexts/ComponentContext.mjs.map +1 -1
  252. package/dist/esm/contexts/ComponentContext.native.js +16 -9
  253. package/dist/esm/contexts/ComponentContext.native.js.map +1 -1
  254. package/dist/esm/createComponent.mjs +45 -42
  255. package/dist/esm/createComponent.mjs.map +1 -1
  256. package/dist/esm/createComponent.native.js +93 -82
  257. package/dist/esm/createComponent.native.js.map +1 -1
  258. package/dist/esm/createTamagui.mjs +33 -15
  259. package/dist/esm/createTamagui.mjs.map +1 -1
  260. package/dist/esm/createTamagui.native.js +34 -20
  261. package/dist/esm/createTamagui.native.js.map +1 -1
  262. package/dist/esm/createTokens.native.js +1 -5
  263. package/dist/esm/createTokens.native.js.map +1 -1
  264. package/dist/esm/createVariable.native.js +1 -5
  265. package/dist/esm/createVariable.native.js.map +1 -1
  266. package/dist/esm/createVariables.native.js +2 -6
  267. package/dist/esm/createVariables.native.js.map +1 -1
  268. package/dist/esm/dom/html.mjs +87 -329
  269. package/dist/esm/dom/html.mjs.map +1 -1
  270. package/dist/esm/dom/html.native.js +53 -2
  271. package/dist/esm/dom/html.native.js.map +1 -1
  272. package/dist/esm/dom/htmlReset.mjs +6 -0
  273. package/dist/esm/dom/htmlReset.mjs.map +1 -0
  274. package/dist/esm/dom/htmlReset.native.js +6 -0
  275. package/dist/esm/dom/htmlReset.native.js.map +1 -0
  276. package/dist/esm/dom/htmlRuntime.native.js +4 -0
  277. package/dist/esm/dom/htmlRuntime.native.js.map +1 -1
  278. package/dist/esm/dom/htmlStaticConfig.mjs +22 -0
  279. package/dist/esm/dom/htmlStaticConfig.mjs.map +1 -0
  280. package/dist/esm/dom/htmlStaticConfig.native.js +22 -0
  281. package/dist/esm/dom/htmlStaticConfig.native.js.map +1 -0
  282. package/dist/esm/dom/primitives.native.js +81 -34
  283. package/dist/esm/dom/primitives.native.js.map +1 -1
  284. package/dist/esm/eventHandling.mjs +10 -4
  285. package/dist/esm/eventHandling.mjs.map +1 -1
  286. package/dist/esm/eventHandling.native.js +52 -16
  287. package/dist/esm/eventHandling.native.js.map +1 -1
  288. package/dist/esm/helpers/NativeTextBinding.mjs +17 -0
  289. package/dist/esm/helpers/NativeTextBinding.mjs.map +1 -0
  290. package/dist/esm/helpers/NativeTextBinding.native.js +18 -0
  291. package/dist/esm/helpers/NativeTextBinding.native.js.map +1 -0
  292. package/dist/esm/helpers/configVariables.native.js +2 -6
  293. package/dist/esm/helpers/configVariables.native.js.map +1 -1
  294. package/dist/esm/helpers/createDesignSystem.mjs +14 -10
  295. package/dist/esm/helpers/createDesignSystem.mjs.map +1 -1
  296. package/dist/esm/helpers/createDesignSystem.native.js +4 -4
  297. package/dist/esm/helpers/createDesignSystem.native.js.map +1 -1
  298. package/dist/esm/helpers/createStyledContext.native.js +1 -5
  299. package/dist/esm/helpers/createStyledContext.native.js.map +1 -1
  300. package/dist/esm/helpers/expandStyle.mjs +41 -1
  301. package/dist/esm/helpers/expandStyle.mjs.map +1 -1
  302. package/dist/esm/helpers/expandStyle.native.js +36 -3
  303. package/dist/esm/helpers/expandStyle.native.js.map +1 -1
  304. package/dist/esm/helpers/expandStyles.mjs +15 -3
  305. package/dist/esm/helpers/expandStyles.mjs.map +1 -1
  306. package/dist/esm/helpers/expandStyles.native.js +14 -8
  307. package/dist/esm/helpers/expandStyles.native.js.map +1 -1
  308. package/dist/esm/helpers/fluid.mjs +36 -0
  309. package/dist/esm/helpers/fluid.mjs.map +1 -0
  310. package/dist/esm/helpers/fluid.native.js +36 -0
  311. package/dist/esm/helpers/fluid.native.js.map +1 -0
  312. package/dist/esm/helpers/formatDiagnostic.native.js +2 -6
  313. package/dist/esm/helpers/formatDiagnostic.native.js.map +1 -1
  314. package/dist/esm/helpers/getCSSStylesAtomic.mjs +6 -6
  315. package/dist/esm/helpers/getCSSStylesAtomic.mjs.map +1 -1
  316. package/dist/esm/helpers/getSplitStyles.mjs +364 -150
  317. package/dist/esm/helpers/getSplitStyles.mjs.map +1 -1
  318. package/dist/esm/helpers/getSplitStyles.native.js +588 -188
  319. package/dist/esm/helpers/getSplitStyles.native.js.map +1 -1
  320. package/dist/esm/helpers/getThemeCSSRules.mjs +37 -25
  321. package/dist/esm/helpers/getThemeCSSRules.mjs.map +1 -1
  322. package/dist/esm/helpers/grammarConfig.mjs +6 -14
  323. package/dist/esm/helpers/grammarConfig.mjs.map +1 -1
  324. package/dist/esm/helpers/grammarConfig.native.js +32 -22
  325. package/dist/esm/helpers/grammarConfig.native.js.map +1 -1
  326. package/dist/esm/helpers/insertStyleRule.mjs +11 -4
  327. package/dist/esm/helpers/insertStyleRule.mjs.map +1 -1
  328. package/dist/esm/helpers/insertStyleRule.native.js +4 -4
  329. package/dist/esm/helpers/insertStyleRule.native.js.map +1 -1
  330. package/dist/esm/helpers/isObj.native.js +1 -5
  331. package/dist/esm/helpers/isObj.native.js.map +1 -1
  332. package/dist/esm/helpers/mainThreadPressEvents.native.js +48 -100
  333. package/dist/esm/helpers/mainThreadPressEvents.native.js.map +1 -1
  334. package/dist/esm/helpers/mergeProps.mjs +18 -21
  335. package/dist/esm/helpers/mergeProps.mjs.map +1 -1
  336. package/dist/esm/helpers/mergeProps.native.js +20 -23
  337. package/dist/esm/helpers/mergeProps.native.js.map +1 -1
  338. package/dist/esm/helpers/nativeOnlyProps.mjs +0 -1
  339. package/dist/esm/helpers/nativeOnlyProps.mjs.map +1 -1
  340. package/dist/esm/helpers/nativeOnlyProps.native.js +0 -1
  341. package/dist/esm/helpers/nativeOnlyProps.native.js.map +1 -1
  342. package/dist/esm/helpers/nativeTextMetrics.mjs +55 -0
  343. package/dist/esm/helpers/nativeTextMetrics.mjs.map +1 -0
  344. package/dist/esm/helpers/nativeTextMetrics.native.js +56 -0
  345. package/dist/esm/helpers/nativeTextMetrics.native.js.map +1 -0
  346. package/dist/esm/helpers/normalizeColor.native.js +17 -2
  347. package/dist/esm/helpers/normalizeColor.native.js.map +1 -1
  348. package/dist/esm/helpers/normalizeValueWithProperty.mjs +2 -1
  349. package/dist/esm/helpers/normalizeValueWithProperty.mjs.map +1 -1
  350. package/dist/esm/helpers/normalizeValueWithProperty.native.js +3 -6
  351. package/dist/esm/helpers/normalizeValueWithProperty.native.js.map +1 -1
  352. package/dist/esm/helpers/objectIdentityKey.native.js +1 -5
  353. package/dist/esm/helpers/objectIdentityKey.native.js.map +1 -1
  354. package/dist/esm/helpers/parseNativeStyle.mjs +168 -0
  355. package/dist/esm/helpers/parseNativeStyle.mjs.map +1 -0
  356. package/dist/esm/helpers/parseNativeStyle.native.js +4 -1
  357. package/dist/esm/helpers/parseNativeStyle.native.js.map +1 -1
  358. package/dist/esm/helpers/proxyThemeToParents.mjs +10 -2
  359. package/dist/esm/helpers/proxyThemeToParents.mjs.map +1 -1
  360. package/dist/esm/helpers/proxyThemeToParents.native.js +29 -2
  361. package/dist/esm/helpers/proxyThemeToParents.native.js.map +1 -1
  362. package/dist/esm/helpers/resolveAnimationDriver.native.js +1 -5
  363. package/dist/esm/helpers/resolveAnimationDriver.native.js.map +1 -1
  364. package/dist/esm/helpers/resolveNativeUnits.mjs +9 -0
  365. package/dist/esm/helpers/resolveNativeUnits.mjs.map +1 -0
  366. package/dist/esm/helpers/resolveNativeUnits.native.js +178 -0
  367. package/dist/esm/helpers/resolveNativeUnits.native.js.map +1 -0
  368. package/dist/esm/helpers/resolveRem.native.js +18 -21
  369. package/dist/esm/helpers/resolveRem.native.js.map +1 -1
  370. package/dist/esm/helpers/resolveSizing.mjs +102 -0
  371. package/dist/esm/helpers/resolveSizing.mjs.map +1 -0
  372. package/dist/esm/helpers/resolveSizing.native.js +109 -0
  373. package/dist/esm/helpers/resolveSizing.native.js.map +1 -0
  374. package/dist/esm/helpers/resolveVariableValue.mjs +7 -7
  375. package/dist/esm/helpers/resolveVariableValue.mjs.map +1 -1
  376. package/dist/esm/helpers/resolveVariableValue.native.js +7 -9
  377. package/dist/esm/helpers/resolveVariableValue.native.js.map +1 -1
  378. package/dist/esm/helpers/resolveVariantStyle.native.js +2 -6
  379. package/dist/esm/helpers/resolveVariantStyle.native.js.map +1 -1
  380. package/dist/esm/helpers/skipProps.mjs +0 -1
  381. package/dist/esm/helpers/skipProps.mjs.map +1 -1
  382. package/dist/esm/helpers/skipProps.native.js +0 -1
  383. package/dist/esm/helpers/skipProps.native.js.map +1 -1
  384. package/dist/esm/helpers/styleFrontend.mjs +20 -1
  385. package/dist/esm/helpers/styleFrontend.mjs.map +1 -1
  386. package/dist/esm/helpers/styleFrontend.native.js +20 -1
  387. package/dist/esm/helpers/styleFrontend.native.js.map +1 -1
  388. package/dist/esm/helpers/styleStaticConfigCore.mjs +5 -4
  389. package/dist/esm/helpers/styleStaticConfigCore.mjs.map +1 -1
  390. package/dist/esm/helpers/styleStaticConfigCore.native.js +7 -4
  391. package/dist/esm/helpers/styleStaticConfigCore.native.js.map +1 -1
  392. package/dist/esm/helpers/styledDynamic.mjs +5 -0
  393. package/dist/esm/helpers/styledDynamic.mjs.map +1 -1
  394. package/dist/esm/helpers/styledDynamic.native.js +8 -7
  395. package/dist/esm/helpers/styledDynamic.native.js.map +1 -1
  396. package/dist/esm/helpers/subscribeToContextGroup.mjs +16 -7
  397. package/dist/esm/helpers/subscribeToContextGroup.mjs.map +1 -1
  398. package/dist/esm/helpers/subscribeToContextGroup.native.js +18 -8
  399. package/dist/esm/helpers/subscribeToContextGroup.native.js.map +1 -1
  400. package/dist/esm/helpers/themeRef.native.js +1 -5
  401. package/dist/esm/helpers/themeRef.native.js.map +1 -1
  402. package/dist/esm/helpers/themes.mjs +20 -11
  403. package/dist/esm/helpers/themes.mjs.map +1 -1
  404. package/dist/esm/helpers/themes.native.js +20 -11
  405. package/dist/esm/helpers/themes.native.js.map +1 -1
  406. package/dist/esm/helpers/tokenCategories.mjs +2 -2
  407. package/dist/esm/helpers/tokenCategories.mjs.map +1 -1
  408. package/dist/esm/helpers/tokenCategories.native.js +2 -2
  409. package/dist/esm/helpers/tokenCategories.native.js.map +1 -1
  410. package/dist/esm/helpers/variables.mjs +1 -1
  411. package/dist/esm/helpers/variables.mjs.map +1 -1
  412. package/dist/esm/helpers/variables.native.js +4 -8
  413. package/dist/esm/helpers/variables.native.js.map +1 -1
  414. package/dist/esm/helpers/warnOnce.mjs +6 -1
  415. package/dist/esm/helpers/warnOnce.mjs.map +1 -1
  416. package/dist/esm/helpers/warnOnce.native.js +6 -1
  417. package/dist/esm/helpers/warnOnce.native.js.map +1 -1
  418. package/dist/esm/helpers/webPropsToSkip.native.js +3 -3
  419. package/dist/esm/helpers/webPropsToSkip.native.js.map +1 -1
  420. package/dist/esm/helpers/wrapStyleTags.mjs +1 -1
  421. package/dist/esm/helpers/wrapStyleTags.mjs.map +1 -1
  422. package/dist/esm/helpers/wrapStyleTags.native.js +1 -1
  423. package/dist/esm/helpers/wrapStyleTags.native.js.map +1 -1
  424. package/dist/esm/hooks/useComponentState.native.js +1 -5
  425. package/dist/esm/hooks/useComponentState.native.js.map +1 -1
  426. package/dist/esm/hooks/useMedia.mjs +27 -34
  427. package/dist/esm/hooks/useMedia.mjs.map +1 -1
  428. package/dist/esm/hooks/useMedia.native.js +45 -51
  429. package/dist/esm/hooks/useMedia.native.js.map +1 -1
  430. package/dist/esm/hooks/useSplitStyles.mjs +1 -1
  431. package/dist/esm/hooks/useSplitStyles.mjs.map +1 -1
  432. package/dist/esm/hooks/useSplitStyles.native.js +1 -1
  433. package/dist/esm/hooks/useSplitStyles.native.js.map +1 -1
  434. package/dist/esm/hooks/useThemeState.mjs +36 -48
  435. package/dist/esm/hooks/useThemeState.mjs.map +1 -1
  436. package/dist/esm/hooks/useThemeState.native.js +44 -50
  437. package/dist/esm/hooks/useThemeState.native.js.map +1 -1
  438. package/dist/esm/index.js +4 -1
  439. package/dist/esm/index.mjs +4 -1
  440. package/dist/esm/index.native.js +4 -1
  441. package/dist/esm/internal-runtime.mjs +22 -3
  442. package/dist/esm/internal-runtime.mjs.map +1 -1
  443. package/dist/esm/internal-runtime.native.js +22 -3
  444. package/dist/esm/internal-runtime.native.js.map +1 -1
  445. package/dist/esm/static-resolve.native.js +2 -9
  446. package/dist/esm/static-resolve.native.js.map +1 -1
  447. package/dist/esm/style.mjs +1 -1
  448. package/dist/esm/style.mjs.map +1 -1
  449. package/dist/esm/style.native.js +4 -7
  450. package/dist/esm/style.native.js.map +1 -1
  451. package/dist/esm/views/Theme.mjs +15 -14
  452. package/dist/esm/views/Theme.mjs.map +1 -1
  453. package/dist/esm/views/Theme.native.js +15 -15
  454. package/dist/esm/views/Theme.native.js.map +1 -1
  455. package/dist/esm/views/ThemeDebug.mjs +1 -1
  456. package/dist/esm/views/ThemeDebug.mjs.map +1 -1
  457. package/dist/esm/views/ThemeUpdate.mjs +1 -1
  458. package/dist/esm/views/ThemeUpdate.mjs.map +1 -1
  459. package/dist/esm/views/ThemeUpdate.native.js +1 -1
  460. package/dist/esm/views/ThemeUpdate.native.js.map +1 -1
  461. package/package.json +20 -18
  462. package/reset.css +11 -0
  463. package/src/_withNativeStyle.tsx +6 -1
  464. package/src/config.ts +6 -6
  465. package/src/contexts/ComponentContext.tsx +8 -0
  466. package/src/createComponent.tsx +177 -57
  467. package/src/createStyledHOC.tsx +25 -26
  468. package/src/createTamagui.ts +47 -28
  469. package/src/dom/contract.ts +4 -1
  470. package/src/dom/html.native.tsx +55 -2
  471. package/src/dom/html.tsx +189 -388
  472. package/src/dom/htmlReset.ts +15 -0
  473. package/src/dom/htmlRuntime.native.tsx +5 -0
  474. package/src/dom/htmlStaticConfig.ts +40 -0
  475. package/src/dom/primitives.native.tsx +138 -33
  476. package/src/dom/standalone.ts +2 -1
  477. package/src/dom/styleTypes.ts +82 -92
  478. package/src/eventHandling.native.ts +61 -11
  479. package/src/eventHandling.ts +19 -4
  480. package/src/helpers/NativeTextBinding.tsx +26 -0
  481. package/src/helpers/createDesignSystem.ts +24 -8
  482. package/src/helpers/expandStyle.ts +88 -4
  483. package/src/helpers/expandStyles.ts +6 -11
  484. package/src/helpers/fluid.ts +66 -0
  485. package/src/helpers/getCSSStylesAtomic.ts +11 -6
  486. package/src/helpers/getSplitStyles.tsx +1032 -296
  487. package/src/helpers/getThemeCSSRules.ts +73 -35
  488. package/src/helpers/grammarConfig.ts +23 -8
  489. package/src/helpers/insertStyleRule.tsx +14 -8
  490. package/src/helpers/mainThreadPressEvents.native.ts +65 -141
  491. package/src/helpers/mergeProps.ts +29 -62
  492. package/src/helpers/nativeOnlyProps.ts +0 -1
  493. package/src/helpers/nativeTextMetrics.ts +77 -0
  494. package/src/helpers/normalizeColor.native.ts +29 -4
  495. package/src/helpers/normalizeValueWithProperty.ts +2 -1
  496. package/src/helpers/{parseNativeStyle.native.ts → parseNativeStyle.ts} +8 -1
  497. package/src/helpers/proxyThemeToParents.ts +13 -2
  498. package/src/helpers/resolveNativeUnits.native.ts +247 -0
  499. package/src/helpers/resolveNativeUnits.ts +10 -0
  500. package/src/helpers/resolveRem.native.ts +25 -26
  501. package/src/helpers/resolveSizing.ts +167 -0
  502. package/src/helpers/resolveVariableValue.ts +21 -17
  503. package/src/helpers/skipProps.ts +0 -1
  504. package/src/helpers/styleFrontend.ts +39 -0
  505. package/src/helpers/styleProvenance.ts +1 -1
  506. package/src/helpers/styleStaticConfigCore.ts +15 -4
  507. package/src/helpers/styledDynamic.ts +3 -1
  508. package/src/helpers/subscribeToContextGroup.tsx +16 -7
  509. package/src/helpers/themes.ts +27 -11
  510. package/src/helpers/tokenCategories.ts +15 -3
  511. package/src/helpers/variables.ts +2 -2
  512. package/src/helpers/warnOnce.ts +6 -0
  513. package/src/helpers/webPropsToSkip.native.ts +9 -3
  514. package/src/helpers/wrapStyleTags.tsx +4 -1
  515. package/src/hooks/useMedia.tsx +36 -47
  516. package/src/hooks/useSplitStyles.tsx +4 -1
  517. package/src/hooks/useThemeState.ts +69 -74
  518. package/src/index.ts +13 -0
  519. package/src/interfaces/RNExclusiveTypes.ts +1 -3
  520. package/src/internal-runtime.ts +43 -2
  521. package/src/style.ts +4 -1
  522. package/src/styled.tsx +34 -3
  523. package/src/types.tsx +412 -132
  524. package/src/views/Theme.tsx +18 -21
  525. package/src/views/ThemeDebug.tsx +1 -1
  526. package/src/views/ThemeUpdate.tsx +1 -1
  527. package/types/_withNativeStyle.d.ts.map +1 -1
  528. package/types/config.d.ts.map +1 -1
  529. package/types/contexts/ComponentContext.d.ts +1 -1
  530. package/types/contexts/ComponentContext.d.ts.map +1 -1
  531. package/types/createComponent.d.ts.map +1 -1
  532. package/types/createStyledHOC.d.ts +5 -2
  533. package/types/createStyledHOC.d.ts.map +1 -1
  534. package/types/createTamagui.d.ts.map +1 -1
  535. package/types/dom/contract.d.ts +4 -1
  536. package/types/dom/contract.d.ts.map +1 -1
  537. package/types/dom/html.d.ts +60 -51
  538. package/types/dom/html.d.ts.map +1 -1
  539. package/types/dom/html.native.d.ts.map +1 -1
  540. package/types/dom/htmlReset.d.ts +10 -0
  541. package/types/dom/htmlReset.d.ts.map +1 -0
  542. package/types/dom/htmlRuntime.native.d.ts.map +1 -1
  543. package/types/dom/htmlStaticConfig.d.ts +22 -0
  544. package/types/dom/htmlStaticConfig.d.ts.map +1 -0
  545. package/types/dom/primitives.native.d.ts.map +1 -1
  546. package/types/dom/standalone.d.ts +2 -1
  547. package/types/dom/standalone.d.ts.map +1 -1
  548. package/types/dom/styleTypes.d.ts +63 -84
  549. package/types/dom/styleTypes.d.ts.map +1 -1
  550. package/types/eventHandling.d.ts +12 -4
  551. package/types/eventHandling.d.ts.map +1 -1
  552. package/types/eventHandling.native.d.ts.map +1 -1
  553. package/types/helpers/NativeTextBinding.d.ts +11 -0
  554. package/types/helpers/NativeTextBinding.d.ts.map +1 -0
  555. package/types/helpers/createDesignSystem.d.ts.map +1 -1
  556. package/types/helpers/expandStyle.d.ts +1 -0
  557. package/types/helpers/expandStyle.d.ts.map +1 -1
  558. package/types/helpers/expandStyles.d.ts.map +1 -1
  559. package/types/helpers/fluid.d.ts +21 -0
  560. package/types/helpers/fluid.d.ts.map +1 -0
  561. package/types/helpers/getCSSStylesAtomic.d.ts +3 -1
  562. package/types/helpers/getCSSStylesAtomic.d.ts.map +1 -1
  563. package/types/helpers/getSplitStyles.d.ts +2 -1
  564. package/types/helpers/getSplitStyles.d.ts.map +1 -1
  565. package/types/helpers/getThemeCSSRules.d.ts.map +1 -1
  566. package/types/helpers/grammarConfig.d.ts.map +1 -1
  567. package/types/helpers/insertStyleRule.d.ts.map +1 -1
  568. package/types/helpers/mainThreadPressEvents.native.d.ts +0 -7
  569. package/types/helpers/mainThreadPressEvents.native.d.ts.map +1 -1
  570. package/types/helpers/mergeProps.d.ts +1 -15
  571. package/types/helpers/mergeProps.d.ts.map +1 -1
  572. package/types/helpers/nativeOnlyProps.d.ts +0 -1
  573. package/types/helpers/nativeOnlyProps.d.ts.map +1 -1
  574. package/types/helpers/nativeTextMetrics.d.ts +16 -0
  575. package/types/helpers/nativeTextMetrics.d.ts.map +1 -0
  576. package/types/helpers/normalizeColor.native.d.ts +4 -1
  577. package/types/helpers/normalizeColor.native.d.ts.map +1 -1
  578. package/types/helpers/normalizeShadow.native.d.ts +3 -1
  579. package/types/helpers/normalizeShadow.native.d.ts.map +1 -1
  580. package/types/helpers/normalizeValueWithProperty.d.ts.map +1 -1
  581. package/types/helpers/{parseNativeStyle.native.d.ts → parseNativeStyle.d.ts} +1 -1
  582. package/types/helpers/parseNativeStyle.d.ts.map +1 -0
  583. package/types/helpers/proxyThemeToParents.d.ts +1 -1
  584. package/types/helpers/proxyThemeToParents.d.ts.map +1 -1
  585. package/types/helpers/resolveNativeUnits.d.ts +6 -0
  586. package/types/helpers/resolveNativeUnits.d.ts.map +1 -0
  587. package/types/helpers/resolveNativeUnits.native.d.ts +16 -0
  588. package/types/helpers/resolveNativeUnits.native.d.ts.map +1 -0
  589. package/types/helpers/resolveRem.native.d.ts +6 -4
  590. package/types/helpers/resolveRem.native.d.ts.map +1 -1
  591. package/types/helpers/resolveSizing.d.ts +90 -0
  592. package/types/helpers/resolveSizing.d.ts.map +1 -0
  593. package/types/helpers/resolveVariableValue.d.ts.map +1 -1
  594. package/types/helpers/skipProps.d.ts +0 -1
  595. package/types/helpers/skipProps.d.ts.map +1 -1
  596. package/types/helpers/styleFrontend.d.ts +21 -0
  597. package/types/helpers/styleFrontend.d.ts.map +1 -1
  598. package/types/helpers/styleProvenance.d.ts +1 -1
  599. package/types/helpers/styleProvenance.d.ts.map +1 -1
  600. package/types/helpers/styleStaticConfigCore.d.ts.map +1 -1
  601. package/types/helpers/styledDynamic.d.ts +1 -1
  602. package/types/helpers/styledDynamic.d.ts.map +1 -1
  603. package/types/helpers/themes.d.ts +4 -0
  604. package/types/helpers/themes.d.ts.map +1 -1
  605. package/types/helpers/tokenCategories.d.ts +1 -1
  606. package/types/helpers/tokenCategories.d.ts.map +1 -1
  607. package/types/helpers/warnOnce.d.ts +1 -0
  608. package/types/helpers/warnOnce.d.ts.map +1 -1
  609. package/types/helpers/webPropsToSkip.native.d.ts +6 -2
  610. package/types/helpers/webPropsToSkip.native.d.ts.map +1 -1
  611. package/types/helpers/wrapStyleTags.d.ts.map +1 -1
  612. package/types/hooks/useMedia.d.ts +5 -2
  613. package/types/hooks/useMedia.d.ts.map +1 -1
  614. package/types/hooks/useSplitStyles.d.ts.map +1 -1
  615. package/types/hooks/useThemeState.d.ts.map +1 -1
  616. package/types/index.d.ts +4 -1
  617. package/types/index.d.ts.map +1 -1
  618. package/types/interfaces/RNExclusiveTypes.d.ts +2 -3
  619. package/types/interfaces/RNExclusiveTypes.d.ts.map +1 -1
  620. package/types/internal-runtime.d.ts +12 -1
  621. package/types/internal-runtime.d.ts.map +1 -1
  622. package/types/style.d.ts.map +1 -1
  623. package/types/styled.d.ts +7 -4
  624. package/types/styled.d.ts.map +1 -1
  625. package/types/types.d.ts +258 -102
  626. package/types/types.d.ts.map +1 -1
  627. package/types/views/Theme.d.ts.map +1 -1
  628. package/dist/cjs/helpers/timer.native.js.map +0 -1
  629. package/dist/esm/helpers/timer.mjs +0 -13
  630. package/dist/esm/helpers/timer.mjs.map +0 -1
  631. package/dist/esm/helpers/timer.native.js +0 -13
  632. package/dist/esm/helpers/timer.native.js.map +0 -1
  633. package/src/helpers/timer.ts +0 -9
  634. package/types/helpers/parseNativeStyle.native.d.ts.map +0 -1
  635. package/types/helpers/timer.d.ts +0 -2
  636. package/types/helpers/timer.d.ts.map +0 -1
@@ -1,3 +1,5 @@
1
+ // leaf subpath on purpose, see grammarConfig
2
+ import { getTransitionResolver } from '@tamagui/animation-helpers/transitionResolver'
1
3
  import { isAndroid, isClient, supportsDynamicColorIOS } from '@tamagui/constants'
2
4
  import {
3
5
  StyleObjectIdentifier,
@@ -14,9 +16,11 @@ import {
14
16
  createTransformAccumulator,
15
17
  finalizeTransformAccumulator,
16
18
  getTransformPartKeys,
19
+ grammarMaxNonPlatformDepth,
20
+ namedCssColors,
17
21
  removeTransformValue,
18
22
  } from '@tamagui/style-grammar/runtime'
19
- import { getConfig, getConfigMaybe, getFont } from '../config'
23
+ import { getConfig, getConfigMaybe, getFont, getSetting } from '../config'
20
24
  import { isDevTools } from '../constants/isDevTools'
21
25
  import { defaultComponentStateMounted } from '../defaultComponentState'
22
26
  import { isVariable } from '../createVariable'
@@ -29,6 +33,7 @@ import type {
29
33
  DebugProp,
30
34
  GetStyleResult,
31
35
  GetStyleState,
36
+ NativeTextMetrics,
32
37
  RulesToInsert,
33
38
  SplitStyleProps,
34
39
  StaticConfig,
@@ -49,7 +54,7 @@ import {
49
54
  flushDirectStyles,
50
55
  registerAtomicSlot,
51
56
  } from './getCSSStylesAtomic'
52
- import { expandStyle } from './expandStyle'
57
+ import { expandStyle, nativeShorthandLogicals } from './expandStyle'
53
58
  import {
54
59
  classifyBorderComponents,
55
60
  splitComponents,
@@ -59,13 +64,13 @@ import { fixStyles } from './expandStyles'
59
64
  import { getConfigRevisionState } from './grammarConfig'
60
65
  import { mediaState as globalMediaState, mediaKeyMatch } from './mediaState'
61
66
  import { getStyleStaticConfig, type StyleStaticConfig } from './styleStaticConfig'
62
- import type { FrontendClassSink } from './styleFrontend'
67
+ import { mergeFrontendCondition, type FrontendClassSink } from './styleFrontend'
63
68
  import { nativeTextInputColorProps, normalizeNativeStyle } from './nativeStyleEngine'
64
69
  import { warnOnce, warnRefusedValue } from './warnOnce'
65
70
 
66
71
  export { getStyleStaticConfig }
67
72
 
68
- import { isColorStyleKey } from './getDynamicVal'
73
+ import { extractValueFromDynamic, isColorStyleKey } from './getDynamicVal'
69
74
  import { getDynamicEnv } from './styledDynamic'
70
75
  import {
71
76
  getRulesForIdentifier,
@@ -76,9 +81,12 @@ import {
76
81
  import { log } from './log'
77
82
  import { normalizeColor } from './normalizeColor'
78
83
  import { normalizeValueWithProperty } from './normalizeValueWithProperty'
79
- import { parseNativeStyle } from './parseNativeStyle.native'
84
+ import { resolveTextMetrics } from './nativeTextMetrics'
85
+ import { isTamaguiElement } from './isTamaguiElement'
86
+ import { parseNativeStyle } from './parseNativeStyle'
80
87
  import { parseNativeTransform } from './parseNativeTransform.native'
81
88
  import { isRemValue, resolveRem } from './resolveRem'
89
+ import { resolveNativeUnits } from './resolveNativeUnits'
82
90
  import { resolveVariableValue } from './resolveVariableValue'
83
91
  import { HOC_CLASSNAME_MARKER, skipProps } from './skipProps'
84
92
  import { styleOriginalValues } from './styleOriginalValues'
@@ -441,6 +449,7 @@ const passFrontendContainerType = 27
441
449
  const passSourceLayer = 28
442
450
  const passParentCursor = 29
443
451
  const passMapSourceKey = 30
452
+ const passVariantOutput = 31
444
453
 
445
454
  const passFlags = 13
446
455
 
@@ -462,6 +471,10 @@ const passTextFlag = 32
462
471
  const passInputFlag = 64
463
472
  const passAsChildStyleFlag = 128
464
473
 
474
+ function isRemovedVendorStyleProp(property: string) {
475
+ return /^(Webkit|Moz|ms)[A-Z]/.test(property) && !(property in stylePropsAll)
476
+ }
477
+
465
478
  // exported so the compiler applies the SAME host-validity decision when it
466
479
  // flattens: a style-shaped key that fails this check must be dropped with a
467
480
  // diagnostic, never kept as a DOM attribute (one predicate, two hosts)
@@ -525,7 +538,6 @@ function contributeProp(
525
538
  const shouldCheckSkipProps = !noSkip
526
539
  const asChildExceptStyleLike = Boolean(flags & passAsChildStyleFlag)
527
540
  const isTextOrInput = isText || isInput
528
- const hocParentVariants = isHOC ? parentVariants : undefined
529
541
  let keyInit = keyOg
530
542
  let valInit = valOg
531
543
 
@@ -588,24 +600,38 @@ function contributeProp(
588
600
  return
589
601
  }
590
602
  const resolveClassName = styleFrontend?.resolveClassName
603
+ // composed utilities (ring width + ring color -> one boxShadow) arrive as
604
+ // `__`-prefixed keys the frontend folds together after the walk. only
605
+ // allocates when a class actually emits one.
606
+ let composedProps: Record<string, any> | null = null
591
607
  const sink: FrontendClassSink = (entry) => {
592
608
  const property = entry[0]
593
- if (entry[2] !== undefined) {
609
+ const condition = entry[2]
610
+ if (property.charCodeAt(0) === 95 && property.charCodeAt(1) === 95) {
611
+ composedProps ||= {}
612
+ composedProps[property] = mergeFrontendCondition(
613
+ composedProps[property],
614
+ entry[1],
615
+ condition
616
+ )
617
+ return
618
+ }
619
+ if (condition !== undefined) {
594
620
  if (isValidStyleKey(property, validStyles)) {
595
- contributeValue(styleState, property, entry[1], undefined, false, entry[2])
621
+ contributeValue(styleState, property, entry[1], undefined, false, condition)
596
622
  } else if (process.env.NODE_ENV === 'development') {
597
623
  console.warn(
598
624
  `[tamagui] "${property}" is not a valid style on this component; the frontend value is dropped.`
599
625
  )
600
626
  }
601
- } else {
602
- if (property === 'group') pass[passFrontendGroup] = entry[1]
603
- else if (property === 'container') pass[passFrontendContainer] = entry[1]
604
- else if (property === 'containerType') {
605
- pass[passFrontendContainerType] = entry[1]
606
- }
607
- contributeProp(pass, property, entry[1])
627
+ return
608
628
  }
629
+ if (property === 'group') pass[passFrontendGroup] = entry[1]
630
+ else if (property === 'container') pass[passFrontendContainer] = entry[1]
631
+ else if (property === 'containerType') {
632
+ pass[passFrontendContainerType] = entry[1]
633
+ }
634
+ contributeProp(pass, property, entry[1])
609
635
  }
610
636
  let start = 0
611
637
  for (let index = 0; index <= valInit.length; index++) {
@@ -639,19 +665,74 @@ function contributeProp(
639
665
  }
640
666
  start = index + 1
641
667
  }
668
+ if (composedProps) {
669
+ // contributed at the className's own authored position, so composing a
670
+ // ring never moves an unrelated property to another precedence tier
671
+ const composed = styleFrontend!.compose?.(composedProps)
672
+ for (const property in composed) {
673
+ contributeProp(pass, property, composed[property])
674
+ }
675
+ }
642
676
  }
643
677
  return
644
678
  }
645
679
 
646
680
  if (keyInit === HOC_CLASSNAME_MARKER) {
647
- if (valInit && typeof valInit === 'object') {
681
+ if (valInit) {
682
+ const [hocClassNames, hocSlots] = valInit as HOCClassNames
648
683
  const direct = styleState as DirectState
649
684
  const layers = (direct.flatPropertyLayers ||= new Map())
650
- for (const property in valInit) {
685
+ for (const property in hocClassNames) {
686
+ if (hocSlots?.has(property)) continue
651
687
  clearDirectStyle(styleState, property)
652
- styleState.classNames[property] = valInit[property]
688
+ styleState.classNames[property] = hocClassNames[property]
653
689
  layers.set(property, pass[passSourceLayer])
654
690
  }
691
+ // a slot class (flex, border, padding...) covers several properties, so
692
+ // the outer styled's entries merge per property with this frame's own
693
+ // slot instead of replacing it: styled(Hoc, { flexWrap }) keeps the
694
+ // frame's flexDirection
695
+ if (hocSlots) {
696
+ const slots = (direct.flatSlots ||= new Map())
697
+ const markerLayer = pass[passSourceLayer]
698
+ for (const [slot, entries] of hocSlots) {
699
+ for (const entry of entries) {
700
+ // the outer component already resolved its own tiers, so its styled
701
+ // definition (base/variant/resolver) arrives here as one tier above
702
+ // this frame's own definition but below the props this frame passes
703
+ // itself. otherwise a skin's size resolver outranks the corner
704
+ // zeroing a Group injects as props (Tabs inside a Group)
705
+ pass[passSourceLayer] = Math.max(entry[7]! >> 5, sourceLayerResolver)
706
+ if (!ownsSourceLayer(styleState, entry[0], !!entry[2])) continue
707
+ if (
708
+ !isHOC &&
709
+ styleState.styleProps.isAnimated &&
710
+ (slot === 'transition' || entry[8]) &&
711
+ !(entry[0] in nonAnimatableStyleProps)
712
+ ) {
713
+ // the host owns lifecycle destinations and their transition.
714
+ const property =
715
+ entry[0] === '--t-x'
716
+ ? 'x'
717
+ : entry[0] === '--t-y'
718
+ ? 'y'
719
+ : entry[0] === '--t-scale-x'
720
+ ? 'scaleX'
721
+ : entry[0] === '--t-scale-y'
722
+ ? 'scaleY'
723
+ : entry[0]
724
+ const value =
725
+ styleState.animationDriver?.inputStyle === 'value' ? entry[6] : entry[1]
726
+ entry[3]
727
+ ? contributeValue(styleState, property, value, entry[6], false, entry[3])
728
+ : emitValue(styleState, property, value, null, entry[6], false)
729
+ } else {
730
+ writeStyleSlot(slots, slot, [...entry], pass[passSourceLayer])
731
+ }
732
+ }
733
+ }
734
+ pass[passSourceLayer] = markerLayer
735
+ }
655
736
  }
656
737
  return
657
738
  }
@@ -690,16 +771,49 @@ function contributeProp(
690
771
  const styleOriginals = shouldTrackStyleTokenProvenance
691
772
  ? styleOriginalValues.get(style)
692
773
  : undefined
693
- for (const key in style) {
694
- if (style[key] == null) continue
774
+ for (const authoredKey in style) {
775
+ const value = style[authoredKey]
776
+ if (value == null) continue
777
+ // style objects and pieces take the same shorthands as props
778
+ const key = disableExpandShorthands
779
+ ? authoredKey
780
+ : shorthands[authoredKey] || authoredKey
781
+ // the style prop is the inline style attribute, as in react: a plain
782
+ // value never becomes an atomic class, so element.style reads it back
783
+ // and it can change every frame without inserting a rule. a value that
784
+ // carries conditions can only exist as css, so those still compile
785
+ let inline = !styleState.styleProps.stylePieceEntries
695
786
  if (process.env.TAMAGUI_TARGET === 'web') {
696
787
  if (key === 'containerName') {
697
- pass[passContainerName] = style[key]
788
+ pass[passContainerName] = value
789
+ inline = false
698
790
  } else if (key === 'containerType') {
699
- pass[passContainerType] = style[key]
791
+ pass[passContainerType] = value
792
+ inline = false
700
793
  }
701
794
  }
702
- contributeValue(styleState, key, style[key], styleOriginals?.[key])
795
+ if (inline) {
796
+ if (typeof value === 'string') {
797
+ const [segments] = getConfigRevisionState(conf).parseFlatValue(value)
798
+ for (let index = 4; index < segments.length; index += 5) {
799
+ if (!(segments[index] & 1)) {
800
+ inline = false
801
+ break
802
+ }
803
+ }
804
+ } else if (
805
+ value &&
806
+ typeof value === 'object' &&
807
+ !Array.isArray(value) &&
808
+ !isVariable(value) &&
809
+ classifyConditionalObject(value, styleState) !== 0
810
+ ) {
811
+ inline = false
812
+ }
813
+ }
814
+ ;(styleState as DirectState).flatInlineStyleProp = inline
815
+ contributeValue(styleState, key, value, styleOriginals?.[authoredKey])
816
+ ;(styleState as DirectState).flatInlineStyleProp = false
703
817
  }
704
818
  }
705
819
  pass[passSourceLayer] = layerBeforeStyle
@@ -715,6 +829,31 @@ function contributeProp(
715
829
  }
716
830
  }
717
831
 
832
+ if (process.env.NODE_ENV === 'development') {
833
+ if (
834
+ !isValidStyleKey(keyInit, validStyles) &&
835
+ (keyInit === 'animation' || !(keyInit in stylePropsAll)) &&
836
+ (!variants || !(keyInit in variants))
837
+ ) {
838
+ let replacement: string | undefined
839
+ if (keyInit === 'animation') replacement = 'transition='
840
+ else if (keyInit === 'hoverStyle') replacement = 'hover: clause'
841
+ else if (keyInit === 'pressStyle') replacement = 'press: clause'
842
+ else if (keyInit === 'focusStyle') replacement = 'focus: clause'
843
+ else if (keyInit === 'enterStyle') replacement = 'enter: clause'
844
+ else if (keyInit === 'exitStyle') replacement = 'exit: clause'
845
+ else if (keyInit.charCodeAt(0) === 36 && keyInit.length > 1) {
846
+ replacement = `${keyInit.slice(1)}: clause`
847
+ }
848
+ if (replacement) {
849
+ warnOnce(
850
+ `v2-prop:${keyInit}`,
851
+ `prop "${keyInit}" was removed in v3; use ${replacement}`
852
+ )
853
+ }
854
+ }
855
+ }
856
+
718
857
  const isNativeInputColor =
719
858
  process.env.TAMAGUI_TARGET === 'native' &&
720
859
  isInput &&
@@ -732,18 +871,21 @@ function contributeProp(
732
871
  }
733
872
  if (keyInit === 'transition' && typeof valInit === 'string') {
734
873
  if (process.env.TAMAGUI_TARGET === 'native') return
735
- const animationConfig = driverAnimations?.[valInit]
736
- if (
737
- animationConfig &&
738
- driverOutputStyle === 'css' &&
739
- process.env.IS_STATIC === 'is_static'
740
- ) {
741
- // css output needs no runtime component: lower its named transition
742
- // to ordinary css so the compiler can keep flattening.
743
- valInit = `all ${animationConfig}`
744
- } else if (animationConfig) {
745
- // animation drivers consume configured preset names directly
746
- return
874
+ // the same grammar the compiler uses, so a value never means one thing
875
+ // here and another there. a transition made only of css timings needs no
876
+ // driver and falls through to the ordinary style path, and a bundle with
877
+ // no driver in it has no resolver because it has no presets to resolve.
878
+ const transitions = getTransitionResolver()
879
+ const resolved = transitions?.resolve(valInit, { animations: driverAnimations })
880
+ if (resolved?.fused) {
881
+ if (driverOutputStyle === 'css' && process.env.IS_STATIC === 'is_static') {
882
+ // css output needs no runtime component: springs lower to a
883
+ // `linear()` easing, so the compiler can keep flattening.
884
+ valInit = transitions!.toCSS(resolved) ?? valInit
885
+ } else {
886
+ // animation drivers consume the authored value directly
887
+ return
888
+ }
747
889
  }
748
890
  } else {
749
891
  return
@@ -764,17 +906,14 @@ function contributeProp(
764
906
  }
765
907
 
766
908
  if (process.env.TAMAGUI_TARGET === 'native') {
909
+ // only text has the native selectable prop. consume the authoring name on
910
+ // either host so a view never receives a text-only host attribute.
911
+ if (keyInit === 'userSelect') {
912
+ if (isText) viewProps.selectable = valInit !== 'none'
913
+ return
914
+ }
767
915
  if (!isValidStyleKeyInit) {
768
- if (!isAndroid) {
769
- // only works in android
770
- if (keyInit === 'elevationAndroid') return
771
- }
772
-
773
- // map userSelect to native prop
774
- if (keyInit === 'userSelect') {
775
- keyInit = 'selectable'
776
- valInit = valInit !== 'none'
777
- } else if (keyInit === 'textOverflow') {
916
+ if (keyInit === 'textOverflow') {
778
917
  // map textOverflow="ellipsis" on Text to numberOfLines + ellipsizeMode.
779
918
  // any other value (e.g. "clip") is a no-op on native (default behavior).
780
919
  if (isText && valInit === 'ellipsis') {
@@ -788,6 +927,30 @@ function contributeProp(
788
927
  }
789
928
  }
790
929
 
930
+ // variants hold styles and aria/data attributes (data- is handled above),
931
+ // which flatten to the same attribute. anything else a variant sets (a
932
+ // theme, a handler, a prop for the wrapped component) is dropped, so a
933
+ // variant means the same flattened or not
934
+ if (
935
+ pass[passVariantOutput] &&
936
+ !isValidStyleKeyInit &&
937
+ !keyInit.startsWith('aria-') &&
938
+ !(keyInit in stylePropsAll) &&
939
+ !(keyInit in skipProps) &&
940
+ !(variants && keyInit in variants) &&
941
+ !(parentVariants && keyInit in parentVariants) &&
942
+ !styledContextKeys?.has(keyInit) &&
943
+ !(styledContext && keyInit in styledContext)
944
+ ) {
945
+ if (process.env.NODE_ENV === 'development') {
946
+ warnOnce(
947
+ `variant-non-style:${keyInit}`,
948
+ `a variant set "${keyInit}", which is not a style. Variants hold styles and aria/data attributes only: set "${keyInit}" on the component one level up.`
949
+ )
950
+ }
951
+ return
952
+ }
953
+
791
954
  if (process.env.TAMAGUI_TARGET === 'web') {
792
955
  if (!noExpand) {
793
956
  // map the React Native-shaped public prop surface onto DOM attributes in
@@ -807,7 +970,7 @@ function contributeProp(
807
970
  ) {
808
971
  viewProps.disabled = true
809
972
  }
810
- if (!variants?.disabled) {
973
+ if (!variants?.disabled && !isHOC) {
811
974
  return
812
975
  }
813
976
  }
@@ -847,12 +1010,13 @@ function contributeProp(
847
1010
 
848
1011
  const shouldPassProp =
849
1012
  (!isStyleProp && isHOC) ||
1013
+ // disabled also controls the inner component's behavior, beyond its skin.
1014
+ (isHOC && keyInit === 'disabled') ||
850
1015
  // is in parent variants
851
- (hocParentVariants && keyInit in hocParentVariants) ||
1016
+ (parentVariants && keyInit in parentVariants) ||
852
1017
  inlineProps?.has(keyInit)
853
1018
 
854
- const parentVariant = parentVariants?.[keyInit]
855
- const isHOCShouldPassThrough = Boolean(isHOC && (parentVariant || keyInit in skipProps))
1019
+ const isHOCShouldPassThrough = isHOC && keyInit in skipProps
856
1020
 
857
1021
  const shouldPassThrough = shouldPassProp || isHOCShouldPassThrough
858
1022
 
@@ -895,10 +1059,12 @@ function contributeProp(
895
1059
  if (!isNativeInputColor && shouldCheckSkipProps && !neverSkipProps?.[keyInit]) {
896
1060
  if (
897
1061
  keyInit in skipProps &&
1062
+ // a plain-css transition is a style, not a driver prop, so it must not be
1063
+ // skipped here. same test as above: only a preset or spring needs a driver
898
1064
  !(
899
1065
  keyInit === 'transition' &&
900
1066
  typeof valInit === 'string' &&
901
- !driverAnimations?.[valInit]
1067
+ !getTransitionResolver()?.resolve(valInit, { animations: driverAnimations }).fused
902
1068
  )
903
1069
  ) {
904
1070
  if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
@@ -968,7 +1134,13 @@ function contributeProp(
968
1134
  }
969
1135
  }
970
1136
  } else {
971
- contributeValue(styleState, keyInit, valInit, originalOg, !isHostStyleKey)
1137
+ contributeValue(
1138
+ styleState,
1139
+ keyInit,
1140
+ valInit,
1141
+ originalOg,
1142
+ !isHostStyleKey || (isStyledContextProp && typeof valInit === 'boolean')
1143
+ )
972
1144
  }
973
1145
  return
974
1146
  }
@@ -994,8 +1166,9 @@ function contributeProp(
994
1166
  return
995
1167
  }
996
1168
 
997
- if (keyInit in stylePropsAll) {
998
- if (process.env.NODE_ENV === 'development') {
1169
+ if (keyInit in stylePropsAll || isRemovedVendorStyleProp(keyInit)) {
1170
+ // shared css authoring intentionally drops unsupported keys on native.
1171
+ if (process.env.NODE_ENV === 'development' && process.env.TAMAGUI_TARGET === 'web') {
999
1172
  console.warn(
1000
1173
  `[tamagui] "${keyInit}" is a text style prop and this component is not text — it would render on neither platform. Use a Text-based component, or html.* for raw web elements.`
1001
1174
  )
@@ -1058,7 +1231,7 @@ export const getSplitStyles: StyleSplitter = (
1058
1231
  const mediaState = styleProps.mediaState || globalMediaState
1059
1232
 
1060
1233
  let shouldDoClasses =
1061
- !process.env.TAMAGUI_DID_OUTPUT_CSS &&
1234
+ process.env.TAMAGUI_RUNTIME !== 'island' &&
1062
1235
  acceptsClassName &&
1063
1236
  process.env.TAMAGUI_TARGET === 'web' &&
1064
1237
  !styleProps.noClass
@@ -1125,6 +1298,18 @@ export const getSplitStyles: StyleSplitter = (
1125
1298
  }
1126
1299
  ;(styleState as DirectState).flatStyleStaticConfig = styleStaticConfig
1127
1300
 
1301
+ // native style stability: if the caller gave us the previous render's style
1302
+ // object we track it so the per-key merge can compare inline and skip the
1303
+ // object allocation when nothing changed
1304
+ if (process.env.TAMAGUI_TARGET === 'native') {
1305
+ const prev = styleProps.prevStyle
1306
+ if (prev) {
1307
+ ;(styleState as DirectState).flatPrevStyle = prev
1308
+ ;(styleState as DirectState).flatStyleChanged = false
1309
+ ;(styleState as DirectState).flatStyleKeyCount = 0
1310
+ }
1311
+ }
1312
+
1128
1313
  if (
1129
1314
  process.env.NODE_ENV === 'development' &&
1130
1315
  (debug === 'profile' || (globalThis as any).time)
@@ -1168,8 +1353,10 @@ export const getSplitStyles: StyleSplitter = (
1168
1353
  let frontendContainer: boolean | string | undefined
1169
1354
  let frontendContainerType: string | undefined
1170
1355
  const processedProps = props
1171
- const parentVariants = parentStaticConfig
1172
- ? getStyleStaticConfig(parentStaticConfig as StaticConfig, conf).variants
1356
+ // only variant names determine HOC forwarding; their style values resolve
1357
+ // in the renderer, so this needs no normalized style snapshot.
1358
+ const parentVariants = isHOC
1359
+ ? staticConfig.Component?.staticConfig?.variants
1173
1360
  : undefined
1174
1361
  const defaultProps = asChild ? styleStaticConfig.defaultProps : undefined
1175
1362
  const asChildExceptStyleLike =
@@ -1208,7 +1395,7 @@ export const getSplitStyles: StyleSplitter = (
1208
1395
  styledContextKeys,
1209
1396
  stylePassFlags,
1210
1397
  debug,
1211
- parentStaticConfig,
1398
+ process.env.NODE_ENV === 'development' ? parentStaticConfig : undefined,
1212
1399
  defaultProps,
1213
1400
  driverAnimations,
1214
1401
  driverOutputStyle,
@@ -1297,6 +1484,7 @@ export const getSplitStyles: StyleSplitter = (
1297
1484
  // later resolver in the chain wins within the tier
1298
1485
  const resolvers = staticConfig.resolvers
1299
1486
  if (resolvers && !noExpand) {
1487
+ const prevSourceLayer = pass[passSourceLayer]
1300
1488
  pass[passSourceLayer] = sourceLayerResolver
1301
1489
  const flagsBefore = pass[passFlags]
1302
1490
  // resolver output is styles only: never re-enter variant dispatch
@@ -1312,6 +1500,7 @@ export const getSplitStyles: StyleSplitter = (
1312
1500
  }
1313
1501
  }
1314
1502
  pass[passFlags] = flagsBefore
1503
+ pass[passSourceLayer] = prevSourceLayer
1315
1504
  }
1316
1505
 
1317
1506
  className = pass[passClassName]
@@ -1371,6 +1560,8 @@ export const getSplitStyles: StyleSplitter = (
1371
1560
  }
1372
1561
  }
1373
1562
  completeResolvedStyles(styleState)
1563
+ if (styleState.flatGroupKeys?.size) pseudoGroups = styleState.flatGroupKeys
1564
+ if (styleState.flatGroupMedia?.size) mediaGroups = styleState.flatGroupMedia
1374
1565
  if (styleProps.isStatic) {
1375
1566
  for (const property in classNames) {
1376
1567
  const identifier = classNames[property]
@@ -1461,6 +1652,7 @@ export const getSplitStyles: StyleSplitter = (
1461
1652
  flushDirectStyles(styleState)
1462
1653
  }
1463
1654
 
1655
+ let nativeTextMetrics: NativeTextMetrics | undefined
1464
1656
  // native: swap out the right family based on weight/style
1465
1657
  if (process.env.TAMAGUI_TARGET === 'native') {
1466
1658
  // set accessible when tabIndex is 0 (issue #3350)
@@ -1468,6 +1660,46 @@ export const getSplitStyles: StyleSplitter = (
1468
1660
  viewProps.accessible ??= true
1469
1661
  }
1470
1662
 
1663
+ if (
1664
+ (isText || isInput || staticConfig.isDOM) &&
1665
+ !isHOC &&
1666
+ (styleState.nativeLineHeight !== undefined ||
1667
+ styleState.style?.fontSize !== undefined ||
1668
+ componentContext?.parentFontSize !== undefined ||
1669
+ componentContext?.parentLineHeight !== undefined)
1670
+ ) {
1671
+ const style = (styleState.style ||= {})
1672
+ let lineHeight =
1673
+ styleState.nativeLineHeight ?? parentSplitStyles?.nativeTextMetrics?.lineHeight
1674
+ if (typeof lineHeight === 'string') {
1675
+ const length = resolveNativeUnits('lineHeight', lineHeight, styleState)
1676
+ if (typeof length === 'number') lineHeight = `${length}px`
1677
+ }
1678
+ nativeTextMetrics = resolveTextMetrics(
1679
+ style,
1680
+ lineHeight,
1681
+ componentContext,
1682
+ styleProps.isStatic,
1683
+ !staticConfig.isDOM &&
1684
+ !(processedProps.asChild && isTamaguiElement(processedProps.children))
1685
+ )
1686
+ if (staticConfig.isDOM) viewProps.__textMetrics = nativeTextMetrics
1687
+ // resolveTextMetrics writes fontSize/lineHeight after the inline merge
1688
+ // compare above, so an inherited-only change (new parent leading with
1689
+ // unchanged own props) must opt out of the prev-style swap below
1690
+ const directText = styleState as DirectState
1691
+ const prevTextStyle = directText.flatPrevStyle
1692
+ if (prevTextStyle && !directText.flatStyleChanged) {
1693
+ const resolvedTextStyle = styleState.style
1694
+ if (
1695
+ resolvedTextStyle &&
1696
+ (resolvedTextStyle.fontSize !== prevTextStyle.fontSize ||
1697
+ resolvedTextStyle.lineHeight !== prevTextStyle.lineHeight)
1698
+ ) {
1699
+ directText.flatStyleChanged = true
1700
+ }
1701
+ }
1702
+ }
1471
1703
  const style = styleState.style
1472
1704
  if (style?.fontFamily) {
1473
1705
  const faceInfo = getFont(style.fontFamily as string)?.face
@@ -1515,6 +1747,70 @@ export const getSplitStyles: StyleSplitter = (
1515
1747
  }
1516
1748
  }
1517
1749
 
1750
+ // native style stability: mergeStyle compares scalar values inline, but
1751
+ // transforms finalize later and need their own value comparison.
1752
+ if (process.env.TAMAGUI_TARGET === 'native') {
1753
+ const direct = styleState as DirectState
1754
+ const prevStyle = direct.flatPrevStyle
1755
+ if (
1756
+ prevStyle &&
1757
+ styleState.style &&
1758
+ !direct.flatStyleChanged &&
1759
+ Object.keys(prevStyle).length === Object.keys(styleState.style).length
1760
+ ) {
1761
+ const previousTransform = prevStyle.transform
1762
+ const nextTransform = styleState.style.transform
1763
+ let transformMatches = previousTransform === nextTransform
1764
+ if (
1765
+ !transformMatches &&
1766
+ Array.isArray(previousTransform) &&
1767
+ Array.isArray(nextTransform) &&
1768
+ previousTransform.length === nextTransform.length
1769
+ ) {
1770
+ transformMatches = true
1771
+ for (let index = 0; index < nextTransform.length; index++) {
1772
+ const previousPart = previousTransform[index]
1773
+ const nextPart = nextTransform[index]
1774
+ if (previousPart === nextPart) continue
1775
+ if (
1776
+ !previousPart ||
1777
+ !nextPart ||
1778
+ typeof previousPart !== 'object' ||
1779
+ typeof nextPart !== 'object'
1780
+ ) {
1781
+ transformMatches = false
1782
+ break
1783
+ }
1784
+ const keys = Object.keys(nextPart)
1785
+ if (keys.length !== Object.keys(previousPart).length) {
1786
+ transformMatches = false
1787
+ break
1788
+ }
1789
+ for (const key of keys) {
1790
+ const previousValue = previousPart[key]
1791
+ const nextValue = nextPart[key]
1792
+ if (
1793
+ previousValue !== nextValue &&
1794
+ !(
1795
+ Array.isArray(previousValue) &&
1796
+ Array.isArray(nextValue) &&
1797
+ previousValue.length === nextValue.length &&
1798
+ nextValue.every(
1799
+ (value, valueIndex) => value === previousValue[valueIndex]
1800
+ )
1801
+ )
1802
+ ) {
1803
+ transformMatches = false
1804
+ break
1805
+ }
1806
+ }
1807
+ if (!transformMatches) break
1808
+ }
1809
+ }
1810
+ if (transformMatches) styleState.style = prevStyle as any
1811
+ }
1812
+ }
1813
+
1518
1814
  // built without conditional spreads: this runs once per component render and
1519
1815
  // each spread transpiles to an ownKeys/defineProperty helper chain that
1520
1816
  // profiles at several percent of total style-resolution time
@@ -1529,6 +1825,8 @@ export const getSplitStyles: StyleSplitter = (
1529
1825
  mediaGroups,
1530
1826
  overriddenContextProps: styleState.overriddenContextProps,
1531
1827
  }
1828
+ if (process.env.TAMAGUI_TARGET === 'native' && nativeTextMetrics)
1829
+ result.nativeTextMetrics = nativeTextMetrics
1532
1830
  if (effectiveTransition != null) result.effectiveTransition = effectiveTransition
1533
1831
  if (conditionalStates) result.programStates = conditionalStates
1534
1832
  if (usesSafeArea) result.usesSafeArea = true
@@ -1561,7 +1859,13 @@ export const getSplitStyles: StyleSplitter = (
1561
1859
  const groupClassName = group ? `t_group_${group}` : ''
1562
1860
  // core host classes carry the base web reset. component hooks are
1563
1861
  // ordinary authored className defaults and do not derive from React identity.
1564
- let finalClassName = isText ? 'is_Text' : 'is_View'
1862
+ // DOM hosts carry is_DOM (never is_Text/is_View): its :where() reset
1863
+ // sets no display, so the browser stylesheet decides block vs inline.
1864
+ let finalClassName = staticConfig.isDOM
1865
+ ? 'is_DOM'
1866
+ : isText
1867
+ ? 'is_Text'
1868
+ : 'is_View'
1565
1869
  if (fontFamilyClassName) finalClassName += ` ${fontFamilyClassName}`
1566
1870
  let hasPropertyClassNames = false
1567
1871
  if (classNames) {
@@ -1573,7 +1877,10 @@ export const getSplitStyles: StyleSplitter = (
1573
1877
  if (groupClassName) finalClassName += ` ${groupClassName}`
1574
1878
  if (className) finalClassName += ` ${className}`
1575
1879
  if (isHOC && hasPropertyClassNames) {
1576
- viewProps[HOC_CLASSNAME_MARKER] = classNames
1880
+ viewProps[HOC_CLASSNAME_MARKER] = [
1881
+ classNames,
1882
+ (styleState as DirectState).flatCapturedSlots,
1883
+ ] satisfies HOCClassNames
1577
1884
  }
1578
1885
  if (finalClassName) {
1579
1886
  viewProps.className = finalClassName
@@ -1633,7 +1940,7 @@ export const getSplitStyles: StyleSplitter = (
1633
1940
  const stylePieceStaticConfig = {
1634
1941
  acceptsClassName: true,
1635
1942
  isText: true,
1636
- validStyles: stylePropsAll,
1943
+ validStyles: stylePropsInput,
1637
1944
  } as StaticConfig
1638
1945
 
1639
1946
  type CompiledStylePiece = {
@@ -1755,7 +2062,7 @@ function applyStylePieceClasses(
1755
2062
  const property = entry[0]
1756
2063
  const conditional = !!entry[2]
1757
2064
  if (!ownsSourceLayer(styleState, property, conditional)) continue
1758
- writeCapturedStyleRecord(slots, slot, entry, sourceLayer)
2065
+ writeStyleSlot(slots, slot, [...entry], sourceLayer)
1759
2066
  }
1760
2067
  }
1761
2068
  if (compiled.programStates) {
@@ -1809,7 +2116,7 @@ function applyStylePieceClasses(
1809
2116
  return applied
1810
2117
  }
1811
2118
 
1812
- function writeCapturedStyleRecord(
2119
+ function writeStyleSlot(
1813
2120
  slots: Map<string, AtomicSlotEntry[]>,
1814
2121
  slot: string,
1815
2122
  source: AtomicSlotEntry,
@@ -1827,6 +2134,16 @@ function writeCapturedStyleRecord(
1827
2134
  (entryFlags & (recordInline | recordCSS)) !==
1828
2135
  (flags & (recordInline | recordCSS))
1829
2136
  ) {
2137
+ // a piece landing after a plain style value replaces its inline record
2138
+ if (
2139
+ sourceLayer === sourceLayerStyle &&
2140
+ entry[7]! >> 5 === sourceLayerStyle &&
2141
+ entry[0] === source[0] &&
2142
+ !condition &&
2143
+ !entry[2]
2144
+ ) {
2145
+ list.splice(index--, 1)
2146
+ }
1830
2147
  continue
1831
2148
  }
1832
2149
  if (entry[0] !== source[0]) continue
@@ -1841,9 +2158,8 @@ function writeCapturedStyleRecord(
1841
2158
  break
1842
2159
  }
1843
2160
  }
1844
- const next = [...source] as AtomicSlotEntry
1845
- next[7] = flags | (sourceLayer << 5)
1846
- list.push(next)
2161
+ source[7] = flags | (sourceLayer << 5)
2162
+ list.push(source)
1847
2163
  }
1848
2164
 
1849
2165
  function mergeStyle(
@@ -1876,7 +2192,22 @@ function mergeStyle(
1876
2192
  } else {
1877
2193
  const shouldNormalize =
1878
2194
  process.env.TAMAGUI_TARGET === 'web' && !disableNormalize && !styleProps.noNormalize
1879
- const out = shouldNormalize ? normalizeValueWithProperty(val, key) : val
2195
+ let out = shouldNormalize ? normalizeValueWithProperty(val, key) : val
2196
+ if (process.env.TAMAGUI_TARGET === 'native' && key === 'lineHeight') {
2197
+ // resolved variant records retain the font Variable as their original value.
2198
+ styleState.nativeLineHeight =
2199
+ typeof out === 'number' &&
2200
+ isVariable(originalVal) &&
2201
+ typeof originalVal.val === 'number'
2202
+ ? `${out}px`
2203
+ : out
2204
+ } else if (process.env.TAMAGUI_TARGET === 'native' && typeof out === 'string') {
2205
+ if (out.includes('cqi') || out.includes('cqw')) {
2206
+ ;(styleState.flatGroupKeys ||= new Set()).add('@')
2207
+ ;(styleState.flatGroupMedia ||= new Set()).add('@')
2208
+ }
2209
+ out = resolveNativeUnits(key, out, styleState)
2210
+ }
1880
2211
  if (
1881
2212
  process.env.TAMAGUI_TARGET === 'native' &&
1882
2213
  staticConfig.isInput &&
@@ -1884,6 +2215,18 @@ function mergeStyle(
1884
2215
  ) {
1885
2216
  viewProps[nativeTextInputColorProps[key]] = out
1886
2217
  } else {
2218
+ // native style stability: compare each value inline against the previous
2219
+ // render's style object. if every key matches we can return the prev ref
2220
+ // and skip RN's diffNestedProperty + cloneNodeWithNewProps entirely.
2221
+ if (process.env.TAMAGUI_TARGET === 'native') {
2222
+ const direct = styleState as DirectState
2223
+ if (direct.flatPrevStyle) {
2224
+ direct.flatStyleKeyCount = (direct.flatStyleKeyCount || 0) + 1
2225
+ if (!direct.flatStyleChanged && direct.flatPrevStyle[key] !== out) {
2226
+ direct.flatStyleChanged = true
2227
+ }
2228
+ }
2229
+ }
1887
2230
  styleState.style ||= {}
1888
2231
  styleState.style[key] = out
1889
2232
  if (shouldTrackStyleTokenProvenance) {
@@ -1907,8 +2250,8 @@ function recordStyleTokenProvenance(
1907
2250
  let tokenName = typeof originalVal === 'string' ? originalVal : ''
1908
2251
  if (tokenName) {
1909
2252
  const slash = tokenName.lastIndexOf('/')
1910
- const opacity = slash === -1 ? NaN : Number(tokenName.slice(slash + 1))
1911
- if (Number.isInteger(opacity) && opacity >= 0 && opacity <= 100) {
2253
+ const opacity = slash === -1 ? NaN : +tokenName.slice(slash + 1)
2254
+ if (opacity % 1 === 0 && opacity >= 0 && opacity <= 100) {
1912
2255
  tokenName = tokenName.slice(0, slash)
1913
2256
  }
1914
2257
  }
@@ -1988,14 +2331,22 @@ export type MergeStyle = (
1988
2331
  originalValue?: any
1989
2332
  ) => void
1990
2333
 
2334
+ type HOCClassNames = [
2335
+ classNames: ClassNamesObject,
2336
+ slots: Map<string, AtomicSlotEntry[]> | undefined,
2337
+ ]
2338
+
1991
2339
  type DirectState = GetStyleState & {
2340
+ // set while a plain style prop value contributes, so its record stays inline
2341
+ flatInlineStyleProp?: boolean
1992
2342
  flatValueScope?: ValueScopeCache
1993
- flatValueScopeKind?: any
1994
2343
  flatConditions?: Map<string, Condition>
1995
2344
  flatConditionsClassed?: boolean
1996
2345
  flatPass?: StylePass
1997
2346
  flatStyleStaticConfig?: StyleStaticConfig
1998
2347
  flatSlots?: Map<string, AtomicSlotEntry[]>
2348
+ // a styled HOC hands its class slot entries to the frame it renders
2349
+ flatCapturedSlots?: Map<string, AtomicSlotEntry[]>
1999
2350
  flatPropertyLayers?: Map<string, number>
2000
2351
  flatCallerVariantKeys?: Set<string>
2001
2352
  flatAtomics?: Map<string, any>
@@ -2005,6 +2356,10 @@ type DirectState = GetStyleState & {
2005
2356
  flatDynamicThemeAccess?: boolean
2006
2357
  flatTextShadow?: Record<string, any>
2007
2358
  flatWebShadow?: any[]
2359
+ // native style stability: inline-compared during the style loop
2360
+ flatPrevStyle?: Record<string, any> | null
2361
+ flatStyleChanged?: boolean
2362
+ flatStyleKeyCount?: number
2008
2363
  }
2009
2364
 
2010
2365
  // orders the authored boxShadow value against the shadow-part record so the
@@ -2017,6 +2372,36 @@ const recordRetract = 4
2017
2372
  const recordDefault = 8
2018
2373
  const recordCSS = 16
2019
2374
 
2375
+ // react-native spells its RTL-aware props the way a dropped CSS draft did
2376
+ // (padding-start, border-end-color, border-top-start-radius, start/end). No
2377
+ // browser implements those, so the rules generated for them were inert and the
2378
+ // props did nothing on web. rename them onto the CSS logical properties that
2379
+ // are RTL-aware in exactly the same way (#3099)
2380
+ const webRTLRenames: Record<string, string> = {
2381
+ marginHorizontal: 'marginInline',
2382
+ marginVertical: 'marginBlock',
2383
+ paddingHorizontal: 'paddingInline',
2384
+ paddingVertical: 'paddingBlock',
2385
+ writingDirection: 'direction',
2386
+ paddingStart: 'paddingInlineStart',
2387
+ paddingEnd: 'paddingInlineEnd',
2388
+ marginStart: 'marginInlineStart',
2389
+ marginEnd: 'marginInlineEnd',
2390
+ borderStartWidth: 'borderInlineStartWidth',
2391
+ borderEndWidth: 'borderInlineEndWidth',
2392
+ borderStartColor: 'borderInlineStartColor',
2393
+ borderEndColor: 'borderInlineEndColor',
2394
+ borderStartStyle: 'borderInlineStartStyle',
2395
+ borderEndStyle: 'borderInlineEndStyle',
2396
+ // css orders these block-then-inline, so top-start is start-start
2397
+ borderTopStartRadius: 'borderStartStartRadius',
2398
+ borderTopEndRadius: 'borderStartEndRadius',
2399
+ borderBottomStartRadius: 'borderEndStartRadius',
2400
+ borderBottomEndRadius: 'borderEndEndRadius',
2401
+ start: 'insetInlineStart',
2402
+ end: 'insetInlineEnd',
2403
+ }
2404
+
2020
2405
  // the property vocabulary is small and its strings are interned, so these
2021
2406
  // per-property classifications resolve once per process instead of running
2022
2407
  // their string tests on every value of every pass
@@ -2024,14 +2409,7 @@ const webStyleProperties = new Map<string, string>()
2024
2409
  function webStyleProperty(property: string) {
2025
2410
  let web = webStyleProperties.get(property)
2026
2411
  if (web === undefined) {
2027
- web =
2028
- property === 'writingDirection'
2029
- ? 'direction'
2030
- : property.endsWith('Horizontal')
2031
- ? `${property.slice(0, -10)}Inline`
2032
- : property.endsWith('Vertical')
2033
- ? `${property.slice(0, -8)}Block`
2034
- : property
2412
+ web = webRTLRenames[property] || property
2035
2413
  webStyleProperties.set(property, web)
2036
2414
  }
2037
2415
  return web
@@ -2084,9 +2462,23 @@ function writeStyleRecord(
2084
2462
  const condition =
2085
2463
  conditionOverride !== -1 ? conditionOverride : cursor ? cursor[conditionValue] : 0
2086
2464
  const identity = cursor ? cursor[conditionKey] : ''
2465
+ if (process.env.TAMAGUI_TARGET === 'native' && value === 'unset' && identity !== '') {
2466
+ // a conditional unset means the platform default while the clause is
2467
+ // active. native has no `unset` keyword, so retract the key instead of
2468
+ // writing a string react native rejects. the record keeps its identity,
2469
+ // so it still overrides the earlier clause and loses to a later one
2470
+ value = undefined
2471
+ original = undefined
2472
+ flags |= recordRetract
2473
+ }
2087
2474
  const direct = state as DirectState
2088
2475
  const slots = (direct.flatSlots ||= new Map())
2089
- const slot =
2476
+ const sourceLayer = direct.flatPass?.[passSourceLayer] || 0
2477
+ if (direct.flatInlineStyleProp) flags |= recordInline
2478
+ // css records share a slot per shorthand group so one class covers the
2479
+ // group; an inline record keeps its own property slot because the emitter
2480
+ // merges exactly one inline winner per slot
2481
+ const cssSlot =
2090
2482
  process.env.TAMAGUI_TARGET === 'web' &&
2091
2483
  canGenerateCSS &&
2092
2484
  (state.flatShouldDoClasses || flags & recordCSS)
@@ -2094,39 +2486,47 @@ function writeStyleRecord(
2094
2486
  : property.startsWith('transition')
2095
2487
  ? 'transition'
2096
2488
  : property
2489
+ const slot = flags & recordInline && cssSlot !== property ? property : cssSlot
2097
2490
  let list = slots.get(slot)
2098
2491
  if (!list) slots.set(slot, (list = []))
2099
- for (let index = 0; index < list.length; index++) {
2100
- const entry = list[index]
2101
- const entryFlags = entry[7]!
2102
- if (
2103
- (entryFlags & (recordInline | recordCSS)) !==
2104
- (flags & (recordInline | recordCSS))
2105
- ) {
2106
- continue
2107
- }
2108
- if (entry[0] !== property) continue
2109
- if (flags & recordDefault) {
2110
- if (!(entryFlags & recordDefault) && (!entry[2] || entry[3] === identity)) return
2111
- } else if (entryFlags & recordDefault && (!condition || entry[3] === identity)) {
2112
- list.splice(index--, 1)
2113
- continue
2114
- }
2115
- if (entry[3] === identity) {
2116
- list.splice(index, 1)
2117
- break
2492
+ // a style array is last-wins per property even across a piece (a class) and
2493
+ // a plain value (inline), which otherwise never meet
2494
+ if (sourceLayer === sourceLayerStyle && !condition) {
2495
+ const other =
2496
+ slot === cssSlot ? list : slots.get(flags & recordInline ? cssSlot : property)
2497
+ if (other) {
2498
+ for (let index = 0; index < other.length; index++) {
2499
+ const entry = other[index]
2500
+ const entryFlags = entry[7]!
2501
+ if (
2502
+ entry[0] === property &&
2503
+ !entry[2] &&
2504
+ entryFlags >> 5 === sourceLayerStyle &&
2505
+ (entryFlags & (recordInline | recordCSS)) !==
2506
+ (flags & (recordInline | recordCSS))
2507
+ ) {
2508
+ other.splice(index--, 1)
2509
+ }
2510
+ }
2118
2511
  }
2119
2512
  }
2120
- list.push([
2121
- property,
2122
- value,
2123
- condition,
2124
- identity,
2125
- cursor ? cursor[conditionSelector] : '',
2126
- cursor ? cursor[conditionWrappers] : undefined,
2127
- original,
2128
- flags | (((state as DirectState).flatPass?.[passSourceLayer] || 0) << 5),
2129
- ])
2513
+ writeStyleSlot(
2514
+ slots,
2515
+ slot,
2516
+ [
2517
+ property,
2518
+ value,
2519
+ condition,
2520
+ identity,
2521
+ cursor ? cursor[conditionSelector] : '',
2522
+ cursor ? cursor[conditionWrappers] : undefined,
2523
+ original,
2524
+ flags,
2525
+ undefined,
2526
+ !sourceLayer && direct.flatPass?.[passVariantOutput],
2527
+ ],
2528
+ sourceLayer
2529
+ )
2130
2530
  }
2131
2531
 
2132
2532
  function streamWriteInline(
@@ -2186,6 +2586,9 @@ function completeResolvedStyles(state: GetStyleState, merge: MergeStyle = mergeS
2186
2586
  const slots = direct.flatSlots
2187
2587
  if (!slots) return
2188
2588
 
2589
+ const capture = state.staticConfig.isHOC
2590
+ ? (direct.flatCapturedSlots ||= new Map())
2591
+ : undefined
2189
2592
  for (const [property, entries] of slots) {
2190
2593
  let cssEntries: AtomicSlotEntry[] | undefined
2191
2594
  let inlineWinner: AtomicSlotEntry | undefined
@@ -2220,7 +2623,21 @@ function completeResolvedStyles(state: GetStyleState, merge: MergeStyle = mergeS
2220
2623
  }
2221
2624
  }
2222
2625
  }
2223
- if (cssEntries) registerAtomicSlot(direct, property, cssEntries)
2626
+ if (cssEntries) {
2627
+ registerAtomicSlot(direct, property, cssEntries)
2628
+ if (capture) {
2629
+ // flagged css so the receiving frame keeps them as classes even when
2630
+ // it renders its own styles inline
2631
+ for (const entry of cssEntries) {
2632
+ entry[7] = entry[7]! | recordCSS
2633
+ if (!(entry[2] & 12)) continue
2634
+ for (const sibling of cssEntries) {
2635
+ if (sibling[0] === entry[0]) sibling[8] = true
2636
+ }
2637
+ }
2638
+ capture.set(property, cssEntries)
2639
+ }
2640
+ }
2224
2641
  if (inlineWinner) {
2225
2642
  if (inlineWinner[7]! & recordRetract) {
2226
2643
  if (state.style) delete state.style[inlineWinner[0]]
@@ -2317,7 +2734,9 @@ const formatScanFailure = (
2317
2734
  ? 'an unterminated "/*" comment'
2318
2735
  : failure === 'stray-comment-close'
2319
2736
  ? 'a stray "*/"'
2320
- : 'an unterminated "("'
2737
+ : failure === 'over-deep-clause'
2738
+ ? `a clause with more than ${grammarMaxNonPlatformDepth} non-platform conditions`
2739
+ : 'an unterminated "("'
2321
2740
 
2322
2741
  const warnScanFailure = (
2323
2742
  property: string,
@@ -2351,25 +2770,36 @@ let valueCacheEntries = 0
2351
2770
  const valueCacheRoot = {}
2352
2771
  const parsedSlices = new WeakMap<object, (string | undefined)[]>()
2353
2772
 
2773
+ const cssWideColorKeywords = new Set([
2774
+ 'inherit',
2775
+ 'initial',
2776
+ 'unset',
2777
+ 'revert',
2778
+ 'revert-layer',
2779
+ 'currentcolor',
2780
+ 'transparent',
2781
+ ])
2782
+
2783
+ const shadowRecipeProperties = new Set(['boxShadow', 'textShadow', 'filter'])
2784
+
2354
2785
  // `embedded` also runs the embedded-token pass when the direct lookup leaves the
2355
2786
  // value alone, and memoizes that result. it is a regex replace over most string
2356
2787
  // values, so repeating it every render of every element is the single largest
2357
2788
  // cost on this path.
2358
- const fontProperties = new Map<string, boolean>()
2359
-
2360
2789
  function configuredValue(
2361
2790
  state: GetStyleState,
2362
2791
  property: string,
2363
2792
  raw: string,
2364
- embedded = false
2793
+ embedded = false,
2794
+ nativeColors?: Map<string, unknown>
2365
2795
  ): any {
2366
2796
  const grammar = getConfigRevisionState(state.conf)
2367
2797
  let name = raw
2368
2798
  let opacity: number | undefined
2369
2799
  const slash = raw.lastIndexOf('/')
2370
2800
  if (slash > 0) {
2371
- const amount = Number(raw.slice(slash + 1))
2372
- if (Number.isInteger(amount) && amount >= 0 && amount <= 100) {
2801
+ const amount = +raw.slice(slash + 1)
2802
+ if (amount % 1 === 0 && amount >= 0 && amount <= 100) {
2373
2803
  name = raw.slice(0, slash)
2374
2804
  opacity = amount
2375
2805
  }
@@ -2381,48 +2811,39 @@ function configuredValue(
2381
2811
  return safeArea
2382
2812
  }
2383
2813
 
2384
- let fontProperty = fontProperties.get(property)
2385
- if (fontProperty === undefined) {
2386
- fontProperty =
2387
- property.startsWith('font') ||
2388
- property === 'lineHeight' ||
2389
- property === 'letterSpacing'
2390
- fontProperties.set(property, fontProperty)
2391
- }
2392
- const revision = grammar.revision
2393
- if (state.conf !== valueCacheConf || revision !== valueCacheRevision) {
2394
- valueCacheConf = state.conf
2395
- valueCacheRevision = revision
2396
- valueCaches = new WeakMap()
2397
- valueCacheEntries = 0
2398
- ;(state as DirectState).flatValueScope = undefined
2399
- }
2400
- const resolveValues =
2401
- process.env.TAMAGUI_TARGET === 'web' &&
2402
- !state.flatShouldDoClasses &&
2403
- state.styleProps.resolveValues === 'auto'
2404
- ? 'value'
2405
- : state.styleProps.resolveValues
2406
- // the scope (theme identity, name, resolveValues) is fixed for a pass apart
2407
- // from the class/inline flip, so resolve it once and key the per-value lookups
2408
- // off interned property and raw strings instead of joining them into a key
2409
- const direct = state as DirectState
2410
- let scope = direct.flatValueScope
2411
- if (scope === undefined || direct.flatValueScopeKind !== resolveValues) {
2412
- const themeObject =
2413
- state.theme && typeof state.theme === 'object' ? state.theme : valueCacheRoot
2414
- let byScope = valueCaches.get(themeObject)
2415
- if (!byScope) valueCaches.set(themeObject, (byScope = new Map()))
2416
- const scopeKey = `${state.flatThemeName || ''}\u001f${resolveValues}`
2417
- scope = byScope.get(scopeKey)
2418
- if (!scope) byScope.set(scopeKey, (scope = new Map()))
2419
- direct.flatValueScope = scope
2420
- direct.flatValueScopeKind = resolveValues
2421
- }
2422
- let maps = scope.get(property)
2423
- if (maps === undefined) scope.set(property, (maps = { direct: new Map() }))
2424
- const byRaw = embedded ? (maps.embedded ||= new Map()) : maps.direct
2425
- if (!fontProperty) {
2814
+ const fontProperty =
2815
+ property.startsWith('font') ||
2816
+ property === 'lineHeight' ||
2817
+ property === 'letterSpacing'
2818
+ const resolveValues = state.styleProps.resolveValues
2819
+ let byRaw: Map<string, any> | undefined
2820
+ if (!fontProperty && !nativeColors) {
2821
+ const revision = grammar.revision
2822
+ if (state.conf !== valueCacheConf || revision !== valueCacheRevision) {
2823
+ valueCacheConf = state.conf
2824
+ valueCacheRevision = revision
2825
+ valueCaches = new WeakMap()
2826
+ valueCacheEntries = 0
2827
+ ;(state as DirectState).flatValueScope = undefined
2828
+ }
2829
+ // the scope (theme identity, name, resolveValues) is fixed for a pass,
2830
+ // so resolve it once and key the per-value lookups
2831
+ // off interned property and raw strings instead of joining them into a key
2832
+ const direct = state as DirectState
2833
+ let scope = direct.flatValueScope
2834
+ if (scope === undefined) {
2835
+ const themeObject =
2836
+ state.theme && typeof state.theme === 'object' ? state.theme : valueCacheRoot
2837
+ let byScope = valueCaches.get(themeObject)
2838
+ if (!byScope) valueCaches.set(themeObject, (byScope = new Map()))
2839
+ const scopeKey = `${state.flatThemeName || ''}\u001f${resolveValues}`
2840
+ scope = byScope.get(scopeKey)
2841
+ if (!scope) byScope.set(scopeKey, (scope = new Map()))
2842
+ direct.flatValueScope = scope
2843
+ }
2844
+ let maps = scope.get(property)
2845
+ if (maps === undefined) scope.set(property, (maps = { direct: new Map() }))
2846
+ byRaw = embedded ? (maps.embedded ||= new Map()) : maps.direct
2426
2847
  const known = byRaw.get(raw)
2427
2848
  if (known !== undefined || byRaw.has(raw)) return known
2428
2849
  }
@@ -2477,17 +2898,120 @@ function configuredValue(
2477
2898
  }
2478
2899
 
2479
2900
  if (process.env.NODE_ENV === 'development') {
2480
- const category = grammar.tokenCategory(property)
2481
- if (category && category !== 'color' && state.conf.tokensParsed.color?.[name]) {
2901
+ const category =
2902
+ grammar.tokenCategory(property) ||
2903
+ grammar.tokenCategory(state.conf.shorthands[property] || property)
2904
+ // shadow recipes contain color tokens alongside their lengths.
2905
+ if (
2906
+ category &&
2907
+ category !== 'color' &&
2908
+ category !== 'boxShadow' &&
2909
+ category !== 'textShadow' &&
2910
+ state.conf.tokensParsed.color?.[name]
2911
+ ) {
2482
2912
  warnOnce(`"${name}" contributes to "color", not "${property}"`)
2483
2913
  }
2914
+
2915
+ if (!value && !fontProperty) {
2916
+ if (name.charCodeAt(0) === 36 || raw.charCodeAt(0) === 36) {
2917
+ const suggested = name.charCodeAt(0) === 36 ? name.slice(1) : raw.slice(1)
2918
+ warnOnce(
2919
+ `v2-token:${property}=${raw}`,
2920
+ `${property}="${raw}": v3 tokens have no "$" prefix, did you mean "${suggested}"?`
2921
+ )
2922
+ } else if (
2923
+ (category === 'size' ||
2924
+ category === 'space' ||
2925
+ category === 'radius' ||
2926
+ category === 'zIndex') &&
2927
+ /^-?\d+(?:\.\d+)?$/.test(name)
2928
+ ) {
2929
+ let nearest: string | undefined
2930
+ let minDistance = Infinity
2931
+ const rawNum = Number(name)
2932
+ const tokens = category ? state.conf.tokensParsed[category] : undefined
2933
+ if (tokens && Number.isFinite(rawNum)) {
2934
+ for (const key in tokens) {
2935
+ const val = tokens[key]?.val
2936
+ const valNum = typeof val === 'number' ? val : Number(val)
2937
+ if (Number.isFinite(valNum)) {
2938
+ const dist = Math.abs(valNum - rawNum)
2939
+ if (dist < minDistance) {
2940
+ minDistance = dist
2941
+ nearest = key
2942
+ }
2943
+ }
2944
+ }
2945
+ }
2946
+ if (nearest) {
2947
+ warnOnce(
2948
+ `numeric-token:${property}=${raw}`,
2949
+ `${property}="${raw}" was passed to CSS as-is${
2950
+ category === 'zIndex' ? '' : ' with px units'
2951
+ }${nearest ? `; nearest token is "${nearest}"` : ''}`
2952
+ )
2953
+ }
2954
+ } else if (
2955
+ category === 'color' &&
2956
+ /^[a-zA-Z0-9-]+$/.test(name) &&
2957
+ /[a-zA-Z]/.test(name)
2958
+ ) {
2959
+ const lower = name.toLowerCase()
2960
+ if (!namedCssColors.has(lower) && !cssWideColorKeywords.has(lower)) {
2961
+ const themeKeys: string[] = []
2962
+ if (state.theme && typeof state.theme === 'object') {
2963
+ for (const k in state.theme) themeKeys.push(k)
2964
+ }
2965
+ if (state.conf.themes) {
2966
+ const active = state.conf.themes[state.flatThemeName || '']
2967
+ if (active) {
2968
+ for (const k in active) themeKeys.push(k)
2969
+ } else {
2970
+ for (const t in state.conf.themes) {
2971
+ for (const k in state.conf.themes[t]) themeKeys.push(k)
2972
+ }
2973
+ }
2974
+ }
2975
+ let bestMatch: string | undefined
2976
+ let minDistance = 3
2977
+ for (const key of themeKeys) {
2978
+ if (Math.abs(key.length - name.length) > 2) continue
2979
+ const m = name.length
2980
+ const n = key.length
2981
+ const d: number[] = []
2982
+ for (let i = 0; i <= m; i++) d[i] = i
2983
+ for (let j = 1; j <= n; j++) {
2984
+ let prev = d[0]
2985
+ d[0] = j
2986
+ for (let i = 1; i <= m; i++) {
2987
+ const temp = d[i]
2988
+ d[i] =
2989
+ name[i - 1] === key[j - 1] ? prev : Math.min(prev, d[i], d[i - 1]) + 1
2990
+ prev = temp
2991
+ }
2992
+ }
2993
+ const dist = d[m]
2994
+ if (dist <= 2 && dist < minDistance) {
2995
+ minDistance = dist
2996
+ bestMatch = key
2997
+ }
2998
+ }
2999
+ warnOnce(
3000
+ `unknown-color:${property}=${raw}`,
3001
+ bestMatch
3002
+ ? `unknown color "${name}", did you mean "${bestMatch}"?`
3003
+ : `unknown color "${name}"`
3004
+ )
3005
+ }
3006
+ }
3007
+ }
2484
3008
  }
2485
3009
  let out = raw
2486
3010
  if (isVariable(value)) {
2487
3011
  out =
2488
3012
  resolveValues === 'except-theme' && fromTheme
2489
3013
  ? `${THEME_REF_PREFIX}${lookupName}${opacity !== undefined ? `/${opacity}` : ''}`
2490
- : resolveVariableValue(property, value, resolveValues)
3014
+ : resolveVariableValue(nativeColors ? 'color' : property, value, resolveValues)
2491
3015
  if (opacity !== undefined) {
2492
3016
  out =
2493
3017
  process.env.TAMAGUI_TARGET === 'web'
@@ -2495,19 +3019,40 @@ function configuredValue(
2495
3019
  : (normalizeColor(out, opacity / 100) ?? out)
2496
3020
  }
2497
3021
  }
3022
+ if (nativeColors && out && typeof out === 'object') {
3023
+ const reference = `__tamagui_native_color_${nativeColors.size}`
3024
+ nativeColors.set(reference, out)
3025
+ out = reference
3026
+ }
2498
3027
  if (embedded && out === raw) {
2499
3028
  const usedSafeArea = state.flatUsesSafeArea
2500
- out = grammar.embeddedTokens(raw, (word) => configuredValue(state, property, word))
3029
+ out = grammar.embeddedTokens(raw, (word) => {
3030
+ const resolved = configuredValue(state, property, word, false, nativeColors)
3031
+ // only a bare name can be a color token; literal colors pass through as authored
3032
+ if (
3033
+ resolved !== word ||
3034
+ !shadowRecipeProperties.has(property) ||
3035
+ !/^[a-z][\w-]*$/i.test(word)
3036
+ )
3037
+ return resolved
3038
+ // a shadow recipe word that is not one of the recipe's own tokens is its
3039
+ // color. react native has no currentColor, so it reads the inherited color
3040
+ if (process.env.TAMAGUI_TARGET === 'native' && word === 'currentColor') {
3041
+ const inherited = configuredValue(state, 'color', 'color', false, nativeColors)
3042
+ return inherited === 'color' ? word : inherited
3043
+ }
3044
+ return configuredValue(state, 'color', word, false, nativeColors)
3045
+ })
2501
3046
  // a safe-area token flips state as it resolves, so a cached hit would lose it
2502
3047
  if (!usedSafeArea && state.flatUsesSafeArea) return out
2503
3048
  }
2504
- if (!fontProperty && !fromTheme) {
3049
+ if (!fontProperty && !fromTheme && !nativeColors) {
2505
3050
  if (valueCacheEntries > 8192) {
2506
3051
  valueCaches = new WeakMap()
2507
3052
  valueCacheEntries = 0
2508
3053
  } else {
2509
3054
  valueCacheEntries++
2510
- byRaw.set(raw, out)
3055
+ byRaw!.set(raw, out)
2511
3056
  }
2512
3057
  }
2513
3058
  return out
@@ -2518,20 +3063,24 @@ function ownsSourceLayer(state: GetStyleState, property: string, conditional = f
2518
3063
  const layer = direct.flatPass?.[passSourceLayer] || 0
2519
3064
  const layers = (direct.flatPropertyLayers ||= new Map())
2520
3065
  const previous = layers.get(property)
2521
- if (previous !== undefined) {
2522
- if (previous > layer) return false
2523
- if (previous < layer) {
2524
- // a conditional contribution layers over a lower tier instead of
2525
- // replacing it: flexDirection="sm:column" on a styled row keeps the
2526
- // base row while the condition is inactive. only a program's
2527
- // unconditional base transfers ownership and clears what it replaces.
2528
- if (conditional) return true
2529
- clearDirectStyle(state, property)
2530
- }
2531
- } else if (conditional) {
2532
- // don't claim the slot either, so a later lower-tier base can still join
2533
- return true
3066
+ if (!layer && !conditional && !direct.flatPass?.[passVariantOutput]) {
3067
+ // a later authored base replaces the default variant's entire output for
3068
+ // this property, including its responsive clauses. direct clauses retain
3069
+ // their own slots, so a conditional-only override still keeps the base.
3070
+ const entries = direct.flatSlots?.get(
3071
+ process.env.TAMAGUI_TARGET === 'web' ? styleSlot(property) : property
3072
+ )
3073
+ if (entries) {
3074
+ for (let index = entries.length; index--; ) {
3075
+ if (entries[index][0] === property && entries[index][9]) entries.splice(index, 1)
3076
+ }
3077
+ }
2534
3078
  }
3079
+ if (previous! > layer) return false
3080
+ // a conditional contribution retains the lower tier's base and ownership.
3081
+ // comparisons with an absent previous layer are false.
3082
+ if (conditional && previous !== layer) return true
3083
+ if (previous! < layer) clearDirectStyle(state, property)
2535
3084
  layers.set(property, layer)
2536
3085
  return true
2537
3086
  }
@@ -2574,11 +3123,17 @@ function emitProperty(
2574
3123
  const theme = cursor ? cursor[conditionTheme] : ''
2575
3124
  if (process.env.TAMAGUI_TARGET === 'native' && theme) {
2576
3125
  if (supportsDynamicColorIOS && isColorStyleKey(property)) {
2577
- const schemes = ((direct.flatDynamicColors ||= {})[property] ||= {})
2578
- schemes[theme] =
2579
- typeof originalValue === 'string' && /^[a-z]+$/i.test(originalValue)
2580
- ? originalValue
2581
- : value
3126
+ const colors = (direct.flatDynamicColors ||= {})
3127
+ let schemes = colors[property]
3128
+ if (!schemes) {
3129
+ schemes = colors[property] = {}
3130
+ const base = direct.flatSlots?.get(property)?.find((entry) => !entry[2])?.[1]
3131
+ if (base !== undefined) {
3132
+ schemes.light = extractValueFromDynamic(base, 'light')
3133
+ schemes.dark = extractValueFromDynamic(base, 'dark')
3134
+ }
3135
+ }
3136
+ schemes[theme] = extractValueFromDynamic(value, theme)
2582
3137
  streamWriteInline(
2583
3138
  state,
2584
3139
  property,
@@ -2621,6 +3176,18 @@ function emitProperty(
2621
3176
  return
2622
3177
  }
2623
3178
 
3179
+ // a lifecycle transition must outrank a base transition class while the
3180
+ // enter or exit clause is active. pseudo transitions stay class-selected.
3181
+ if (
3182
+ property === 'transition' &&
3183
+ condition & 12 &&
3184
+ !state.staticConfig.isHOC &&
3185
+ state.styleProps.isAnimated
3186
+ ) {
3187
+ streamWriteInline(state, property, value, cursor, originalValue, false, -1, true)
3188
+ return
3189
+ }
3190
+
2624
3191
  const shouldPromoteAnimatedStyle =
2625
3192
  canGenerateCSS &&
2626
3193
  !condition &&
@@ -2645,14 +3212,15 @@ function emitProperty(
2645
3212
  streamWriteInline(state, property, value, cursor, originalValue)
2646
3213
  }
2647
3214
 
2648
- function numericUnitValue(value: string, first: string, second?: string): number {
2649
- const unitLength =
2650
- value.endsWith(first) || (second !== undefined && value.endsWith(second))
2651
- ? first.length
2652
- : 0
2653
- if (!unitLength || value.length === unitLength) return Number.NaN
2654
- const numeric = Number(value.slice(0, value.length - unitLength))
2655
- return Number.isFinite(numeric) ? numeric : Number.NaN
3215
+ function numericUnitValue(value: string, first: string, second: string): number {
3216
+ return value.length > first.length && (value.endsWith(first) || value.endsWith(second))
3217
+ ? +value.slice(0, -first.length)
3218
+ : NaN
3219
+ }
3220
+
3221
+ function resolveNumericValue(value: string): string | number {
3222
+ let numeric = numericUnitValue(value, 'px', 'dp')
3223
+ return isFinite(numeric) ? numeric : isFinite((numeric = +value)) ? numeric : value
2656
3224
  }
2657
3225
 
2658
3226
  function emitBorder(
@@ -2740,19 +3308,35 @@ function emitResolved(
2740
3308
  originalValue: any,
2741
3309
  contextOnly: boolean
2742
3310
  ) {
2743
- let value = configuredValue(state, property, raw, true)
3311
+ emitProperty(
3312
+ state,
3313
+ property,
3314
+ resolveValue(state, property, raw),
3315
+ cursor,
3316
+ originalValue,
3317
+ contextOnly
3318
+ )
3319
+ }
3320
+
3321
+ function resolveValue(
3322
+ state: GetStyleState,
3323
+ property: string,
3324
+ raw: any,
3325
+ nativeColors?: Map<string, unknown>
3326
+ ) {
3327
+ let value =
3328
+ typeof raw === 'string'
3329
+ ? configuredValue(state, property, raw, true, nativeColors)
3330
+ : raw
2744
3331
  if (
2745
3332
  (process.env.TAMAGUI_TARGET === 'native' || !state.flatShouldDoClasses) &&
2746
- typeof value === 'string'
3333
+ typeof value === 'string' &&
3334
+ value !== '' &&
3335
+ property !== 'lineHeight'
2747
3336
  ) {
2748
- const unitValue = numericUnitValue(value, 'px', 'dp')
2749
- if (Number.isFinite(unitValue)) {
2750
- value = unitValue
2751
- } else if (value !== '' && Number.isFinite(Number(value))) {
2752
- value = Number(value)
2753
- }
3337
+ value = resolveNumericValue(value)
2754
3338
  }
2755
- emitProperty(state, property, value, cursor, originalValue, contextOnly)
3339
+ return value
2756
3340
  }
2757
3341
 
2758
3342
  function shadowUnit(part: any) {
@@ -2799,15 +3383,11 @@ function emitValue(
2799
3383
  }
2800
3384
 
2801
3385
  if (isVariable(raw)) {
2802
- raw = resolveVariableValue(
2803
- property,
2804
- raw,
2805
- process.env.TAMAGUI_TARGET === 'web' &&
2806
- !state.flatShouldDoClasses &&
2807
- state.styleProps.resolveValues === 'auto'
2808
- ? 'value'
2809
- : state.styleProps.resolveValues
2810
- )
3386
+ raw = resolveVariableValue(property, raw, state.styleProps.resolveValues)
3387
+ if (property === 'lineHeight') {
3388
+ emitProperty(state, property, raw, cursor, originalValue, contextOnly)
3389
+ return
3390
+ }
2811
3391
  }
2812
3392
 
2813
3393
  if (
@@ -2895,7 +3475,11 @@ function emitValue(
2895
3475
  if (canGenerateCSS && state.flatShouldDoClasses && Array.isArray(raw)) {
2896
3476
  raw = transformsToString(raw)
2897
3477
  }
2898
- if (process.env.TAMAGUI_TARGET === 'native' && typeof raw === 'string') {
3478
+ if (
3479
+ typeof raw === 'string' &&
3480
+ (process.env.TAMAGUI_TARGET === 'native' ||
3481
+ (!state.flatShouldDoClasses && state.animationDriver?.inputStyle === 'value'))
3482
+ ) {
2899
3483
  const transform = parseNativeTransform(raw)
2900
3484
  if (transform) {
2901
3485
  emitProperty(state, property, transform, cursor, originalValue, contextOnly)
@@ -2922,7 +3506,12 @@ function emitValue(
2922
3506
  }
2923
3507
  if (typeof raw === 'string' && property === 'background') {
2924
3508
  const parts = splitComponents(raw)
2925
- if (parts.length === 1 && !startsValueFunction(parts[0])) {
3509
+ if (
3510
+ parts.length === 1 &&
3511
+ (!startsValueFunction(parts[0]) ||
3512
+ (process.env.TAMAGUI_TARGET === 'native' &&
3513
+ classifyBorderComponents(parts[0]).color))
3514
+ ) {
2926
3515
  emitResolved(state, 'backgroundColor', parts[0], cursor, originalValue, contextOnly)
2927
3516
  return
2928
3517
  }
@@ -2950,7 +3539,8 @@ function emitValue(
2950
3539
  ) {
2951
3540
  if (
2952
3541
  property === 'rotate' &&
2953
- !Number.isFinite(numericUnitValue(value, 'deg', 'rad'))
3542
+ !isFinite(numericUnitValue(value, 'deg', 'rad')) &&
3543
+ (process.env.TAMAGUI_TARGET === 'native' || !startsValueFunction(value))
2954
3544
  ) {
2955
3545
  if (process.env.NODE_ENV === 'development') {
2956
3546
  warnOnce(
@@ -2963,12 +3553,7 @@ function emitValue(
2963
3553
  }
2964
3554
  return
2965
3555
  }
2966
- const unitValue = numericUnitValue(value, 'px', 'dp')
2967
- if (Number.isFinite(unitValue)) {
2968
- value = unitValue
2969
- } else if (Number.isFinite(Number(value))) {
2970
- value = Number(value)
2971
- }
3556
+ value = resolveNumericValue(value)
2972
3557
  }
2973
3558
  if (!canGenerateCSS || !state.flatShouldDoClasses) {
2974
3559
  emitProperty(state, property, value, cursor, originalValue, contextOnly)
@@ -3015,22 +3600,15 @@ function emitValue(
3015
3600
  return
3016
3601
  }
3017
3602
 
3018
- let value: any = raw
3019
- if (typeof raw === 'string') {
3020
- value = configuredValue(state, property, raw, true)
3021
- }
3022
-
3023
- if (
3024
- (process.env.TAMAGUI_TARGET === 'native' || !state.flatShouldDoClasses) &&
3025
- typeof value === 'string'
3026
- ) {
3027
- const unitValue = numericUnitValue(value, 'px', 'dp')
3028
- if (Number.isFinite(unitValue)) {
3029
- value = unitValue
3030
- } else if (value !== '' && Number.isFinite(Number(value))) {
3031
- value = Number(value)
3032
- }
3033
- }
3603
+ const nativeColors =
3604
+ process.env.TAMAGUI_TARGET === 'native' &&
3605
+ typeof raw === 'string' &&
3606
+ (property === 'backgroundImage' ||
3607
+ property === 'boxShadow' ||
3608
+ property === 'textShadow')
3609
+ ? new Map<string, unknown>()
3610
+ : undefined
3611
+ let value: any = resolveValue(state, property, raw, nativeColors)
3034
3612
  if (
3035
3613
  canGenerateCSS &&
3036
3614
  state.flatShouldDoClasses &&
@@ -3048,7 +3626,7 @@ function emitValue(
3048
3626
  property === 'boxShadow' ||
3049
3627
  property === 'textShadow')
3050
3628
  ) {
3051
- const parsed = parseNativeStyle(property, value)
3629
+ const parsed = parseNativeStyle(property, value, nativeColors)
3052
3630
  if (parsed) {
3053
3631
  if (property === 'textShadow') {
3054
3632
  for (const [key, parsedValue] of parsed) {
@@ -3066,6 +3644,8 @@ function emitValue(
3066
3644
  }
3067
3645
  return
3068
3646
  }
3647
+ // unmapped css names cannot become native host styles.
3648
+ if (property === 'backgroundImage' || property === 'textShadow') return
3069
3649
  }
3070
3650
 
3071
3651
  if (
@@ -3105,6 +3685,23 @@ function emitValue(
3105
3685
  : `${value} 0px`
3106
3686
  }
3107
3687
 
3688
+ if (process.env.TAMAGUI_TARGET === 'native' && !cursor && !state.styleProps.noExpand) {
3689
+ const logicals = nativeShorthandLogicals[property]
3690
+ const slots = (state as DirectState).flatSlots
3691
+ if (logicals && slots) {
3692
+ for (let index = 0; index < logicals.length; index++) {
3693
+ const list = slots.get(logicals[index])
3694
+ if (!list) continue
3695
+ // only the unconditional records: a media or pseudo longhand still
3696
+ // wins while its clause is active, the same as on web
3697
+ for (let entry = list.length; entry--; ) {
3698
+ if (list[entry][3] === '') list.splice(entry, 1)
3699
+ }
3700
+ if (!list.length) clearDirectStyle(state, logicals[index])
3701
+ }
3702
+ }
3703
+ }
3704
+
3108
3705
  const expanded =
3109
3706
  process.env.TAMAGUI_TARGET === 'native' && !state.styleProps.noExpand
3110
3707
  ? expandStyle(property, value, state.conf.settings.styleCompat || 'web')
@@ -3114,7 +3711,14 @@ function emitValue(
3114
3711
  return
3115
3712
  }
3116
3713
 
3117
- if (typeof raw === 'string' && expanded.length > 1) {
3714
+ // an expansion that already computed distinct per-slot values (direction,
3715
+ // visibility) is used as-is; only a same-value fan-out (margin, padding)
3716
+ // distributes the raw string parts per css slot order
3717
+ if (
3718
+ typeof raw === 'string' &&
3719
+ expanded.length > 1 &&
3720
+ expanded.every((entry) => entry[1] === expanded[0][1])
3721
+ ) {
3118
3722
  const parts = splitComponents(raw)
3119
3723
  if (parts.length > 0 && parts.length <= (expanded.length === 4 ? 4 : 2)) {
3120
3724
  for (let index = 0; index < expanded.length; index++) {
@@ -3150,13 +3754,46 @@ function emitValue(
3150
3754
  }
3151
3755
  }
3152
3756
 
3757
+ type ConditionalValueSink = (payload: any, condition: unknown, source: any) => void
3758
+
3759
+ function emitConditionalValue(
3760
+ state: GetStyleState,
3761
+ property: string,
3762
+ payload: any,
3763
+ condition: Condition | null,
3764
+ source: any,
3765
+ sink: ConditionalValueSink | null,
3766
+ mode: number,
3767
+ contextOnly: boolean
3768
+ ) {
3769
+ if (sink) {
3770
+ sink(payload, condition, source)
3771
+ } else if (condition) {
3772
+ emitUnderCondition(
3773
+ state,
3774
+ property,
3775
+ payload,
3776
+ condition,
3777
+ mode === 2 || state.staticConfig.isHOC || state.styleProps.stylePieceEntries
3778
+ ? payload
3779
+ : undefined,
3780
+ contextOnly,
3781
+ mode,
3782
+ source
3783
+ )
3784
+ } else {
3785
+ emitValue(state, property, payload, null, payload, contextOnly)
3786
+ }
3787
+ }
3788
+
3153
3789
  export function walkConditionalValue(
3154
3790
  state: GetStyleState,
3155
3791
  property: string,
3156
3792
  value: any,
3157
3793
  parent: unknown,
3158
- sink: (payload: any, condition: unknown, source: any) => void,
3159
- warnMode = 0
3794
+ sink: ConditionalValueSink | null,
3795
+ warnMode = 0,
3796
+ contextOnly = false
3160
3797
  ) {
3161
3798
  const parentCondition = (parent as Condition) || null
3162
3799
  let hasBase = false
@@ -3165,6 +3802,21 @@ export function walkConditionalValue(
3165
3802
  if (typeof value === 'string') {
3166
3803
  const parsed = getConfigRevisionState(state.conf).parseFlatValue(value)
3167
3804
  const [segments, failure, failureIndex] = parsed
3805
+ if (process.env.NODE_ENV === 'development') {
3806
+ const syntax = getSetting('styleValueSyntax')
3807
+ if (syntax === 'object') {
3808
+ const hasClause =
3809
+ segments.length > 5 ||
3810
+ (segments.length >= 5 && segments[2] !== -1) ||
3811
+ value.includes(':')
3812
+ if (hasClause) {
3813
+ warnOnce(
3814
+ `syntax:string:${property}=${value}`,
3815
+ `string syntax is disabled by config (styleValueSyntax: 'object'); received "${property}=${value}"`
3816
+ )
3817
+ }
3818
+ }
3819
+ }
3168
3820
  // the parse result is cached per authored string, so its payload and chain
3169
3821
  // substrings can be too. without this every render of every element re-slices
3170
3822
  // the same pieces out of the same value
@@ -3172,9 +3824,9 @@ export function walkConditionalValue(
3172
3824
  if (slices === undefined) parsedSlices.set(parsed, (slices = []))
3173
3825
  const chainCount = segments.length / 5 - 1
3174
3826
  if (property === 'aspectRatio' && chainCount === 1) {
3175
- const left = Number(value.slice(segments[7], segments[8]))
3176
- const right = Number(value.slice(segments[5], segments[6]))
3177
- if (left > 0 && right > 0 && Number.isFinite(left) && Number.isFinite(right)) {
3827
+ const left = +value.slice(segments[7], segments[8])
3828
+ const right = +value.slice(segments[5], segments[6])
3829
+ if (left > 0 && right > 0 && isFinite(left) && isFinite(right)) {
3178
3830
  return false
3179
3831
  }
3180
3832
  }
@@ -3189,7 +3841,16 @@ export function walkConditionalValue(
3189
3841
  if (start === end) continue
3190
3842
  if (flags & 2) {
3191
3843
  const payload = (slices[index] ??= value.slice(start, end))
3192
- sink(payload, parentCondition, payload)
3844
+ emitConditionalValue(
3845
+ state,
3846
+ property,
3847
+ payload,
3848
+ parentCondition,
3849
+ payload,
3850
+ sink,
3851
+ warnMode,
3852
+ contextOnly
3853
+ )
3193
3854
  hasBase = true
3194
3855
  } else if (
3195
3856
  process.env.NODE_ENV !== 'production' &&
@@ -3197,7 +3858,16 @@ export function walkConditionalValue(
3197
3858
  !chainCount &&
3198
3859
  (failure === 'invalid-character' || failure === 'stray-comment-close')
3199
3860
  ) {
3200
- sink(value, parentCondition, value)
3861
+ emitConditionalValue(
3862
+ state,
3863
+ property,
3864
+ value,
3865
+ parentCondition,
3866
+ value,
3867
+ sink,
3868
+ warnMode,
3869
+ contextOnly
3870
+ )
3201
3871
  hasBase = true
3202
3872
  } else if (warnMode) {
3203
3873
  warnScanFailure(property, value, failure, failureIndex)
@@ -3227,7 +3897,16 @@ export function walkConditionalValue(
3227
3897
  )
3228
3898
  conditions |= cursor[conditionValue]
3229
3899
  if (cursor[conditionValue] & conditionResolvedFlag || warnMode) {
3230
- sink((slices[index] ??= value.slice(start, end)), cursor, value)
3900
+ emitConditionalValue(
3901
+ state,
3902
+ property,
3903
+ (slices[index] ??= value.slice(start, end)),
3904
+ cursor,
3905
+ value,
3906
+ sink,
3907
+ warnMode,
3908
+ contextOnly
3909
+ )
3231
3910
  }
3232
3911
  }
3233
3912
  if (process.env.NODE_ENV !== 'production') lastPayload = value.slice(lastPayloadStart)
@@ -3241,8 +3920,26 @@ export function walkConditionalValue(
3241
3920
  ) {
3242
3921
  return false
3243
3922
  }
3923
+ if (process.env.NODE_ENV === 'development') {
3924
+ const syntax = getSetting('styleValueSyntax')
3925
+ if (syntax === 'string') {
3926
+ warnOnce(
3927
+ `syntax:object:${property}=${JSON.stringify(value)}`,
3928
+ `object-form conditional syntax is disabled by config (styleValueSyntax: 'string'); received "${property}"`
3929
+ )
3930
+ }
3931
+ }
3244
3932
  if (value.default != null) {
3245
- sink(value.default, parentCondition, value.default)
3933
+ emitConditionalValue(
3934
+ state,
3935
+ property,
3936
+ value.default,
3937
+ parentCondition,
3938
+ value.default,
3939
+ sink,
3940
+ warnMode,
3941
+ contextOnly
3942
+ )
3246
3943
  hasBase = true
3247
3944
  }
3248
3945
  for (const key in value) {
@@ -3250,7 +3947,16 @@ export function walkConditionalValue(
3250
3947
  const cursor = conditionFromKey(state, key, parentCondition)
3251
3948
  conditions |= cursor[conditionValue]
3252
3949
  if (cursor[conditionValue] & conditionResolvedFlag || warnMode) {
3253
- sink(value[key], cursor, value[key])
3950
+ emitConditionalValue(
3951
+ state,
3952
+ property,
3953
+ value[key],
3954
+ cursor,
3955
+ value[key],
3956
+ sink,
3957
+ warnMode,
3958
+ contextOnly
3959
+ )
3254
3960
  }
3255
3961
  }
3256
3962
  }
@@ -3262,21 +3968,24 @@ export function walkConditionalValue(
3262
3968
  !hasBase &&
3263
3969
  conditions &&
3264
3970
  getConfigRevisionState(state.conf).tokenCategory(property) &&
3971
+ getConfigRevisionState(state.conf).propertyKind(property) !== 8 &&
3972
+ property !== 'boxShadow' &&
3973
+ property !== 'textShadow' &&
3974
+ property !== 'fontFamily' &&
3975
+ property !== 'gap' &&
3265
3976
  splitComponents(lastPayload).length > 1
3266
3977
  ) {
3267
3978
  warnOnce(
3268
3979
  `${property}="${value}" has multiple values after its first conditional. Write the base value before the first conditional.`
3269
3980
  )
3270
3981
  }
3271
- if (
3272
- warnMode === 1 &&
3273
- (!canGenerateCSS || !state.flatShouldDoClasses) &&
3274
- conditions & 12 &&
3275
- !hasBase
3276
- ) {
3277
- // inline lifecycle styles need a natural resting value when no base was
3278
- // authored anywhere: a lower tier that owns the property (a styled default)
3279
- // is the resting value already, so don't stamp over it
3982
+ if (warnMode === 1 && conditions & 12 && !hasBase) {
3983
+ // a property whose only values are lifecycle clauses has no resting value,
3984
+ // so synthesize the CSS initial as its base. the styled HOC is usually the
3985
+ // only pass that ever walks the authored value (the leaf receives captured
3986
+ // slots), so this cannot be left to whichever pass renders inline. a lower
3987
+ // tier that owns the property (a styled default) is the resting value
3988
+ // already, so don't stamp over it
3280
3989
  const resting =
3281
3990
  property === 'opacity' || property.startsWith('scale')
3282
3991
  ? 1
@@ -3285,8 +3994,38 @@ export function walkConditionalValue(
3285
3994
  : property === 'x' || property === 'y'
3286
3995
  ? 0
3287
3996
  : null
3288
- if (resting !== null && !(state as DirectState).flatPropertyLayers?.has(property)) {
3289
- sink(resting, parentCondition, resting)
3997
+ // a transform is emitted under its composition key on the class path, so
3998
+ // the ownership check has to ask about that key. asking for the authored
3999
+ // name always misses there and stamps this base over the styled default
4000
+ // that already owns the property, dropping its lifecycle clauses with it
4001
+ const layers = (state as DirectState).flatPropertyLayers
4002
+ const owned =
4003
+ !canGenerateCSS || !state.flatShouldDoClasses
4004
+ ? layers?.has(property)
4005
+ : property === 'scale'
4006
+ ? layers?.has('--t-scale-x') || layers?.has('--t-scale-y')
4007
+ : layers?.has(
4008
+ property === 'x'
4009
+ ? '--t-x'
4010
+ : property === 'y'
4011
+ ? '--t-y'
4012
+ : property === 'scaleX'
4013
+ ? '--t-scale-x'
4014
+ : property === 'scaleY'
4015
+ ? '--t-scale-y'
4016
+ : property
4017
+ )
4018
+ if (resting !== null && !owned) {
4019
+ emitConditionalValue(
4020
+ state,
4021
+ property,
4022
+ resting,
4023
+ parentCondition,
4024
+ resting,
4025
+ sink,
4026
+ warnMode,
4027
+ contextOnly
4028
+ )
3290
4029
  }
3291
4030
  }
3292
4031
  return true
@@ -3300,6 +4039,30 @@ function contributeValue(
3300
4039
  contextOnly = false,
3301
4040
  condition?: Condition | string
3302
4041
  ) {
4042
+ // every style source shares this path, including style objects and resolvers.
4043
+ if (
4044
+ !contextOnly &&
4045
+ isRemovedVendorStyleProp(property) &&
4046
+ !(state.staticConfig.validStyles && property in state.staticConfig.validStyles)
4047
+ ) {
4048
+ return
4049
+ }
4050
+ if (
4051
+ process.env.TAMAGUI_TARGET === 'native' &&
4052
+ !contextOnly &&
4053
+ !(
4054
+ property in
4055
+ (state.staticConfig.validStyles ||
4056
+ (state.staticConfig.isInput
4057
+ ? stylePropsInput
4058
+ : state.staticConfig.isText
4059
+ ? stylePropsText
4060
+ : validStylesView))
4061
+ ) &&
4062
+ property in stylePropsAll
4063
+ ) {
4064
+ return
4065
+ }
3303
4066
  if (condition !== undefined) {
3304
4067
  const directState = state as DirectState
3305
4068
  const parent = (directState.flatPass?.[passParentCursor] as Condition) || null
@@ -3319,24 +4082,7 @@ function contributeValue(
3319
4082
  }
3320
4083
  if (
3321
4084
  typeof value !== 'string' &&
3322
- walkConditionalValue(
3323
- state,
3324
- property,
3325
- value,
3326
- effective,
3327
- (payload, cursor, source) =>
3328
- emitUnderCondition(
3329
- state,
3330
- property,
3331
- payload,
3332
- cursor as Condition,
3333
- payload,
3334
- contextOnly,
3335
- 2,
3336
- source
3337
- ),
3338
- 2
3339
- )
4085
+ walkConditionalValue(state, property, value, effective, null, 2, contextOnly)
3340
4086
  ) {
3341
4087
  return true
3342
4088
  }
@@ -3383,28 +4129,7 @@ function contributeValue(
3383
4129
  }
3384
4130
  const parent =
3385
4131
  ((state as DirectState).flatPass?.[passParentCursor] as Condition) || null
3386
- if (
3387
- walkConditionalValue(
3388
- state,
3389
- property,
3390
- value,
3391
- parent,
3392
- (payload, cursor, source) =>
3393
- cursor
3394
- ? emitUnderCondition(
3395
- state,
3396
- property,
3397
- payload,
3398
- cursor as Condition,
3399
- undefined,
3400
- contextOnly,
3401
- 1,
3402
- source
3403
- )
3404
- : emitValue(state, property, payload, null, payload, contextOnly),
3405
- 1
3406
- )
3407
- )
4132
+ if (walkConditionalValue(state, property, value, parent, null, 1, contextOnly))
3408
4133
  return true
3409
4134
  if (value != null) {
3410
4135
  emitAtParentCondition(state, property, value, originalValue ?? value, contextOnly)
@@ -3414,7 +4139,10 @@ function contributeValue(
3414
4139
  }
3415
4140
 
3416
4141
  function clearDirectStyle(state: GetStyleState, property: string) {
4142
+ if (process.env.TAMAGUI_TARGET === 'native' && property === 'lineHeight')
4143
+ state.nativeLineHeight = undefined
3417
4144
  const direct = state as DirectState
4145
+ if (direct.flatDynamicColors) delete direct.flatDynamicColors[property]
3418
4146
  if (process.env.TAMAGUI_TARGET === 'web') property = webStyleProperty(property)
3419
4147
  const propertyKind = getConfigRevisionState(state.conf).propertyKind(property)
3420
4148
  const atomicKey = property.startsWith('transition')
@@ -3429,15 +4157,20 @@ function clearDirectStyle(state: GetStyleState, property: string) {
3429
4157
  const slot = process.env.TAMAGUI_TARGET === 'web' ? styleSlot(atomicKey) : atomicKey
3430
4158
  direct.flatAtomics?.delete(slot)
3431
4159
  if (direct.flatSlots) {
3432
- if (slot !== atomicKey) {
4160
+ // a slot groups related properties under one atomic class. clearing a
4161
+ // longhand removes only its records, and so does clearing `flex`, which
4162
+ // shares its slot with flexDirection and flexWrap: <XStack flex={undefined} />
4163
+ // keeps the styled row
4164
+ if (slot !== atomicKey || atomicKey === 'flex') {
3433
4165
  const entries = direct.flatSlots.get(slot)
3434
4166
  if (entries) {
3435
4167
  for (let index = entries.length; index--; ) {
3436
4168
  if (entries[index][0] === atomicKey) entries.splice(index, 1)
3437
4169
  }
4170
+ if (!entries.length) direct.flatSlots.delete(slot)
3438
4171
  }
3439
4172
  }
3440
- direct.flatSlots.delete(atomicKey)
4173
+ if (atomicKey !== 'flex') direct.flatSlots.delete(atomicKey)
3441
4174
  }
3442
4175
  if (atomicKey === 'transform') state.transformAccumulator = undefined
3443
4176
  if (state.style) delete state.style[atomicKey]
@@ -3470,9 +4203,12 @@ export function emitVariantStyle(
3470
4203
  {})[key] = original
3471
4204
  }
3472
4205
  const parent = pass[passParentCursor]
4206
+ const parentVariantOutput = pass[passVariantOutput]
3473
4207
  pass[passParentCursor] = condition
4208
+ pass[passVariantOutput] = true
3474
4209
  contributeProp(pass, key, value, original, disabled)
3475
4210
  pass[passParentCursor] = parent
4211
+ pass[passVariantOutput] = parentVariantOutput
3476
4212
  }
3477
4213
 
3478
4214
  // handles finding and resolving the fontFamily to the token name