@tamagui/web 1.36.5 → 1.37.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 (146) 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/getSplitStyles.js +169 -223
  12. package/dist/cjs/helpers/getSplitStyles.js.map +2 -2
  13. package/dist/cjs/helpers/getStylesAtomic.js +1 -1
  14. package/dist/cjs/helpers/getStylesAtomic.js.map +1 -1
  15. package/dist/cjs/helpers/getThemeCSSRules.js +1 -1
  16. package/dist/cjs/helpers/getThemeCSSRules.js.map +1 -1
  17. package/dist/cjs/helpers/getVariantExtras.js +1 -1
  18. package/dist/cjs/helpers/getVariantExtras.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/esm/constants/accessibilityDirectMap.native.js +2 -0
  22. package/dist/esm/constants/accessibilityDirectMap.native.js.map +1 -1
  23. package/dist/esm/createComponent.js +29 -25
  24. package/dist/esm/createComponent.js.map +1 -1
  25. package/dist/esm/createTamagui.js +8 -9
  26. package/dist/esm/createTamagui.js.map +1 -1
  27. package/dist/esm/helpers/ThemeManager.js +2 -2
  28. package/dist/esm/helpers/ThemeManager.js.map +1 -1
  29. package/dist/esm/helpers/createPropMapper.js +7 -6
  30. package/dist/esm/helpers/createPropMapper.js.map +1 -1
  31. package/dist/esm/helpers/getSplitStyles.js +169 -224
  32. package/dist/esm/helpers/getSplitStyles.js.map +2 -2
  33. package/dist/esm/helpers/getStylesAtomic.js +1 -1
  34. package/dist/esm/helpers/getStylesAtomic.js.map +1 -1
  35. package/dist/esm/helpers/getThemeCSSRules.js +1 -1
  36. package/dist/esm/helpers/getThemeCSSRules.js.map +1 -1
  37. package/dist/esm/helpers/getVariantExtras.js +1 -1
  38. package/dist/esm/helpers/getVariantExtras.js.map +1 -1
  39. package/dist/esm/hooks/useMedia.js +3 -2
  40. package/dist/esm/hooks/useMedia.js.map +1 -1
  41. package/package.json +9 -9
  42. package/src/constants/accessibilityDirectMap.native.tsx +3 -0
  43. package/src/createComponent.tsx +36 -25
  44. package/src/createTamagui.ts +16 -9
  45. package/src/helpers/ThemeManager.tsx +2 -2
  46. package/src/helpers/createPropMapper.ts +7 -12
  47. package/src/helpers/getSplitStyles.tsx +248 -272
  48. package/src/helpers/getStylesAtomic.ts +1 -1
  49. package/src/helpers/getThemeCSSRules.ts +4 -1
  50. package/src/helpers/getVariantExtras.tsx +1 -1
  51. package/src/hooks/useMedia.tsx +6 -3
  52. package/src/types.tsx +4 -2
  53. package/types/Tamagui.d.ts.map +1 -0
  54. package/types/config.d.ts.map +1 -0
  55. package/types/constants/accessibilityDirectMap.d.ts.map +1 -0
  56. package/types/constants/accessibilityDirectMap.native.d.ts +1 -0
  57. package/types/constants/accessibilityDirectMap.native.d.ts.map +1 -0
  58. package/types/constants/constants.d.ts.map +1 -0
  59. package/types/constants/isDevTools.d.ts.map +1 -0
  60. package/types/contexts/AnimationDriverContext.d.ts.map +1 -0
  61. package/types/contexts/ButtonNestingContext.d.ts.map +1 -0
  62. package/types/contexts/FontLanguageContext.d.ts.map +1 -0
  63. package/types/contexts/TextAncestorContext.d.ts.map +1 -0
  64. package/types/createComponent.d.ts.map +1 -0
  65. package/types/createFont.d.ts.map +1 -0
  66. package/types/createShorthands.d.ts.map +1 -0
  67. package/types/createTamagui.d.ts.map +1 -0
  68. package/types/createTheme.d.ts.map +1 -0
  69. package/types/createTokens.d.ts.map +1 -0
  70. package/types/createVariable.d.ts.map +1 -0
  71. package/types/createVariables.d.ts.map +1 -0
  72. package/types/helpers/ThemeManager.d.ts.map +1 -0
  73. package/types/helpers/ThemeManagerContext.d.ts.map +1 -0
  74. package/types/helpers/createChainedWeakCache.d.ts.map +1 -0
  75. package/types/helpers/createMediaStyle.d.ts.map +1 -0
  76. package/types/helpers/createPropMapper.d.ts.map +1 -0
  77. package/types/helpers/createProxy.d.ts.map +1 -0
  78. package/types/helpers/createStyledContext.d.ts.map +1 -0
  79. package/types/helpers/defaultOffset.d.ts.map +1 -0
  80. package/types/helpers/expandStyle.d.ts.map +1 -0
  81. package/types/helpers/expandStyles.d.ts.map +1 -0
  82. package/types/helpers/extendStaticConfig.d.ts.map +1 -0
  83. package/types/helpers/getAnimationDriver.d.ts.map +1 -0
  84. package/types/helpers/getExpandedShorthands.d.ts.map +1 -0
  85. package/types/helpers/getFontLanguage.d.ts.map +1 -0
  86. package/types/helpers/getSplitStyles.d.ts +1 -1
  87. package/types/helpers/getSplitStyles.d.ts.map +1 -0
  88. package/types/helpers/getStylesAtomic.d.ts.map +1 -0
  89. package/types/helpers/getStylesAtomic.native.d.ts.map +1 -0
  90. package/types/helpers/getThemeCSSRules.d.ts.map +1 -0
  91. package/types/helpers/getThemeCSSRules.native.d.ts.map +1 -0
  92. package/types/helpers/getVariantExtras.d.ts.map +1 -0
  93. package/types/helpers/insertStyleRule.d.ts.map +1 -0
  94. package/types/helpers/isObj.d.ts.map +1 -0
  95. package/types/helpers/isTamaguiComponent.d.ts.map +1 -0
  96. package/types/helpers/isTamaguiElement.d.ts.map +1 -0
  97. package/types/helpers/matchMedia.d.ts.map +1 -0
  98. package/types/helpers/matchMedia.native.d.ts.map +1 -0
  99. package/types/helpers/mergeProps.d.ts.map +1 -0
  100. package/types/helpers/normalizeColor.d.ts.map +1 -0
  101. package/types/helpers/normalizeShadow.d.ts.map +1 -0
  102. package/types/helpers/normalizeShadow.native.d.ts.map +1 -0
  103. package/types/helpers/normalizeStylePropKeys.d.ts.map +1 -0
  104. package/types/helpers/normalizeStylePropKeys.native.d.ts.map +1 -0
  105. package/types/helpers/normalizeValueWithProperty.d.ts.map +1 -0
  106. package/types/helpers/objectIdentityKey.d.ts.map +1 -0
  107. package/types/helpers/proxyThemeVariables.d.ts.map +1 -0
  108. package/types/helpers/pseudoDescriptors.d.ts.map +1 -0
  109. package/types/helpers/registerCSSVariable.d.ts.map +1 -0
  110. package/types/helpers/themeable.d.ts.map +1 -0
  111. package/types/helpers/themes.d.ts.map +1 -0
  112. package/types/helpers/timer.d.ts.map +1 -0
  113. package/types/helpers/useShallowSetState.d.ts.map +1 -0
  114. package/types/helpers/withStaticProperties.d.ts.map +1 -0
  115. package/types/hooks/getThemeUnwrapped.d.ts.map +1 -0
  116. package/types/hooks/useAnimationDriver.d.ts.map +1 -0
  117. package/types/hooks/useId.d.ts.map +1 -0
  118. package/types/hooks/useIsTouchDevice.d.ts.map +1 -0
  119. package/types/hooks/useMedia.d.ts.map +1 -0
  120. package/types/hooks/useProps.d.ts.map +1 -0
  121. package/types/hooks/useSafeRef.d.ts.map +1 -0
  122. package/types/hooks/useServerHooks.d.ts.map +1 -0
  123. package/types/hooks/useStyle.d.ts.map +1 -0
  124. package/types/hooks/useTheme.d.ts.map +1 -0
  125. package/types/hooks/useThemeName.d.ts.map +1 -0
  126. package/types/index.d.ts.map +1 -0
  127. package/types/inject-styles.d.ts.map +1 -0
  128. package/types/insertFont.d.ts.map +1 -0
  129. package/types/setupHooks.d.ts.map +1 -0
  130. package/types/setupReactNative.d.ts.map +1 -0
  131. package/types/styled.d.ts.map +1 -0
  132. package/types/types.d.ts +4 -3
  133. package/types/types.d.ts.map +1 -0
  134. package/types/views/AnimationDriverProvider.d.ts.map +1 -0
  135. package/types/views/FontLanguage.d.ts.map +1 -0
  136. package/types/views/FontLanguage.native.d.ts.map +1 -0
  137. package/types/views/FontLanguage.types.d.ts.map +1 -0
  138. package/types/views/Slot.d.ts.map +1 -0
  139. package/types/views/Stack.d.ts.map +1 -0
  140. package/types/views/TamaguiProvider.d.ts.map +1 -0
  141. package/types/views/Text.d.ts.map +1 -0
  142. package/types/views/Theme.d.ts.map +1 -0
  143. package/types/views/ThemeDebug.d.ts.map +1 -0
  144. package/types/views/ThemeDebug.native.d.ts.map +1 -0
  145. package/types/views/ThemeProvider.d.ts.map +1 -0
  146. package/types/views/View.d.ts.map +1 -0
