@tamagui/web 1.36.6 → 1.37.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/dist/cjs/constants/accessibilityDirectMap.native.js +3 -0
  2. package/dist/cjs/constants/accessibilityDirectMap.native.js.map +1 -1
  3. package/dist/cjs/createComponent.js +29 -25
  4. package/dist/cjs/createComponent.js.map +1 -1
  5. package/dist/cjs/createTamagui.js +8 -9
  6. package/dist/cjs/createTamagui.js.map +1 -1
  7. package/dist/cjs/helpers/ThemeManager.js +2 -2
  8. package/dist/cjs/helpers/ThemeManager.js.map +1 -1
  9. package/dist/cjs/helpers/createPropMapper.js +7 -6
  10. package/dist/cjs/helpers/createPropMapper.js.map +1 -1
  11. package/dist/cjs/helpers/extendStaticConfig.js +3 -2
  12. package/dist/cjs/helpers/extendStaticConfig.js.map +1 -1
  13. package/dist/cjs/helpers/getSplitStyles.js +178 -228
  14. package/dist/cjs/helpers/getSplitStyles.js.map +2 -2
  15. package/dist/cjs/helpers/getStylesAtomic.js +1 -1
  16. package/dist/cjs/helpers/getStylesAtomic.js.map +1 -1
  17. package/dist/cjs/helpers/getThemeCSSRules.js +1 -1
  18. package/dist/cjs/helpers/getThemeCSSRules.js.map +1 -1
  19. package/dist/cjs/hooks/useMedia.js +3 -2
  20. package/dist/cjs/hooks/useMedia.js.map +1 -1
  21. package/dist/cjs/styled.js +10 -6
  22. package/dist/cjs/styled.js.map +1 -1
  23. package/dist/esm/constants/accessibilityDirectMap.native.js +2 -0
  24. package/dist/esm/constants/accessibilityDirectMap.native.js.map +1 -1
  25. package/dist/esm/createComponent.js +29 -25
  26. package/dist/esm/createComponent.js.map +1 -1
  27. package/dist/esm/createTamagui.js +8 -9
  28. package/dist/esm/createTamagui.js.map +1 -1
  29. package/dist/esm/helpers/ThemeManager.js +2 -2
  30. package/dist/esm/helpers/ThemeManager.js.map +1 -1
  31. package/dist/esm/helpers/createPropMapper.js +7 -6
  32. package/dist/esm/helpers/createPropMapper.js.map +1 -1
  33. package/dist/esm/helpers/extendStaticConfig.js +3 -2
  34. package/dist/esm/helpers/extendStaticConfig.js.map +1 -1
  35. package/dist/esm/helpers/getSplitStyles.js +178 -229
  36. package/dist/esm/helpers/getSplitStyles.js.map +2 -2
  37. package/dist/esm/helpers/getStylesAtomic.js +1 -1
  38. package/dist/esm/helpers/getStylesAtomic.js.map +1 -1
  39. package/dist/esm/helpers/getThemeCSSRules.js +1 -1
  40. package/dist/esm/helpers/getThemeCSSRules.js.map +1 -1
  41. package/dist/esm/hooks/useMedia.js +3 -2
  42. package/dist/esm/hooks/useMedia.js.map +1 -1
  43. package/dist/esm/styled.js +10 -6
  44. package/dist/esm/styled.js.map +1 -1
  45. package/package.json +9 -9
  46. package/src/constants/accessibilityDirectMap.native.tsx +3 -0
  47. package/src/createComponent.tsx +37 -25
  48. package/src/createTamagui.ts +16 -9
  49. package/src/helpers/ThemeManager.tsx +2 -2
  50. package/src/helpers/createPropMapper.ts +7 -12
  51. package/src/helpers/extendStaticConfig.ts +6 -2
  52. package/src/helpers/getSplitStyles.tsx +268 -281
  53. package/src/helpers/getStylesAtomic.ts +1 -1
  54. package/src/helpers/getThemeCSSRules.ts +4 -1
  55. package/src/hooks/useMedia.tsx +6 -3
  56. package/src/styled.tsx +8 -4
  57. package/src/types.tsx +7 -2
  58. package/types/constants/accessibilityDirectMap.native.d.ts +1 -0
  59. package/types/helpers/getSplitStyles.d.ts +1 -1
  60. package/types/types.d.ts +5 -3
  61. package/types/Tamagui.d.ts.map +0 -1
  62. package/types/config.d.ts.map +0 -1
  63. package/types/constants/accessibilityDirectMap.d.ts.map +0 -1
  64. package/types/constants/accessibilityDirectMap.native.d.ts.map +0 -1
  65. package/types/constants/constants.d.ts.map +0 -1
  66. package/types/constants/isDevTools.d.ts.map +0 -1
  67. package/types/contexts/AnimationDriverContext.d.ts.map +0 -1
  68. package/types/contexts/ButtonNestingContext.d.ts.map +0 -1
  69. package/types/contexts/FontLanguageContext.d.ts.map +0 -1
  70. package/types/contexts/TextAncestorContext.d.ts.map +0 -1
  71. package/types/createComponent.d.ts.map +0 -1
  72. package/types/createFont.d.ts.map +0 -1
  73. package/types/createShorthands.d.ts.map +0 -1
  74. package/types/createTamagui.d.ts.map +0 -1
  75. package/types/createTheme.d.ts.map +0 -1
  76. package/types/createTokens.d.ts.map +0 -1
  77. package/types/createVariable.d.ts.map +0 -1
  78. package/types/createVariables.d.ts.map +0 -1
  79. package/types/helpers/ThemeManager.d.ts.map +0 -1
  80. package/types/helpers/ThemeManagerContext.d.ts.map +0 -1
  81. package/types/helpers/createChainedWeakCache.d.ts.map +0 -1
  82. package/types/helpers/createMediaStyle.d.ts.map +0 -1
  83. package/types/helpers/createPropMapper.d.ts.map +0 -1
  84. package/types/helpers/createProxy.d.ts.map +0 -1
  85. package/types/helpers/createStyledContext.d.ts.map +0 -1
  86. package/types/helpers/defaultOffset.d.ts.map +0 -1
  87. package/types/helpers/expandStyle.d.ts.map +0 -1
  88. package/types/helpers/expandStyles.d.ts.map +0 -1
  89. package/types/helpers/extendStaticConfig.d.ts.map +0 -1
  90. package/types/helpers/getAnimationDriver.d.ts.map +0 -1
  91. package/types/helpers/getExpandedShorthands.d.ts.map +0 -1
  92. package/types/helpers/getFontLanguage.d.ts.map +0 -1
  93. package/types/helpers/getSplitStyles.d.ts.map +0 -1
  94. package/types/helpers/getStylesAtomic.d.ts.map +0 -1
  95. package/types/helpers/getStylesAtomic.native.d.ts.map +0 -1
  96. package/types/helpers/getThemeCSSRules.d.ts.map +0 -1
  97. package/types/helpers/getThemeCSSRules.native.d.ts.map +0 -1
  98. package/types/helpers/getVariantExtras.d.ts.map +0 -1
  99. package/types/helpers/insertStyleRule.d.ts.map +0 -1
  100. package/types/helpers/isObj.d.ts.map +0 -1
  101. package/types/helpers/isTamaguiComponent.d.ts.map +0 -1
  102. package/types/helpers/isTamaguiElement.d.ts.map +0 -1
  103. package/types/helpers/matchMedia.d.ts.map +0 -1
  104. package/types/helpers/matchMedia.native.d.ts.map +0 -1
  105. package/types/helpers/mergeProps.d.ts.map +0 -1
  106. package/types/helpers/normalizeColor.d.ts.map +0 -1
  107. package/types/helpers/normalizeShadow.d.ts.map +0 -1
  108. package/types/helpers/normalizeShadow.native.d.ts.map +0 -1
  109. package/types/helpers/normalizeStylePropKeys.d.ts.map +0 -1
  110. package/types/helpers/normalizeStylePropKeys.native.d.ts.map +0 -1
  111. package/types/helpers/normalizeValueWithProperty.d.ts.map +0 -1
  112. package/types/helpers/objectIdentityKey.d.ts.map +0 -1
  113. package/types/helpers/proxyThemeVariables.d.ts.map +0 -1
  114. package/types/helpers/pseudoDescriptors.d.ts.map +0 -1
  115. package/types/helpers/registerCSSVariable.d.ts.map +0 -1
  116. package/types/helpers/themeable.d.ts.map +0 -1
  117. package/types/helpers/themes.d.ts.map +0 -1
  118. package/types/helpers/timer.d.ts.map +0 -1
  119. package/types/helpers/useShallowSetState.d.ts.map +0 -1
  120. package/types/helpers/withStaticProperties.d.ts.map +0 -1
  121. package/types/hooks/getThemeUnwrapped.d.ts.map +0 -1
  122. package/types/hooks/useAnimationDriver.d.ts.map +0 -1
  123. package/types/hooks/useId.d.ts.map +0 -1
  124. package/types/hooks/useIsTouchDevice.d.ts.map +0 -1
  125. package/types/hooks/useMedia.d.ts.map +0 -1
  126. package/types/hooks/useProps.d.ts.map +0 -1
  127. package/types/hooks/useSafeRef.d.ts.map +0 -1
  128. package/types/hooks/useServerHooks.d.ts.map +0 -1
  129. package/types/hooks/useStyle.d.ts.map +0 -1
  130. package/types/hooks/useTheme.d.ts.map +0 -1
  131. package/types/hooks/useThemeName.d.ts.map +0 -1
  132. package/types/index.d.ts.map +0 -1
  133. package/types/inject-styles.d.ts.map +0 -1
  134. package/types/insertFont.d.ts.map +0 -1
  135. package/types/setupHooks.d.ts.map +0 -1
  136. package/types/setupReactNative.d.ts.map +0 -1
  137. package/types/styled.d.ts.map +0 -1
  138. package/types/types.d.ts.map +0 -1
  139. package/types/views/AnimationDriverProvider.d.ts.map +0 -1
  140. package/types/views/FontLanguage.d.ts.map +0 -1
  141. package/types/views/FontLanguage.native.d.ts.map +0 -1
  142. package/types/views/FontLanguage.types.d.ts.map +0 -1
  143. package/types/views/Slot.d.ts.map +0 -1
  144. package/types/views/Stack.d.ts.map +0 -1
  145. package/types/views/TamaguiProvider.d.ts.map +0 -1
  146. package/types/views/Text.d.ts.map +0 -1
  147. package/types/views/Theme.d.ts.map +0 -1
  148. package/types/views/ThemeDebug.d.ts.map +0 -1
  149. package/types/views/ThemeDebug.native.d.ts.map +0 -1
  150. package/types/views/ThemeProvider.d.ts.map +0 -1
  151. package/types/views/View.d.ts.map +0 -1