@@ -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,60 @@ 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
+ if (keyInit in skipProps) continue
218
+
219
+ if (process.env.TAMAGUI_TARGET === 'web') {
220
+ if (typeof valInit === 'string' && valInit[0] === '_') {
221
+ if (keyInit in validStyleProps || keyInit.includes('-')) {
222
+ if (process.env.NODE_ENV === 'development' && debug) {
223
+ // rome-ignore lint/nursery/noConsoleLog: <explanation>
224
+ console.log(`Adding compiled style ${keyInit}: ${valInit}`)
225
+ }
226
+
227
+ if (shouldDoClasses) {
228
+ classNames[keyInit] = valInit
229
+ delete style[keyInit]
230
+ } else {
231
+ style[keyInit] = reverseMapClassNameToValue(keyInit, valInit)
232
+ delete className[keyInit]
233
+ }
234
+ continue
235
+ }
236
+ }
246
237
  }
247
238
 
248
239
  if (process.env.TAMAGUI_TARGET === 'native') {
249
240
  if (!isAndroid) {
250
241
  // only works in android
251
- if (keyInit === 'elevationAndroid') return
242
+ if (keyInit === 'elevationAndroid') continue
252
243
  }
244
+
253
245
  // map userSelect to native prop
254
246
  if (keyInit === 'userSelect') {
255
247
  keyInit = 'selectable'
256
248
  valInit = valInit === 'none' ? false : true
257
- } else if (keyInit.startsWith('aria-') || keyInit === 'role') {
249
+ } else if (keyInit === 'role') {
250
+ if (valInit === 'list') {
251
+ // role = "list"
252
+ viewProps[keyInit] = valInit
253
+ } else if (accessibilityWebRoleToNativeRole[valInit]) {
254
+ viewProps['accessibilityRole'] = accessibilityWebRoleToNativeRole[
255
+ valInit
256
+ ] as GetStyleResult['viewProps']['AccessibilityRole']
257
+ }
258
+ continue
259
+ } else if (keyInit.startsWith('aria-')) {
258
260
  if (webToNativeAccessibilityDirectMap[keyInit]) {
259
261
  const nativeA11yProp = webToNativeAccessibilityDirectMap[keyInit]
260
262
  if (keyInit === 'aria-hidden') {
@@ -262,8 +264,7 @@ export const getSplitStyles: StyleSplitter = (
262
264
  viewProps['aria-hidden'] = valInit
263
265
  }
264
266
  viewProps[nativeA11yProp] = valInit
265
- usedKeys[keyInit] = 1
266
- return
267
+ continue
267
268
  } else if (nativeAccessibilityValue[keyInit]) {
268
269
  let field = nativeAccessibilityValue[keyInit]
269
270
  if (viewProps['accessibilityValue']) {
@@ -273,7 +274,6 @@ export const getSplitStyles: StyleSplitter = (
273
274
  [field]: valInit,
274
275
  }
275
276
  }
276
- usedKeys[keyInit] = 1
277
277
  } else if (nativeAccessibilityState[keyInit]) {
278
278
  let field = nativeAccessibilityState[keyInit]
279
279
  if (viewProps['accessibilityState']) {
@@ -283,64 +283,33 @@ export const getSplitStyles: StyleSplitter = (
283
283
  [field]: valInit,
284
284
  }
285
285
  }
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
286
  }
298
- return
287
+ continue
299
288
  } else if (keyInit.startsWith('data-')) {
300
- return
289
+ continue
301
290
  }
302
291
  }
303
292
 
304
- if (process.env.TAMAGUI_TARGET === 'web') {
305
- if (keyInit === 'elevationAndroid') return
306
- }
307
-
308
293
  if (!staticConfig.isHOC) {
309
294
  if (keyInit in skipProps) {
310
295
  if (process.env.NODE_ENV === 'development' && debug && keyInit === 'debug') {
311
- // pass throuhg debug
312
- } 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
296
+ // pass through debug
326
297
  } else {
327
- style[keyInit] = reverseMapClassNameToValue(keyInit, valInit)
298
+ continue
328
299
  }
329
- usedKeys[keyInit] = 1
330
- return
331
300
  }
332
301
  }