@@ -7,7 +7,6 @@ import {
7
7
  useIsomorphicLayoutEffect,
8
8
  } from '@tamagui/constants'
9
9
  import {
10
- stylePropsFont,
11
10
  stylePropsText,
12
11
  stylePropsTransform,
13
12
  validPseudoKeys,
@@ -103,6 +102,7 @@ type StyleSplitter = (
103
102
  ) => GetStyleResult
104
103
 
105
104
  export const PROP_SPLIT = '-'
105
+ let defaultFontVariable = ''
106
106
 
107
107
  // loop props backwards
108
108
  // track used keys:
@@ -128,10 +128,10 @@ export const getSplitStyles: StyleSplitter = (
128
128
  const validStyleProps = staticConfig.isText ? stylePropsText : validStyles
129
129
  const viewProps: GetStyleResult['viewProps'] = {}
130
130
  let pseudos: PseudoStyles | null = null
131
- let psuedosUsed: Record<string, number> | null = null
132
131
  const mediaState = state.mediaState || globalMediaState
133
132
  const usedKeys: Record<string, number> = {}
134
133
  const propKeys = Object.keys(props)
134
+ const numProps = propKeys.length
135
135
  let space: SpaceTokens | null = props.space
136
136
  let hasMedia: boolean | string[] = false
137
137
 
@@ -140,14 +140,13 @@ export const getSplitStyles: StyleSplitter = (
140
140
 
141
141
  let style: ViewStyleWithPseudos = {}
142
142
  const flatTransforms: FlatTransforms = {}
143
-
144
- const len = propKeys.length
145
143
  const rulesToInsert: RulesToInsert = []
146
144
  const classNames: ClassNamesObject = {}
147
145
  let className = '' // existing classNames
148
146
  // we need to gather these specific to each media query / pseudo
149
147
  // value is [hash, val], so ["-jnjad-asdnjk", "scaleX(1) rotate(10deg)"]
150
148
  const transforms: Record<TransformNamespaceKey, [string, string]> = {}
149
+
151
150
  // fontFamily is our special baby, ensure we grab the latest set one always
152
151
  let fontFamily: string | undefined
153
152
 
@@ -167,15 +166,17 @@ export const getSplitStyles: StyleSplitter = (
167
166
  languageContext,
168
167
  }
169
168
 
170
- if (process.env.NODE_ENV === 'development' && debug) {
171
- console.groupCollapsed('getSplitStyles (looping backwards)')
169
+ if (process.env.NODE_ENV === 'development' && debug && isClient) {
170
+ console.groupCollapsed('getSplitStyles (collapsed)')
172
171
  // prettier-ignore
173
172
  // rome-ignore lint/nursery/noConsoleLog: ok
174
173
  console.log({ props, staticConfig, shouldDoClasses, state, IS_STATIC, propKeys, styleState, theme: { ...theme } })
175
174
  console.groupEnd()
176
175
  }
177
176
 
178
- if (props.className) {
177
+ // handle before the loop so we can mark usedKeys in className
178
+ // since the compiler will optimize to className we just treat className as the more powerful
179
+ if (typeof props.className === 'string') {
179
180
  for (const cn of props.className.split(' ')) {
180
181
  if (cn[0] === '_') {
181
182
  // tamagui, merge it expanded on key, eventually this will go away with better compiler
@@ -202,59 +203,59 @@ export const getSplitStyles: StyleSplitter = (
202
203
  }
203
204
  }
204
205
 
205
- function passDownProp(
206
- key: string,
207
- val: any,
208
- shouldMergeObject = key in pseudoDescriptors
209
- ) {
210
- if (shouldMergeObject) {
211
- viewProps[key] ||= {}
212
- // we are going backwards to apply in front
213
- viewProps[key] = {
214
- ...val,
215
- ...viewProps[key],
216
- }
217
- } else {
218
- usedKeys[key] = 1
219
- viewProps[key] = val
220
- }
221
- }
222
-
223
- /**
224
- * Need to process these after done with flattening the rest of the props + variants/mediam when we have the final font family.
225
- *
226
- * We use this because fonts are grouped together and cannot be processed correctly without the correct font family.
227
- */
228
- const specialProps: [string, any][] = []
229
-
230
- function processProp(
231
- keyInit: string,
232
- valInit: any,
233
- special = false,
234
- fontFamilyOverride: any = null
235
- ) {
236
- if (keyInit === 'className') return // handled above
206
+ for (let i = 0; i < numProps; i++) {
207
+ let keyInit = propKeys[i]
208
+ let valInit = props[keyInit]
237
209
 
238
210
  // normalize shorthands up front
239
211
  if (keyInit in shorthands) {
240
212
  keyInit = shorthands[keyInit]
241
213
  }
242
214
 
243
- // edge-case: given we have `role="A"`, without this check, `accessibilityRole="B"` doesn't overwrite `role` and the value remains "A"
244
- if (keyInit === 'accessibilityRole') {
245
- usedKeys['role'] = 1
215
+ if (keyInit === 'className') continue // handled above
216
+ if (keyInit in usedKeys) continue
217
+
218
+ if (process.env.TAMAGUI_TARGET === 'web') {
219
+ if (typeof valInit === 'string' && valInit[0] === '_') {
220
+ if (keyInit in validStyleProps || keyInit.includes('-')) {
221
+ if (process.env.NODE_ENV === 'development' && debug) {
222
+ // rome-ignore lint/nursery/noConsoleLog: <explanation>
223
+ console.log(`Adding compiled style ${keyInit}: ${valInit}`)
224
+ }
225
+
226
+ if (shouldDoClasses) {
227
+ classNames[keyInit] = valInit
228
+ delete style[keyInit]
229
+ } else {
230
+ style[keyInit] = reverseMapClassNameToValue(keyInit, valInit)
231
+ delete className[keyInit]
232
+ }
233
+ continue
234
+ }
235
+ }
246
236
  }
247
237
 
248
238
  if (process.env.TAMAGUI_TARGET === 'native') {
249
239
  if (!isAndroid) {
250
240
  // only works in android
251
- if (keyInit === 'elevationAndroid') return
241
+ if (keyInit === 'elevationAndroid') continue
252
242
  }
243
+
253
244
  // map userSelect to native prop
254
245
  if (keyInit === 'userSelect') {
255
246
  keyInit = 'selectable'
256
247
  valInit = valInit === 'none' ? false : true
257
- } else if (keyInit.startsWith('aria-') || keyInit === 'role') {
248
+ } else if (keyInit === 'role') {
249
+ if (valInit === 'list') {
250
+ // role = "list"
251
+ viewProps[keyInit] = valInit
252
+ } else if (accessibilityWebRoleToNativeRole[valInit]) {
253
+ viewProps['accessibilityRole'] = accessibilityWebRoleToNativeRole[
254
+ valInit
255
+ ] as GetStyleResult['viewProps']['AccessibilityRole']
256
+ }
257
+ continue
258
+ } else if (keyInit.startsWith('aria-')) {
258
259
  if (webToNativeAccessibilityDirectMap[keyInit]) {
259
260
  const nativeA11yProp = webToNativeAccessibilityDirectMap[keyInit]
260
261
  if (keyInit === 'aria-hidden') {
@@ -262,8 +263,7 @@ export const getSplitStyles: StyleSplitter = (
262
263
  viewProps['aria-hidden'] = valInit
263
264
  }
264
265
  viewProps[nativeA11yProp] = valInit
265
- usedKeys[keyInit] = 1
266
- return
266
+ continue
267
267
  } else if (nativeAccessibilityValue[keyInit]) {
268
268
  let field = nativeAccessibilityValue[keyInit]
269
269
  if (viewProps['accessibilityValue']) {
@@ -273,7 +273,6 @@ export const getSplitStyles: StyleSplitter = (
273
273
  [field]: valInit,
274
274
  }
275
275
  }
276
- usedKeys[keyInit] = 1
277
276
  } else if (nativeAccessibilityState[keyInit]) {
278
277
  let field = nativeAccessibilityState[keyInit]
279
278
  if (viewProps['accessibilityState']) {
@@ -283,64 +282,33 @@ export const getSplitStyles: StyleSplitter = (
283
282
  [field]: valInit,
284
283
  }
285
284
  }
286
- usedKeys[keyInit] = 1
287
- } else if (keyInit === 'role') {
288
- if (valInit === 'list') {
289
- // role = "list"
290
- viewProps[keyInit] = valInit
291
- } else if (accessibilityWebRoleToNativeRole[valInit]) {
292
- viewProps['accessibilityRole'] = accessibilityWebRoleToNativeRole[
293
- valInit
294
- ] as GetStyleResult['viewProps']['AccessibilityRole']
295
- }
296
- return
297
285
  }
298
- return
286
+ continue
299
287
  } else if (keyInit.startsWith('data-')) {
300
- return
288
+ continue
301
289
  }
302
290
  }
303
291
 
304
- if (process.env.TAMAGUI_TARGET === 'web') {
305
- if (keyInit === 'elevationAndroid') return
306
- }
307
-
308
292
  if (!staticConfig.isHOC) {
309
293
  if (keyInit in skipProps) {
310
294
  if (process.env.NODE_ENV === 'development' && debug && keyInit === 'debug') {
311
- // pass throuhg debug
295
+ // pass through debug
312
296
  } else {
313
- return
314
- }
315
- }
316
- }
317
-
318
- if (keyInit in usedKeys) {
319
- return
320
- }
321
-
322
- if (typeof valInit === 'string' && valInit[0] === '_') {
323
- if (keyInit in validStyleProps || keyInit.includes('-')) {
324
- if (shouldDoClasses) {
325
- classNames[keyInit] = valInit
326
- } else {
327
- style[keyInit] = reverseMapClassNameToValue(keyInit, valInit)
297
+ continue
328
298
  }
329
- usedKeys[keyInit] = 1
330
- return
331
299
  }
332
300
  }
333
301
 
334
302
  if (keyInit === 'dataSet') {
335
- for (const key in valInit) {
336
- viewProps[`data-${hyphenate(key)}`] = valInit[key]
303
+ for (const keyInit in valInit) {
304
+ viewProps[`data-${hyphenate(keyInit)}`] = valInit[keyInit]
337
305
  }
338
- return
306
+ continue
339
307
  }
340
308
 
341
309
  const isMainStyle = keyInit === 'style'
342
310
  if (isMainStyle || keyInit.startsWith('_style')) {
343
- if (!valInit) return
311
+ if (!valInit) continue
344
312
  const styles = [].concat(valInit).flat()
345
313
  const styleLen = styles.length
346
314
  for (let j = styleLen; j >= 0; j--) {
@@ -354,7 +322,7 @@ export const getSplitStyles: StyleSplitter = (
354
322
  style[key] = cur[key]
355
323
  }
356
324
  }
357
- return
325
+ continue
358
326
  }
359
327
 
360
328
  if (process.env.TAMAGUI_TARGET === 'web') {
@@ -364,7 +332,6 @@ export const getSplitStyles: StyleSplitter = (
364
332
  */
365
333
 
366
334
  if (keyInit === 'disabled' && valInit === true) {
367
- usedKeys[keyInit] = 1
368
335
  viewProps['aria-disabled'] = true
369
336
  // Enhance with native semantics
370
337
  if (
@@ -377,40 +344,38 @@ export const getSplitStyles: StyleSplitter = (
377
344
  viewProps.disabled = true
378
345
  }
379
346
  if (!variants?.disabled) {
380
- return
347
+ continue
381
348
  }
382
349
  }
383
350
 
384
351
  if (keyInit === 'testID') {
385
- usedKeys[keyInit] = 1
386
352
  viewProps[isReactNative ? 'testId' : 'data-testid'] = valInit
387
- return
353
+ continue
388
354
  }
389
355
 
390
356
  if (keyInit === 'id' || keyInit === 'nativeID') {
391
- usedKeys[keyInit] = 1
392
357
  if (isReactNative) {
393
358
  viewProps.nativeID = valInit
394
359
  } else {
395
360
  viewProps.id = valInit
396
361
  }
397
- return
362
+ continue
398
363
  }
399
364
 
400
365
  let didUseKeyInit = false
401
366
 
402
367
  if (isReactNative) {
403
368
  // pass along to react-native-web
404
- if (accessibilityDirectMap[keyInit] || keyInit.startsWith('accessibility')) {
369
+ if (keyInit in accessibilityDirectMap || keyInit.startsWith('accessibility')) {
405
370
  viewProps[keyInit] = valInit
406
- usedKeys[keyInit] = 1
407
- return
371
+ continue
408
372
  }
409
373
  } else {
410
374
  didUseKeyInit = true
411
375
 
412
376
  if (keyInit in accessibilityDirectMap) {
413
377
  viewProps[accessibilityDirectMap[keyInit]] = valInit
378
+ continue
414
379
  } else {
415
380
  switch (keyInit) {
416
381
  case 'accessibilityRole': {
@@ -419,7 +384,7 @@ export const getSplitStyles: StyleSplitter = (
419
384
  } else {
420
385
  viewProps.role = accessibilityRoleToWebRole[valInit] || valInit
421
386
  }
422
- return
387
+ continue
423
388
  }
424
389
  case 'accessibilityLabelledBy':
425
390
  case 'accessibilityFlowTo':
@@ -427,17 +392,17 @@ export const getSplitStyles: StyleSplitter = (
427
392
  case 'accessibilityDescribedBy': {
428
393
  viewProps[`aria-${keyInit.replace('accessibility', '').toLowerCase()}`] =
429
394
  processIDRefList(valInit)
430
- return
395
+ continue
431
396
  }
432
397
  case 'accessibilityKeyShortcuts': {
433
398
  if (Array.isArray(valInit)) {
434
399
  viewProps['aria-keyshortcuts'] = valInit.join(' ')
435
400
  }
436
- return
401
+ continue
437
402
  }
438
403
  case 'accessibilityLiveRegion': {
439
404
  viewProps['aria-live'] = valInit === 'none' ? 'off' : valInit
440
- return
405
+ continue
441
406
  }
442
407
  case 'accessibilityReadOnly': {
443
408
  viewProps['aria-readonly'] = valInit
@@ -449,7 +414,7 @@ export const getSplitStyles: StyleSplitter = (
449
414
  ) {
450
415
  viewProps.readOnly = true
451
416
  }
452
- return
417
+ continue
453
418
  }
454
419
  case 'accessibilityRequired': {
455
420
  viewProps['aria-required'] = valInit
@@ -461,7 +426,7 @@ export const getSplitStyles: StyleSplitter = (
461
426
  ) {
462
427
  viewProps.required = valInit
463
428
  }
464
- return
429
+ continue
465
430
  }
466
431
  default: {
467
432
  didUseKeyInit = false
@@ -471,8 +436,7 @@ export const getSplitStyles: StyleSplitter = (
471
436
  }
472
437
 
473
438
  if (didUseKeyInit) {
474
- usedKeys[keyInit] = 1
475
- return
439
+ continue
476
440
  }
477
441
 
478
442
  if (valInit && valInit[0] === '_') {
@@ -485,13 +449,12 @@ export const getSplitStyles: StyleSplitter = (
485
449
  validStyles[keyInit.split(PROP_SPLIT)[0]]
486
450
 
487
451
  if (isValidClassName || isMediaOrPseudo) {
488
- usedKeys[keyInit] = 1
489
452
  if (process.env.NODE_ENV === 'development' && debug) {
490
453
  // rome-ignore lint/nursery/noConsoleLog: ok
491
454
  console.log('tamagui classname props', keyInit, valInit)
492
455
  }
493
456
  mergeClassName(transforms, classNames, keyInit, valInit, isMediaOrPseudo)
494
- return
457
+ continue
495
458
  }
496
459
  }
497
460
  }
@@ -507,72 +470,83 @@ export const getSplitStyles: StyleSplitter = (
507
470
  let isPseudo = keyInit in validPseudoKeys
508
471
  let isMediaOrPseudo = isMedia || isPseudo
509
472
 
510
- const isVariant = variants && keyInit in variants
473
+ let isVariant = variants && keyInit in variants
511
474
  const isStyleProp =
512
475
  isMediaOrPseudo || isVariant || keyInit in validStyleProps || keyInit in shorthands
513
476
 
514
477
  if (isStyleProp && props.asChild === 'except-style') {
515
- return
478
+ continue
516
479
  }
517
480
 
518
481
  const shouldPassProp = !isStyleProp
519
482
 
520
- const isHOCShouldPassThrough =
483
+ const isHOCShouldPassThrough = Boolean(
521
484
  staticConfig.isHOC &&
522
- (isMediaOrPseudo || staticConfig.parentStaticConfig?.variants?.[keyInit])
523
- const shouldPassThrough = shouldPassProp || isHOCShouldPassThrough
485
+ (isMediaOrPseudo ||
486
+ staticConfig.parentStaticConfig?.variants?.[keyInit] ||
487
+ keyInit in skipProps)
488
+ )
524
489
 
525
- if (shouldPassThrough) {
526
- if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
527
- console.groupCollapsed(` 🔹 pass through ${keyInit}`)
528
- // rome-ignore lint/nursery/noConsoleLog: <explanation>
529
- console.log({
530
- valInit,
531
- variants,
532
- variant: variants?.[keyInit],
533
- isVariant,
534
- shouldPassProp,
535
- isHOCShouldPassThrough,
536
- })
537
- console.groupEnd()
538
- }
490
+ const shouldPassThrough = shouldPassProp || isHOCShouldPassThrough
539
491
 
540
- if (isPseudo) {
541
- // this is a lot... but we need to track sub-keys so we don't override them in future things that aren't passed down
542
- // like our own variants that aren't in parent
543
- const pseudoStyleObject = getSubStyle(
544
- styleState,
545
- keyInit,
546
- valInit,
547
- true,
548
- state.noClassNames
549
- )
550
- const descriptor = pseudoDescriptors[keyInit]
551
- for (const key in pseudoStyleObject) {
552
- const fullKey = `${key}${PROP_SPLIT}${descriptor.name}`
553
- usedKeys[fullKey] = 1
554
- }
555
- }
492
+ if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
493
+ console.groupCollapsed(
494
+ ` 🔹 prop ${keyInit} ${shouldPassThrough ? 'pass through' : ''}`
495
+ )
496
+ // prettier-ignore
497
+ // rome-ignore lint/nursery/noConsoleLog: <explanation>
498
+ console.log({ valInit, variants, variant: variants?.[keyInit], isVariant, shouldPassProp, isHOCShouldPassThrough })
499
+ console.groupEnd()
500
+ }
556
501
 
557
- passDownProp(keyInit, valInit, isMediaOrPseudo)
502
+ if (shouldPassThrough) {
503
+ // // TODO bring this back but probably improve it?
504
+ // if (isPseudo) {
505
+ // // this is a lot... but we need to track sub-keys so we don't override them in future things that aren't passed down
506
+ // // like our own variants that aren't in parent
507
+ // const pseudoStyleObject = getSubStyle(
508
+ // styleState,
509
+ // keyInit,
510
+ // valInit,
511
+ // fontFamily,
512
+ // true,
513
+ // state.noClassNames
514
+ // )
515
+ // const descriptor = pseudoDescriptors[keyInit]
516
+ // for (const key in pseudoStyleObject) {
517
+ // debugger
518
+ // }
519
+ // }
520
+
521
+ passDownProp(viewProps, keyInit, valInit, isMediaOrPseudo)
558
522
 
559
523
  // if it's a variant here, we have a two layer variant...
560
524
  // aka styled(Input, { unstyled: true, variants: { unstyled: {} } })
561
525
  // which now has it's own unstyled + the child unstyled...
562
526
  // so *don't* skip applying the styles, but also pass `unstyled` to children
563
527
  if (!isVariant) {
564
- return
528
+ continue
565
529
  }
566
530
  }
567
531
 
532
+ // after shouldPassThrough
533
+ if (keyInit in skipProps) continue
534
+
535
+ // default font family
536
+ // is this great? no, but backwards compat until we add tests and make better
537
+ defaultFontVariable ||= `$${conf.defaultFont}`
538
+ fontFamily ||=
539
+ props[conf.inverseShorthands.fontFamily] || props.fontFamily || defaultFontVariable
540
+
568
541
  const expanded = isMediaOrPseudo
569
542
  ? [[keyInit, valInit]]
570
543
  : propMapper(
571
544
  keyInit,
572
545
  valInit,
573
546
  theme,
574
- special ? { ...props, fontFamily: fontFamilyOverride } : props,
547
+ props,
575
548
  state,
549
+ fontFamily,
576
550
  languageContext,
577
551
  undefined,
578
552
  debug
@@ -583,18 +557,11 @@ export const getSplitStyles: StyleSplitter = (
583
557
  }
584
558
 
585
559
  if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
586
- console.groupCollapsed(' 🔹 styles', keyInit, valInit)
587
- // rome-ignore lint/nursery/noConsoleLog: <explanation>
588
- console.log({
589
- expanded,
590
- state,
591
- isVariant,
592
- variant: variants?.[keyInit],
593
- shouldPassProp,
594
- isHOCShouldPassThrough,
595
- theme,
596
- })
560
+ console.groupCollapsed(' 🔹 expanded', keyInit, valInit)
597
561
  if (!isServer && isDevTools) {
562
+ // prettier-ignore
563
+ // rome-ignore lint/nursery/noConsoleLog: <explanation>
564
+ console.log({ expanded, state: { ...state }, isVariant, variant: variants?.[keyInit], shouldPassProp, isHOCShouldPassThrough, theme, usedKeys: { ...usedKeys } })
598
565
  // rome-ignore lint/nursery/noConsoleLog: ok
599
566
  console.log('expanded', expanded, '\nusedKeys', { ...usedKeys }, '\ncurrent', {
600
567
  ...style,
@@ -603,30 +570,17 @@ export const getSplitStyles: StyleSplitter = (
603
570
  console.groupEnd()
604
571
  }
605
572
 
606
- if (!expanded) return
573
+ if (!expanded) continue
607
574
 
608
575
  for (const [key, val] of expanded) {
609
- if (val === undefined) continue
610
-
611
- if (key in stylePropsFont && !special && key !== 'fontFamily') {
612
- specialProps.push([key, val])
613
- continue
614
- }
576
+ if (val == null) continue
577
+ if (key in usedKeys) continue
615
578
 
616
579
  isMedia = isMediaKey(key)
617
580
  isPseudo = key in validPseudoKeys
618
581
  isMediaOrPseudo = isMedia || isPseudo
619
582
 
620
- if (!isMediaOrPseudo && key in usedKeys) {
621
- if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
622
- // rome-ignore lint/nursery/noConsoleLog: <explanation>
623
- console.log(`Used media/pseudo ${key}`)
624
- }
625
- continue
626
- }
627
-
628
583
  if (inlineProps?.has(key) || inlineWhenUnflattened?.has(key)) {
629
- usedKeys[key] = 1
630
584
  viewProps[key] = props[key] ?? val
631
585
  }
632
586
 
@@ -636,7 +590,14 @@ export const getSplitStyles: StyleSplitter = (
636
590
  (isMediaOrPseudo || staticConfig.parentStaticConfig?.variants?.[keyInit])
637
591
 
638
592
  if (isHOCShouldPassThrough) {
639
- passDownProp(key, val)
593
+ isVariant = variants && key in variants
594
+ passDownProp(viewProps, key, val, isMediaOrPseudo)
595
+ if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
596
+ console.groupCollapsed(` - passing down prop ${key}`)
597
+ // rome-ignore lint/nursery/noConsoleLog: <explanation>
598
+ console.log({ val, after: { ...viewProps[key] } })
599
+ console.groupEnd()
600
+ }
640
601
  // if its also a variant here, pass down but also keep it
641
602
  if (!isVariant) {
642
603
  continue
@@ -652,6 +613,7 @@ export const getSplitStyles: StyleSplitter = (
652
613
  styleState,
653
614
  key,
654
615
  val,
616
+ fontFamily,
655
617
  true,
656
618
  state.noClassNames
657
619
  )
@@ -662,38 +624,52 @@ export const getSplitStyles: StyleSplitter = (
662
624
 
663
625
  // don't continue here on isEnter && !state.unmounted because we need to merge defaults
664
626
  if (!descriptor || (isExit && !state.isExiting)) {
627
+ if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
628
+ // prettier-ignore
629
+ // rome-ignore lint/nursery/noConsoleLog: <explanation>
630
+ console.log('skip exit')
631
+ }
632
+
665
633
  continue
666
634
  }
667
635
 
668
636
  if (!shouldDoClasses || IS_STATIC) {
669
637
  pseudos ||= {}
670
638
  pseudos[key] ||= {}
671
- Object.assign(pseudos[key], pseudoStyleObject)
672
639
  }
673
640
 
674
641
  if (shouldDoClasses && !isEnter && !isExit) {
675
642
  const pseudoStyles = generateAtomicStyles(pseudoStyleObject, descriptor)
643
+
644
+ if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
645
+ // prettier-ignore
646
+ console.groupCollapsed('pseudo (classes)', key)
647
+ // prettier-ignore
648
+ // rome-ignore lint/nursery/noConsoleLog: <explanation>
649
+ console.log({ pseudoStyleObject, pseudoStyles })
650
+ console.groupEnd()
651
+ }
652
+
676
653
  for (const psuedoStyle of pseudoStyles) {
677
654
  const fullKey = `${psuedoStyle.property}${PROP_SPLIT}${descriptor.name}`
678
-
679
- if (!(fullKey in usedKeys)) {
680
- usedKeys[fullKey] = 1
681
- addStyleToInsertRules(rulesToInsert, psuedoStyle)
682
- mergeClassName(
683
- transforms,
684
- classNames,
685
- fullKey,
686
- psuedoStyle.identifier,
687
- isMediaOrPseudo
688
- )
689
- }
655
+ addStyleToInsertRules(rulesToInsert, psuedoStyle)
656
+ mergeClassName(
657
+ transforms,
658
+ classNames,
659
+ fullKey,
660
+ psuedoStyle.identifier,
661
+ isMediaOrPseudo
662
+ )
690
663
  }
691
664
  } else {
692
- if (key in usedKeys) {
693
- continue
694
- }
665
+ // we don't skip this if disabled because we need to animate to default states that aren't even set:
666
+ // so if we have <Stack enterStyle={{ opacity: 0 }} />
667
+ // we need to animate from 0 => 1 once enter is finished
668
+ // see the if (isDisabled) block below which loops through animatableDefaults
695
669
 
696
- let isDisabled = !state[descriptor.stateKey || descriptor.name]
670
+ const descriptorKey = descriptor.stateKey || descriptor.name
671
+ const pseudoState = state[descriptorKey]
672
+ let isDisabled = !pseudoState
697
673
 
698
674
  // we never animate in on server side just show the full thing
699
675
  // on client side we use CSS to hide the fully in SSR items, then
@@ -702,51 +678,62 @@ export const getSplitStyles: StyleSplitter = (
702
678
  isDisabled = false
703
679
  }
704
680
 
705
- if (!isDisabled) {
706
- if (valInit === staticConfig.defaultProps[keyInit]) {
707
- // ignore:
708
- // if it's a default property given by styled(), we don't mark it as used, so
709
- // that props given inline can override:
710
- } else {
711
- usedKeys[key] ||= 1
712
- if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
713
- // rome-ignore lint/nursery/noConsoleLog: <explanation>
714
- console.log(`Setting used ${key}`)
715
- }
716
- }
681
+ if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
682
+ // prettier-ignore
683
+ console.groupCollapsed('pseudo', key, !isDisabled)
684
+ // prettier-ignore
685
+ // rome-ignore lint/nursery/noConsoleLog: <explanation>
686
+ console.log(pseudoStyleObject, { isDisabled, descriptorKey, descriptor, pseudoState, state: { ...state } })
687
+ console.groupEnd()
717
688
  }
718
689
 
719
- psuedosUsed ||= {}
690
+ // if (!isDisabled) {
691
+ // if (valInit === staticConfig.defaultProps[keyInit]) {
692
+ // // ignore:
693
+ // // if it's a default property given by styled(), we don't mark it as used, so
694
+ // // that props given inline can override:
695
+ // }
696
+ // }
720
697
 
721
698
  const importance = descriptor.priority
722
699
 
700
+ if (!isDisabled) {
701
+ // mark usedKeys based not on pseudoStyleObject
702
+ for (const key in val) {
703
+ const k = shorthands[key] || key
704
+ usedKeys[k] = Math.max(importance, usedKeys[k] || 0)
705
+ }
706
+ }
707
+
723
708
  for (const pkey in pseudoStyleObject) {
724
709
  const val = pseudoStyleObject[pkey]
725
710
  // when disabled ensure the default value is set for future animations to align
711
+
726
712
  if (isDisabled) {
727
- if (!(pkey in usedKeys) && pkey in animatableDefaults) {
713
+ if (pkey in animatableDefaults && !(pkey in usedKeys)) {
728
714
  const defaultVal = animatableDefaults[pkey]
729
- mergeStyle(styleState, flatTransforms, pkey, defaultVal, true)
715
+ mergeStyle(styleState, flatTransforms, pkey, defaultVal)
716
+ }
717
+ } else {
718
+ const curImportance = usedKeys[importance] || 0
719
+ const shouldMerge = importance >= curImportance
720
+
721
+ if (shouldMerge) {
722
+ pseudos ||= {}
723
+ pseudos[key] ||= {}
724
+ pseudos[key][pkey] = val
725
+ mergeStyle(styleState, flatTransforms, pkey, val)
726
+ usedKeys[pkey] ||= 1
727
+ }
728
+ if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
729
+ // prettier-ignore
730
+ // rome-ignore lint/nursery/noConsoleLog: <explanation>
731
+ console.log(' subKey', pkey, shouldMerge, { importance, curImportance, pkey, val })
730
732
  }
731
- continue
732
- }
733
- const curImportance = psuedosUsed[importance] || 0
734
- const shouldMerge = importance >= curImportance
735
-
736
- if (shouldMerge) {
737
- psuedosUsed[pkey] = importance
738
- pseudos ||= {}
739
- pseudos[key] ||= {}
740
- pseudos[key][pkey] = val
741
- mergeStyle(styleState, flatTransforms, pkey, val)
742
- }
743
- if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
744
- // prettier-ignore
745
- // rome-ignore lint/nursery/noConsoleLog: <explanation>
746
- console.log(' merge pseudo?', keyInit, shouldMerge, { importance, curImportance, pkey, val })
747
733
  }
748
734
  }
749
735
  }
736
+
750
737
  continue
751
738
  }
752
739
 
@@ -763,6 +750,7 @@ export const getSplitStyles: StyleSplitter = (
763
750
  styleState,
764
751
  key,
765
752
  val,
753
+ fontFamily,
766
754
  // TODO try true like pseudo
767
755
  false
768
756
  )
@@ -809,12 +797,8 @@ export const getSplitStyles: StyleSplitter = (
809
797
  for (const style of mediaStyles) {
810
798
  const out = createMediaStyle(style, mediaKeyShort, mediaQueryConfig)
811
799
  const fullKey = `${style.property}${PROP_SPLIT}${mediaKeyShort}`
812
-
813
- if (!usedKeys[fullKey]) {
814
- usedKeys[fullKey] = 1
815
- addStyleToInsertRules(rulesToInsert, out as any)
816
- mergeClassName(transforms, classNames, fullKey, out.identifier, true)
817
- }
800
+ addStyleToInsertRules(rulesToInsert, out as any)
801
+ mergeClassName(transforms, classNames, fullKey, out.identifier, true)
818
802
  }
819
803
  } else if (mediaState[mediaKeyShort]) {
820
804
  for (const subKey in mediaStyle) {
@@ -845,7 +829,6 @@ export const getSplitStyles: StyleSplitter = (
845
829
 
846
830
  if (process.env.TAMAGUI_TARGET === 'native') {
847
831
  if (key === 'pointerEvents') {
848
- usedKeys[key] = 1
849
832
  viewProps[key] = val
850
833
  continue
851
834
  }
@@ -858,43 +841,24 @@ export const getSplitStyles: StyleSplitter = (
858
841
  }
859
842
  }
860
843
 
861
- if (key in validStyleProps) {
862
- mergeStyle(styleState, flatTransforms, key, val)
863
- continue
864
- } else if (
865
- process.env.TAMAGUI_TARGET === 'native' &&
866
- isAndroid &&
867
- key === 'elevation'
844
+ if (
845
+ key in validStyleProps ||
846
+ (process.env.TAMAGUI_TARGET === 'native' && isAndroid && key === 'elevation')
868
847
  ) {
869
848
  mergeStyle(styleState, flatTransforms, key, val)
870
849
  continue
871
850
  }
872
851
 
873
852
  // pass to view props
874
- if (!isVariant && !(key in skipProps)) {
853
+ if (!isVariant) {
875
854
  viewProps[key] = val
876
- usedKeys[key] = 1
877
855
  }
878
856
  }
879
857
  }
880
858
 
881
- // loop backwards so we can skip already-used props
882
- for (let i = len - 1; i >= 0; i--) {
883
- const keyInit = propKeys[i]
884
- const valInit = props[keyInit]
885
- processProp(keyInit, valInit)
886
- }
887
-
888
859
  // default to default font
889
860
  fontFamily ||= conf.defaultFont
890
861
 
891
- // loop the special props once again
892
- // this one doesn't need to be backwards since it was pushed in the backwards loop (is already reversed)
893
- for (let i = 0; i < specialProps.length; i++) {
894
- const [key, value] = specialProps[i]
895
- processProp(key, value, true, fontFamily)
896
- }
897
-
898
862
  fixStyles(style)
899
863
  if (isWeb) {
900
864
  styleToCSS(style)
@@ -932,7 +896,7 @@ export const getSplitStyles: StyleSplitter = (
932
896
  // always do this at the very end to preserve the order strictly (animations, origin)
933
897
  // and allow proper merging of all pseudos before applying
934
898
  if (flatTransforms) {
935
- mergeTransforms(style, flatTransforms, true)
899
+ mergeFlatTransforms(style, flatTransforms, true)
936
900
  }
937
901
 
938
902
  // add in defaults if not set:
@@ -961,9 +925,10 @@ export const getSplitStyles: StyleSplitter = (
961
925
  // avoid re-processing for rnw
962
926
  } else {
963
927
  const atomic = getStylesAtomic(style)
928
+
964
929
  for (const atomicStyle of atomic) {
965
930
  const key = atomicStyle.property
966
- if (props.animateOnly && props.animateOnly.includes(key)) {
931
+ if (state.isAnimated && props.animateOnly && props.animateOnly.includes(key)) {
967
932
  retainedStyles[key] = style[key]
968
933
  } else {
969
934
  addStyleToInsertRules(rulesToInsert, atomicStyle)
@@ -1042,21 +1007,11 @@ export const getSplitStyles: StyleSplitter = (
1042
1007
  }
1043
1008
  }
1044
1009
 
1045
- // now we need to reverse viewProps because order is important for wrapped tamagui children:
1046
- // techcnically we could just do this when it is HOC/has parentStaticConfig I think... but safer this way
1047
- const nextViewProps = {}
1048
- const ks = Object.keys(viewProps)
1049
- const l = ks.length
1050
- for (let i = l - 1; i >= 0; i--) {
1051
- const key = ks[i]
1052
- nextViewProps[key] = viewProps[key]
1053
- }
1054
-
1055
1010
  const result: GetStyleResult = {
1056
1011
  space,
1057
1012
  hasMedia,
1058
1013
  fontFamily,
1059
- viewProps: nextViewProps,
1014
+ viewProps,
1060
1015
  // @ts-expect-error
1061
1016
  style,
1062
1017
  pseudos,
@@ -1070,9 +1025,9 @@ export const getSplitStyles: StyleSplitter = (
1070
1025
 
1071
1026
  if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
1072
1027
  if (isDevTools) {
1073
- console.groupCollapsed(' 🔹 =>')
1028
+ console.groupCollapsed(' 🔹 ===>')
1074
1029
  // prettier-ignore
1075
- const logs = { ...result, state, etc: { transforms, viewProps, rulesToInsert, parentSplitStyles, flatTransforms } }
1030
+ const logs = { ...result, state, transforms, viewProps, viewPropsOrder: Object.keys(viewProps), rulesToInsert, parentSplitStyles, flatTransforms }
1076
1031
  for (const key in logs) {
1077
1032
  // rome-ignore lint/nursery/noConsoleLog: ok
1078
1033
  console.log(key, logs[key])
@@ -1177,17 +1132,14 @@ function getSubStyleProps(
1177
1132
  }
1178
1133
 
1179
1134
  function mergeStyle(
1180
- { usedKeys, classNames, viewProps, style }: GetStyleState,
1135
+ { classNames, viewProps, style, usedKeys }: GetStyleState,
1181
1136
  flatTransforms: FlatTransforms,
1182
1137
  key: string,
1183
- val: any,
1184
- dontSetUsed = false
1138
+ val: any
1185
1139
  ) {
1186
- if (!dontSetUsed) {
1187
- usedKeys[key] ||= 1
1188
- }
1189
- if (val && val[0] === '_') {
1140
+ if (val?.[0] === '_') {
1190
1141
  classNames[key] = val
1142
+ usedKeys[key] ||= 1
1191
1143
  } else if (key in stylePropsTransform) {
1192
1144
  flatTransforms ||= {}
1193
1145
  flatTransforms[key] = val
@@ -1205,6 +1157,7 @@ export const getSubStyle = (
1205
1157
  styleState: GetStyleState,
1206
1158
  subKey: string,
1207
1159
  styleIn: Object,
1160
+ fontFamily?: string,
1208
1161
  avoidDefaultProps?: boolean,
1209
1162
  avoidMergeTransform?: boolean
1210
1163
  ): TextStyleProps => {
@@ -1220,15 +1173,13 @@ export const getSubStyle = (
1220
1173
  theme,
1221
1174
  getSubStyleProps(staticConfig.defaultProps, props, props[subKey]),
1222
1175
  state,
1176
+ fontFamily,
1223
1177
  languageContext,
1224
1178
  avoidDefaultProps
1225
1179
  )
1226
- if (!staticConfig.isHOC) {
1227
- if (key in skipProps) {
1228
- continue
1229
- }
1180
+ if (!expanded || (!staticConfig.isHOC && key in skipProps)) {
1181
+ continue
1230
1182
  }
1231
- if (!expanded) continue
1232
1183
  for (const [skey, sval] of expanded) {
1233
1184
  if (!avoidMergeTransform && skey in stylePropsTransform) {
1234
1185
  mergeTransform(styleOut, skey, sval)
@@ -1280,6 +1231,8 @@ const animatableDefaults = {
1280
1231
  rotate: '0deg',
1281
1232
  rotateY: '0deg',
1282
1233
  rotateX: '0deg',
1234
+ x: 0,
1235
+ y: 0,
1283
1236
  }
1284
1237
 
1285
1238
  const lowercaseHyphenate = (match: string) => `-${match.toLowerCase()}`
@@ -1299,14 +1252,25 @@ const mergeTransform = (
1299
1252
  } as any)
1300
1253
  }
1301
1254
 
1302
- const mergeTransforms = (
1255
+ // we need to match the order for animations to work because it needs consistent order
1256
+ // was thinking of having something like `state.prevTransformsOrder = ['y', 'x', ...]
1257
+ // but if we just handle it here its not a big cost and avoids having stateful things
1258
+ // so the strategy is: always sort by a consistent order, until you run into a "duplicate"
1259
+ // because you can have something like:
1260
+ // [{ translateX: 0 }, { scale: 1 }, { translateX: 10 }]
1261
+ // so basically we sort until we get to a duplicate... we could sort even smarter but
1262
+ // this should work for most (all?) of our cases since the order preservation really only needs to apply
1263
+ // to the "flat" transform props
1264
+ const mergeFlatTransforms = (
1303
1265
  obj: TextStyleProps,
1304
1266
  flatTransforms: FlatTransforms,
1305
1267
  backwards = false
1306
1268
  ) => {
1307
- Object.entries(flatTransforms).forEach(([key, val]) => {
1308
- mergeTransform(obj, key, val, backwards)
1309
- })
1269
+ Object.entries(flatTransforms)
1270
+ .sort(([a], [b]) => a.localeCompare(b))
1271
+ .forEach(([key, val]) => {
1272
+ mergeTransform(obj, key, val, backwards)
1273
+ })
1310
1274
  }
1311
1275
 
1312
1276
  const mapTransformKeys = {
@@ -1345,6 +1309,10 @@ if (process.env.TAMAGUI_TARGET === 'native') {
1345
1309
  outlineWidth: true,
1346
1310
  outlineColor: true,
1347
1311
  })
1312
+ } else {
1313
+ Object.assign(skipProps, {
1314
+ elevationAndroid: true,
1315
+ })
1348
1316
  }
1349
1317
 
1350
1318
  const accessibilityRoleToWebRole = {
@@ -1355,3 +1323,22 @@ const accessibilityRoleToWebRole = {
1355
1323
  none: 'presentation',
1356
1324
  summary: 'region',
1357
1325
  }
1326
+
1327
+ function passDownProp(
1328
+ viewProps: Object,
1329
+ key: string,
1330
+ val: any,
1331
+ shouldMergeObject = false
1332
+ ) {
1333
+ if (shouldMergeObject) {
1334
+ const next = {
1335
+ ...viewProps[key],
1336
+ ...val,
1337
+ }
1338
+ // need to re-insert it at current position
1339
+ delete viewProps[key]
1340
+ viewProps[key] = next
1341
+ } else {
1342
+ viewProps[key] = val
1343
+ }
1344
+ }