333
302
 
334
303
  if (keyInit === 'dataSet') {
335
- for (const key in valInit) {
336
- viewProps[`data-${hyphenate(key)}`] = valInit[key]
304
+ for (const keyInit in valInit) {
305
+ viewProps[`data-${hyphenate(keyInit)}`] = valInit[keyInit]
337
306
  }
338
- return
307
+ continue
339
308
  }
340
309
 
341
310
  const isMainStyle = keyInit === 'style'
342
311
  if (isMainStyle || keyInit.startsWith('_style')) {
343
- if (!valInit) return
312
+ if (!valInit) continue
344
313
  const styles = [].concat(valInit).flat()
345
314
  const styleLen = styles.length
346
315
  for (let j = styleLen; j >= 0; j--) {
@@ -354,7 +323,7 @@ export const getSplitStyles: StyleSplitter = (
354
323
  style[key] = cur[key]
355
324
  }
356
325
  }
357
- return
326
+ continue
358
327
  }
359
328
 
360
329
  if (process.env.TAMAGUI_TARGET === 'web') {
@@ -364,7 +333,6 @@ export const getSplitStyles: StyleSplitter = (
364
333
  */
365
334
 
366
335
  if (keyInit === 'disabled' && valInit === true) {
367
- usedKeys[keyInit] = 1
368
336
  viewProps['aria-disabled'] = true
369
337
  // Enhance with native semantics
370
338
  if (
@@ -377,40 +345,38 @@ export const getSplitStyles: StyleSplitter = (
377
345
  viewProps.disabled = true
378
346
  }
379
347
  if (!variants?.disabled) {
380
- return
348
+ continue
381
349
  }
382
350
  }
383
351
 
384
352
  if (keyInit === 'testID') {
385
- usedKeys[keyInit] = 1
386
353
  viewProps[isReactNative ? 'testId' : 'data-testid'] = valInit
387
- return
354
+ continue
388
355
  }
389
356
 
390
357
  if (keyInit === 'id' || keyInit === 'nativeID') {
391
- usedKeys[keyInit] = 1
392
358
  if (isReactNative) {
393
359
  viewProps.nativeID = valInit
394
360
  } else {
395
361
  viewProps.id = valInit
396
362
  }
397
- return
363
+ continue
398
364
  }
399
365
 
400
366
  let didUseKeyInit = false
401
367
 
402
368
  if (isReactNative) {
403
369
  // pass along to react-native-web
404
- if (accessibilityDirectMap[keyInit] || keyInit.startsWith('accessibility')) {
370
+ if (keyInit in accessibilityDirectMap || keyInit.startsWith('accessibility')) {
405
371
  viewProps[keyInit] = valInit
406
- usedKeys[keyInit] = 1
407
- return
372
+ continue
408
373
  }
409
374
  } else {
410
375
  didUseKeyInit = true
411
376
 
412
377
  if (keyInit in accessibilityDirectMap) {
413
378
  viewProps[accessibilityDirectMap[keyInit]] = valInit
379
+ continue
414
380
  } else {
415
381
  switch (keyInit) {
416
382
  case 'accessibilityRole': {
@@ -419,7 +385,7 @@ export const getSplitStyles: StyleSplitter = (
419
385
  } else {
420
386
  viewProps.role = accessibilityRoleToWebRole[valInit] || valInit
421
387
  }
422
- return
388
+ continue
423
389
  }
424
390
  case 'accessibilityLabelledBy':
425
391
  case 'accessibilityFlowTo':
@@ -427,17 +393,17 @@ export const getSplitStyles: StyleSplitter = (
427
393
  case 'accessibilityDescribedBy': {
428
394
  viewProps[`aria-${keyInit.replace('accessibility', '').toLowerCase()}`] =
429
395
  processIDRefList(valInit)
430
- return
396
+ continue
431
397
  }
432
398
  case 'accessibilityKeyShortcuts': {
433
399
  if (Array.isArray(valInit)) {
434
400
  viewProps['aria-keyshortcuts'] = valInit.join(' ')
435
401
  }
436
- return
402
+ continue
437
403
  }
438
404
  case 'accessibilityLiveRegion': {
439
405
  viewProps['aria-live'] = valInit === 'none' ? 'off' : valInit
440
- return
406
+ continue
441
407
  }
442
408
  case 'accessibilityReadOnly': {
443
409
  viewProps['aria-readonly'] = valInit
@@ -449,7 +415,7 @@ export const getSplitStyles: StyleSplitter = (
449
415
  ) {
450
416
  viewProps.readOnly = true
451
417
  }
452
- return
418
+ continue
453
419
  }
454
420
  case 'accessibilityRequired': {
455
421
  viewProps['aria-required'] = valInit
@@ -461,7 +427,7 @@ export const getSplitStyles: StyleSplitter = (
461
427
  ) {
462
428
  viewProps.required = valInit
463
429
  }
464
- return
430
+ continue
465
431
  }
466
432
  default: {
467
433
  didUseKeyInit = false
@@ -471,8 +437,7 @@ export const getSplitStyles: StyleSplitter = (
471
437
  }
472
438
 
473
439
  if (didUseKeyInit) {
474
- usedKeys[keyInit] = 1
475
- return
440
+ continue
476
441
  }
477
442
 
478
443
  if (valInit && valInit[0] === '_') {
@@ -485,13 +450,12 @@ export const getSplitStyles: StyleSplitter = (
485
450
  validStyles[keyInit.split(PROP_SPLIT)[0]]
486
451
 
487
452
  if (isValidClassName || isMediaOrPseudo) {
488
- usedKeys[keyInit] = 1
489
453
  if (process.env.NODE_ENV === 'development' && debug) {
490
454
  // rome-ignore lint/nursery/noConsoleLog: ok
491
455
  console.log('tamagui classname props', keyInit, valInit)
492
456
  }
493
457
  mergeClassName(transforms, classNames, keyInit, valInit, isMediaOrPseudo)
494
- return
458
+ continue
495
459
  }
496
460
  }
497
461
  }
@@ -507,72 +471,76 @@ export const getSplitStyles: StyleSplitter = (
507
471
  let isPseudo = keyInit in validPseudoKeys
508
472
  let isMediaOrPseudo = isMedia || isPseudo
509
473
 
510
- const isVariant = variants && keyInit in variants
474
+ let isVariant = variants && keyInit in variants
511
475
  const isStyleProp =
512
476
  isMediaOrPseudo || isVariant || keyInit in validStyleProps || keyInit in shorthands
513
477
 
514
478
  if (isStyleProp && props.asChild === 'except-style') {
515
- return
479
+ continue
516
480
  }
517
481
 
518
- const shouldPassProp = !isStyleProp
482
+ const shouldPassProp = !isStyleProp && !(keyInit in handledProps)
519
483
 
520
- const isHOCShouldPassThrough =
484
+ const isHOCShouldPassThrough = Boolean(
521
485
  staticConfig.isHOC &&
522
- (isMediaOrPseudo || staticConfig.parentStaticConfig?.variants?.[keyInit])
486
+ (isMediaOrPseudo || staticConfig.parentStaticConfig?.variants?.[keyInit])
487
+ )
488
+
523
489
  const shouldPassThrough = shouldPassProp || isHOCShouldPassThrough
524
490
 
525
491
  if (shouldPassThrough) {
526
492
  if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
527
493
  console.groupCollapsed(` 🔹 pass through ${keyInit}`)
494
+ // prettier-ignore
528
495
  // rome-ignore lint/nursery/noConsoleLog: <explanation>
529
- console.log({
530
- valInit,
531
- variants,
532
- variant: variants?.[keyInit],
533
- isVariant,
534
- shouldPassProp,
535
- isHOCShouldPassThrough,
536
- })
496
+ console.log({ valInit, variants, variant: variants?.[keyInit], isVariant, shouldPassProp, isHOCShouldPassThrough })
537
497
  console.groupEnd()
538
498
  }
539
499
 
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
- }
556
-
557
- passDownProp(keyInit, valInit, isMediaOrPseudo)
500
+ // // TODO bring this back but probably improve it?
501
+ // if (isPseudo) {
502
+ // // 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
503
+ // // like our own variants that aren't in parent
504
+ // const pseudoStyleObject = getSubStyle(
505
+ // styleState,
506
+ // keyInit,
507
+ // valInit,
508
+ // fontFamily,
509
+ // true,
510
+ // state.noClassNames
511
+ // )
512
+ // const descriptor = pseudoDescriptors[keyInit]
513
+ // for (const key in pseudoStyleObject) {
514
+ // debugger
515
+ // }
516
+ // }
517
+
518
+ passDownProp(viewProps, keyInit, valInit, isMediaOrPseudo)
558
519
 
559
520
  // if it's a variant here, we have a two layer variant...
560
521
  // aka styled(Input, { unstyled: true, variants: { unstyled: {} } })
561
522
  // which now has it's own unstyled + the child unstyled...
562
523
  // so *don't* skip applying the styles, but also pass `unstyled` to children
563
524
  if (!isVariant) {
564
- return
525
+ continue
565
526
  }
566
527
  }
567
528
 
529
+ // default font family
530
+ // is this great? no, but backwards compat until we add tests and make better
531
+ defaultFontVariable ||= `$${conf.defaultFont}`
532
+ fontFamily ||=
533
+ props[conf.inverseShorthands.fontFamily] || props.fontFamily || defaultFontVariable
534
+
568
535
  const expanded = isMediaOrPseudo
569
536
  ? [[keyInit, valInit]]
570
537
  : propMapper(
571
538
  keyInit,
572
539
  valInit,
573
540
  theme,
574
- special ? { ...props, fontFamily: fontFamilyOverride } : props,
541
+ props,
575
542
  state,
543
+ fontFamily,
576
544
  languageContext,
577
545
  undefined,
578
546
  debug
@@ -582,18 +550,11 @@ export const getSplitStyles: StyleSplitter = (
582
550
  fontFamily = getPropMappedFontFamily(expanded)
583
551
  }
584
552
 
585
- if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
553
+ if (process.env.NODE_ENV === 'development' && debug === 'verbose' && isClient) {
586
554
  console.groupCollapsed(' 🔹 styles', keyInit, valInit)
555
+ // prettier-ignore
587
556
  // 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
- })
557
+ console.log({ expanded, state: { ...state }, isVariant, variant: variants?.[keyInit], shouldPassProp, isHOCShouldPassThrough, theme, usedKeys: { ...usedKeys } })
597
558
  if (!isServer && isDevTools) {
598
559
  // rome-ignore lint/nursery/noConsoleLog: ok
599
560
  console.log('expanded', expanded, '\nusedKeys', { ...usedKeys }, '\ncurrent', {
@@ -603,30 +564,18 @@ export const getSplitStyles: StyleSplitter = (
603
564
  console.groupEnd()
604
565
  }
605
566
 
606
- if (!expanded) return
567
+ if (!expanded) continue
607
568
 
608
569
  for (const [key, val] of expanded) {
609
- if (val === undefined) continue
570
+ if (val == null) continue
610
571
 
611
- if (key in stylePropsFont && !special && key !== 'fontFamily') {
612
- specialProps.push([key, val])
613
- continue
614
- }
572
+ if (key in usedKeys) continue
615
573
 
616
574
  isMedia = isMediaKey(key)
617
575
  isPseudo = key in validPseudoKeys
618
576
  isMediaOrPseudo = isMedia || isPseudo
619
577
 
620
- if (!isMediaOrPseudo && key in usedKeys) {
621
- if (process.env.NODE_ENV === 'developmnet' && debug === 'verbose') {
622
- // rome-ignore lint/nursery/noConsoleLog: <explanation>
623
- console.log(`Used media/pseudo ${key}`)
624
- }
625
- continue
626
- }
627
-
628
578
  if (inlineProps?.has(key) || inlineWhenUnflattened?.has(key)) {
629
- usedKeys[key] = 1
630
579
  viewProps[key] = props[key] ?? val
631
580
  }
632
581
 
@@ -636,7 +585,14 @@ export const getSplitStyles: StyleSplitter = (
636
585
  (isMediaOrPseudo || staticConfig.parentStaticConfig?.variants?.[keyInit])
637
586
 
638
587
  if (isHOCShouldPassThrough) {
639
- passDownProp(key, val)
588
+ isVariant = variants && key in variants
589
+ passDownProp(viewProps, key, val, isMediaOrPseudo)
590
+ if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
591
+ console.groupCollapsed(` - passing down prop ${key}`)
592
+ // rome-ignore lint/nursery/noConsoleLog: <explanation>
593
+ console.log({ val, after: { ...viewProps[key] } })
594
+ console.groupEnd()
595
+ }
640
596
  // if its also a variant here, pass down but also keep it
641
597
  if (!isVariant) {
642
598
  continue
@@ -652,6 +608,7 @@ export const getSplitStyles: StyleSplitter = (
652
608
  styleState,
653
609
  key,
654
610
  val,
611
+ fontFamily,
655
612
  true,
656
613
  state.noClassNames
657
614
  )
@@ -662,38 +619,42 @@ export const getSplitStyles: StyleSplitter = (
662
619
 
663
620
  // don't continue here on isEnter && !state.unmounted because we need to merge defaults
664
621
  if (!descriptor || (isExit && !state.isExiting)) {
622
+ if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
623
+ // prettier-ignore
624
+ // rome-ignore lint/nursery/noConsoleLog: <explanation>
625
+ console.log('skip exit')
626
+ }
627
+
665
628
  continue
666
629
  }
667
630
 
668
631
  if (!shouldDoClasses || IS_STATIC) {
669
632
  pseudos ||= {}
670
633
  pseudos[key] ||= {}
671
- Object.assign(pseudos[key], pseudoStyleObject)
672
634
  }
673
635
 
674
636
  if (shouldDoClasses && !isEnter && !isExit) {
675
637
  const pseudoStyles = generateAtomicStyles(pseudoStyleObject, descriptor)
676
638
  for (const psuedoStyle of pseudoStyles) {
677
639
  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
- }
640
+ addStyleToInsertRules(rulesToInsert, psuedoStyle)
641
+ mergeClassName(
642
+ transforms,
643
+ classNames,
644
+ fullKey,
645
+ psuedoStyle.identifier,
646
+ isMediaOrPseudo
647
+ )
690
648
  }
691
649
  } else {
692
- if (key in usedKeys) {
693
- continue
694
- }
650
+ // we don't skip this if disabled because we need to animate to default states that aren't even set:
651
+ // so if we have <Stack enterStyle={{ opacity: 0 }} />
652
+ // we need to animate from 0 => 1 once enter is finished
653
+ // see the if (isDisabled) block below which loops through animatableDefaults
695
654
 
696
- let isDisabled = !state[descriptor.stateKey || descriptor.name]
655
+ const descriptorKey = descriptor.stateKey || descriptor.name
656
+ const pseudoState = state[descriptorKey]
657
+ let isDisabled = !pseudoState
697
658
 
698
659
  // we never animate in on server side just show the full thing
699
660
  // on client side we use CSS to hide the fully in SSR items, then
@@ -702,51 +663,62 @@ export const getSplitStyles: StyleSplitter = (
702
663
  isDisabled = false
703
664
  }
704
665
 
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
- }
666
+ if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
667
+ // prettier-ignore
668
+ console.groupCollapsed('pseudo', keyInit, !isDisabled)
669
+ // prettier-ignore
670
+ // rome-ignore lint/nursery/noConsoleLog: <explanation>
671
+ console.log(pseudoStyleObject, { isDisabled, descriptorKey, descriptor, pseudoState, state: { ...state } })
672
+ console.groupEnd()
717
673
  }
718
674
 
719
- psuedosUsed ||= {}
675
+ // if (!isDisabled) {
676
+ // if (valInit === staticConfig.defaultProps[keyInit]) {
677
+ // // ignore:
678
+ // // if it's a default property given by styled(), we don't mark it as used, so
679
+ // // that props given inline can override:
680
+ // }
681
+ // }
720
682
 
721
683
  const importance = descriptor.priority
722
684
 
685
+ if (!isDisabled) {
686
+ // mark usedKeys based not on pseudoStyleObject
687
+ for (const key in val) {
688
+ const k = shorthands[key] || key
689
+ usedKeys[k] = Math.max(importance, usedKeys[k] || 0)
690
+ }
691
+ }
692
+
723
693
  for (const pkey in pseudoStyleObject) {
724
694
  const val = pseudoStyleObject[pkey]
725
695
  // when disabled ensure the default value is set for future animations to align
696
+
726
697
  if (isDisabled) {
727
- if (!(pkey in usedKeys) && pkey in animatableDefaults) {
698
+ if (pkey in animatableDefaults && !(pkey in usedKeys)) {
728
699
  const defaultVal = animatableDefaults[pkey]
729
- mergeStyle(styleState, flatTransforms, pkey, defaultVal, true)
700
+ mergeStyle(styleState, flatTransforms, pkey, defaultVal)
701
+ }
702
+ } else {
703
+ const curImportance = usedKeys[importance] || 0
704
+ const shouldMerge = importance >= curImportance
705
+
706
+ if (shouldMerge) {
707
+ pseudos ||= {}
708
+ pseudos[key] ||= {}
709
+ pseudos[key][pkey] = val
710
+ mergeStyle(styleState, flatTransforms, pkey, val)
711
+ usedKeys[pkey] ||= 1
712
+ }
713
+ if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
714
+ // prettier-ignore
715
+ // rome-ignore lint/nursery/noConsoleLog: <explanation>
716
+ console.log(' subKey', pkey, shouldMerge, { importance, curImportance, pkey, val })
730
717
  }
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
718
  }
748
719
  }
749
720
  }
721
+
750
722
  continue
751
723
  }
752
724
 
@@ -763,6 +735,7 @@ export const getSplitStyles: StyleSplitter = (
763
735
  styleState,
764
736
  key,
765
737
  val,
738
+ fontFamily,
766
739
  // TODO try true like pseudo
767
740
  false
768
741
  )
@@ -809,12 +782,8 @@ export const getSplitStyles: StyleSplitter = (
809
782
  for (const style of mediaStyles) {
810
783
  const out = createMediaStyle(style, mediaKeyShort, mediaQueryConfig)
811
784
  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
- }
785
+ addStyleToInsertRules(rulesToInsert, out as any)
786
+ mergeClassName(transforms, classNames, fullKey, out.identifier, true)
818
787
  }
819
788
  } else if (mediaState[mediaKeyShort]) {
820
789
  for (const subKey in mediaStyle) {
@@ -845,7 +814,6 @@ export const getSplitStyles: StyleSplitter = (
845
814
 
846
815
  if (process.env.TAMAGUI_TARGET === 'native') {
847
816
  if (key === 'pointerEvents') {
848
- usedKeys[key] = 1
849
817
  viewProps[key] = val
850
818
  continue
851
819
  }
@@ -858,13 +826,9 @@ export const getSplitStyles: StyleSplitter = (
858
826
  }
859
827
  }
860
828
 
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'
829
+ if (
830
+ key in validStyleProps ||
831
+ (process.env.TAMAGUI_TARGET === 'native' && isAndroid && key === 'elevation')
868
832
  ) {
869
833
  mergeStyle(styleState, flatTransforms, key, val)
870
834
  continue
@@ -873,28 +837,13 @@ export const getSplitStyles: StyleSplitter = (
873
837
  // pass to view props
874
838
  if (!isVariant && !(key in skipProps)) {
875
839
  viewProps[key] = val
876
- usedKeys[key] = 1
877
840
  }
878
841
  }
879
842
  }
880
843
 
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
844
  // default to default font
889
845
  fontFamily ||= conf.defaultFont
890
846
 
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
847
  fixStyles(style)
899
848
  if (isWeb) {
900
849
  styleToCSS(style)
@@ -932,7 +881,7 @@ export const getSplitStyles: StyleSplitter = (
932
881
  // always do this at the very end to preserve the order strictly (animations, origin)
933
882
  // and allow proper merging of all pseudos before applying
934
883
  if (flatTransforms) {
935
- mergeTransforms(style, flatTransforms, true)
884
+ mergeFlatTransforms(style, flatTransforms, true)
936
885
  }
937
886
 
938
887
  // add in defaults if not set:
@@ -961,9 +910,10 @@ export const getSplitStyles: StyleSplitter = (
961
910
  // avoid re-processing for rnw
962
911
  } else {
963
912
  const atomic = getStylesAtomic(style)
913
+
964
914
  for (const atomicStyle of atomic) {
965
915
  const key = atomicStyle.property
966
- if (props.animateOnly && props.animateOnly.includes(key)) {
916
+ if (state.isAnimated && props.animateOnly && props.animateOnly.includes(key)) {
967
917
  retainedStyles[key] = style[key]
968
918
  } else {
969
919
  addStyleToInsertRules(rulesToInsert, atomicStyle)
@@ -1042,21 +992,11 @@ export const getSplitStyles: StyleSplitter = (
1042
992
  }
1043
993
  }
1044
994
 
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
995
  const result: GetStyleResult = {
1056
996
  space,
1057
997
  hasMedia,
1058
998
  fontFamily,
1059
- viewProps: nextViewProps,
999
+ viewProps,
1060
1000
  // @ts-expect-error
1061
1001
  style,
1062
1002
  pseudos,
@@ -1070,9 +1010,9 @@ export const getSplitStyles: StyleSplitter = (
1070
1010
 
1071
1011
  if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
1072
1012
  if (isDevTools) {
1073
- console.groupCollapsed(' 🔹 =>')
1013
+ console.groupCollapsed(' 🔹 ===>')
1074
1014
  // prettier-ignore
1075
- const logs = { ...result, state, etc: { transforms, viewProps, rulesToInsert, parentSplitStyles, flatTransforms } }
1015
+ const logs = { ...result, state, transforms, viewProps, viewPropsOrder: Object.keys(viewProps), rulesToInsert, parentSplitStyles, flatTransforms }
1076
1016
  for (const key in logs) {
1077
1017
  // rome-ignore lint/nursery/noConsoleLog: ok
1078
1018
  console.log(key, logs[key])
@@ -1177,17 +1117,14 @@ function getSubStyleProps(
1177
1117
  }
1178
1118
 
1179
1119
  function mergeStyle(
1180
- { usedKeys, classNames, viewProps, style }: GetStyleState,
1120
+ { classNames, viewProps, style, usedKeys }: GetStyleState,
1181
1121
  flatTransforms: FlatTransforms,
1182
1122
  key: string,
1183
- val: any,
1184
- dontSetUsed = false
1123
+ val: any
1185
1124
  ) {
1186
- if (!dontSetUsed) {
1187
- usedKeys[key] ||= 1
1188
- }
1189
1125
  if (val && val[0] === '_') {
1190
1126
  classNames[key] = val
1127
+ usedKeys[key] ||= 1
1191
1128
  } else if (key in stylePropsTransform) {
1192
1129
  flatTransforms ||= {}
1193
1130
  flatTransforms[key] = val
@@ -1205,6 +1142,7 @@ export const getSubStyle = (
1205
1142
  styleState: GetStyleState,
1206
1143
  subKey: string,
1207
1144
  styleIn: Object,
1145
+ fontFamily?: string,
1208
1146
  avoidDefaultProps?: boolean,
1209
1147
  avoidMergeTransform?: boolean
1210
1148
  ): TextStyleProps => {
@@ -1220,15 +1158,13 @@ export const getSubStyle = (
1220
1158
  theme,
1221
1159
  getSubStyleProps(staticConfig.defaultProps, props, props[subKey]),
1222
1160
  state,
1161
+ fontFamily,
1223
1162
  languageContext,
1224
1163
  avoidDefaultProps
1225
1164
  )
1226
- if (!staticConfig.isHOC) {
1227
- if (key in skipProps) {
1228
- continue
1229
- }
1165
+ if (!expanded || (!staticConfig.isHOC && key in skipProps)) {
1166
+ continue
1230
1167
  }
1231
- if (!expanded) continue
1232
1168
  for (const [skey, sval] of expanded) {
1233
1169
  if (!avoidMergeTransform && skey in stylePropsTransform) {
1234
1170
  mergeTransform(styleOut, skey, sval)
@@ -1280,6 +1216,8 @@ const animatableDefaults = {
1280
1216
  rotate: '0deg',
1281
1217
  rotateY: '0deg',
1282
1218
  rotateX: '0deg',
1219
+ x: 0,
1220
+ y: 0,
1283
1221
  }
1284
1222
 
1285
1223
  const lowercaseHyphenate = (match: string) => `-${match.toLowerCase()}`
@@ -1299,14 +1237,25 @@ const mergeTransform = (
1299
1237
  } as any)
1300
1238
  }
1301
1239
 
1302
- const mergeTransforms = (
1240
+ // we need to match the order for animations to work because it needs consistent order
1241
+ // was thinking of having something like `state.prevTransformsOrder = ['y', 'x', ...]
1242
+ // but if we just handle it here its not a big cost and avoids having stateful things
1243
+ // so the strategy is: always sort by a consistent order, until you run into a "duplicate"
1244
+ // because you can have something like:
1245
+ // [{ translateX: 0 }, { scale: 1 }, { translateX: 10 }]
1246
+ // so basically we sort until we get to a duplicate... we could sort even smarter but
1247
+ // this should work for most (all?) of our cases since the order preservation really only needs to apply
1248
+ // to the "flat" transform props
1249
+ const mergeFlatTransforms = (
1303
1250
  obj: TextStyleProps,
1304
1251
  flatTransforms: FlatTransforms,
1305
1252
  backwards = false
1306
1253
  ) => {
1307
- Object.entries(flatTransforms).forEach(([key, val]) => {
1308
- mergeTransform(obj, key, val, backwards)
1309
- })
1254
+ Object.entries(flatTransforms)
1255
+ .sort(([a], [b]) => a.localeCompare(b))
1256
+ .forEach(([key, val]) => {
1257
+ mergeTransform(obj, key, val, backwards)
1258
+ })
1310
1259
  }
1311
1260
 
1312
1261
  const mapTransformKeys = {
@@ -1323,6 +1272,10 @@ const skipProps = {
1323
1272
  tag: true,
1324
1273
  }
1325
1274
 
1275
+ const handledProps = {
1276
+ role: true,
1277
+ }
1278
+
1326
1279
  if (process.env.NODE_ENV === 'test') {
1327
1280
  skipProps['data-test-renders'] = true
1328
1281
  }
@@ -1345,6 +1298,10 @@ if (process.env.TAMAGUI_TARGET === 'native') {
1345
1298
  outlineWidth: true,
1346
1299
  outlineColor: true,
1347
1300
  })
1301
+ } else {
1302
+ Object.assign(skipProps, {
1303
+ elevationAndroid: true,
1304
+ })
1348
1305
  }
1349
1306
 
1350
1307
  const accessibilityRoleToWebRole = {
@@ -1355,3 +1312,22 @@ const accessibilityRoleToWebRole = {
1355
1312
  none: 'presentation',
1356
1313
  summary: 'region',
1357
1314
  }
1315
+
1316
+ function passDownProp(
1317
+ viewProps: Object,
1318
+ key: string,
1319
+ val: any,
1320
+ shouldMergeObject = false
1321
+ ) {
1322
+ if (shouldMergeObject) {
1323
+ const next = {
1324
+ ...viewProps[key],
1325
+ ...val,
1326
+ }
1327
+ // need to re-insert it at current position
1328
+ delete viewProps[key]
1329
+ viewProps[key] = next
1330
+ } else {
1331
+ viewProps[key] = val
1332
+ }
1333
+ }