@tamagui/web 1.46.1 → 1.47.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 (173) hide show
  1. package/dist/cjs/constants/constants.js +15 -15
  2. package/dist/cjs/constants/constants.js.map +1 -1
  3. package/dist/cjs/createComponent.js +92 -114
  4. package/dist/cjs/createComponent.js.map +1 -1
  5. package/dist/cjs/createTamagui.js +0 -1
  6. package/dist/cjs/createTamagui.js.map +1 -1
  7. package/dist/cjs/helpers/ThemeManager.js +6 -5
  8. package/dist/cjs/helpers/ThemeManager.js.map +1 -1
  9. package/dist/cjs/helpers/getSplitStyles.js +75 -98
  10. package/dist/cjs/helpers/getSplitStyles.js.map +2 -2
  11. package/dist/cjs/helpers/getStylesAtomic.js +7 -7
  12. package/dist/cjs/helpers/getStylesAtomic.js.map +1 -1
  13. package/dist/cjs/helpers/getVariantExtras.js +2 -10
  14. package/dist/cjs/helpers/getVariantExtras.js.map +1 -1
  15. package/dist/cjs/helpers/isTamaguiComponent.js +1 -1
  16. package/dist/cjs/helpers/isTamaguiComponent.js.map +1 -1
  17. package/dist/cjs/helpers/mergeProps.js +6 -14
  18. package/dist/cjs/helpers/mergeProps.js.map +1 -1
  19. package/dist/cjs/helpers/normalizeColor.js +2 -1
  20. package/dist/cjs/helpers/normalizeColor.js.map +1 -1
  21. package/dist/cjs/helpers/normalizeValueWithProperty.js +5 -56
  22. package/dist/cjs/helpers/normalizeValueWithProperty.js.map +1 -1
  23. package/dist/cjs/helpers/{createPropMapper.js → propMapper.js} +63 -139
  24. package/dist/cjs/helpers/propMapper.js.map +6 -0
  25. package/dist/cjs/helpers/pseudoDescriptors.js +0 -1
  26. package/dist/cjs/helpers/pseudoDescriptors.js.map +1 -1
  27. package/dist/cjs/helpers/useShallowSetState.js +9 -17
  28. package/dist/cjs/helpers/useShallowSetState.js.map +1 -1
  29. package/dist/cjs/helpers/withStaticProperties.js +9 -0
  30. package/dist/cjs/helpers/withStaticProperties.js.map +1 -1
  31. package/dist/cjs/hooks/useMedia.js +7 -9
  32. package/dist/cjs/hooks/useMedia.js.map +1 -1
  33. package/dist/cjs/hooks/useStyle.js +5 -2
  34. package/dist/cjs/hooks/useStyle.js.map +1 -1
  35. package/dist/cjs/hooks/useTheme.js +28 -32
  36. package/dist/cjs/hooks/useTheme.js.map +1 -1
  37. package/dist/cjs/index.js +2 -2
  38. package/dist/cjs/index.js.map +1 -1
  39. package/dist/cjs/views/Stack.js +1 -4
  40. package/dist/cjs/views/Stack.js.map +1 -1
  41. package/dist/cjs/views/Theme.js +2 -2
  42. package/dist/cjs/views/Theme.js.map +1 -1
  43. package/dist/cjs/views/ThemeDebug.js +2 -2
  44. package/dist/cjs/views/ThemeDebug.js.map +1 -1
  45. package/dist/esm/constants/constants.js +14 -13
  46. package/dist/esm/constants/constants.js.map +1 -1
  47. package/dist/esm/createComponent.js +92 -114
  48. package/dist/esm/createComponent.js.map +1 -1
  49. package/dist/esm/createTamagui.js +0 -1
  50. package/dist/esm/createTamagui.js.map +1 -1
  51. package/dist/esm/helpers/ThemeManager.js +6 -5
  52. package/dist/esm/helpers/ThemeManager.js.map +1 -1
  53. package/dist/esm/helpers/getSplitStyles.js +74 -97
  54. package/dist/esm/helpers/getSplitStyles.js.map +2 -2
  55. package/dist/esm/helpers/getStylesAtomic.js +7 -7
  56. package/dist/esm/helpers/getStylesAtomic.js.map +1 -1
  57. package/dist/esm/helpers/getVariantExtras.js +2 -10
  58. package/dist/esm/helpers/getVariantExtras.js.map +1 -1
  59. package/dist/esm/helpers/isTamaguiComponent.js +1 -1
  60. package/dist/esm/helpers/isTamaguiComponent.js.map +1 -1
  61. package/dist/esm/helpers/mergeProps.js +6 -14
  62. package/dist/esm/helpers/mergeProps.js.map +1 -1
  63. package/dist/esm/helpers/normalizeColor.js +2 -1
  64. package/dist/esm/helpers/normalizeColor.js.map +1 -1
  65. package/dist/esm/helpers/normalizeValueWithProperty.js +5 -56
  66. package/dist/esm/helpers/normalizeValueWithProperty.js.map +1 -1
  67. package/dist/esm/helpers/{createPropMapper.js → propMapper.js} +56 -132
  68. package/dist/esm/helpers/propMapper.js.map +6 -0
  69. package/dist/esm/helpers/pseudoDescriptors.js +0 -1
  70. package/dist/esm/helpers/pseudoDescriptors.js.map +1 -1
  71. package/dist/esm/helpers/useShallowSetState.js +9 -17
  72. package/dist/esm/helpers/useShallowSetState.js.map +1 -1
  73. package/dist/esm/helpers/withStaticProperties.js +9 -0
  74. package/dist/esm/helpers/withStaticProperties.js.map +1 -1
  75. package/dist/esm/hooks/useMedia.js +8 -10
  76. package/dist/esm/hooks/useMedia.js.map +1 -1
  77. package/dist/esm/hooks/useStyle.js +5 -2
  78. package/dist/esm/hooks/useStyle.js.map +1 -1
  79. package/dist/esm/hooks/useTheme.js +28 -32
  80. package/dist/esm/hooks/useTheme.js.map +1 -1
  81. package/dist/esm/index.js +1 -1
  82. package/dist/esm/index.js.map +1 -1
  83. package/dist/esm/views/Stack.js +1 -4
  84. package/dist/esm/views/Stack.js.map +1 -1
  85. package/dist/esm/views/Theme.js +2 -2
  86. package/dist/esm/views/Theme.js.map +1 -1
  87. package/dist/esm/views/ThemeDebug.js +2 -2
  88. package/dist/esm/views/ThemeDebug.js.map +1 -1
  89. package/package.json +9 -9
  90. package/src/constants/constants.ts +15 -11
  91. package/src/createComponent.tsx +157 -148
  92. package/src/createTamagui.ts +0 -1
  93. package/src/helpers/ThemeManager.tsx +10 -6
  94. package/src/helpers/getSplitStyles.tsx +139 -172
  95. package/src/helpers/getStylesAtomic.ts +7 -7
  96. package/src/helpers/getVariantExtras.tsx +15 -31
  97. package/src/helpers/isTamaguiComponent.tsx +3 -3
  98. package/src/helpers/mergeProps.ts +5 -20
  99. package/src/helpers/normalizeColor.ts +2 -1
  100. package/src/helpers/normalizeValueWithProperty.ts +8 -64
  101. package/src/helpers/{createPropMapper.ts → propMapper.ts} +71 -165
  102. package/src/helpers/pseudoDescriptors.ts +0 -1
  103. package/src/helpers/useShallowSetState.tsx +10 -16
  104. package/src/helpers/withStaticProperties.tsx +13 -0
  105. package/src/hooks/useMedia.tsx +15 -10
  106. package/src/hooks/useStyle.tsx +7 -4
  107. package/src/hooks/useTheme.tsx +36 -47
  108. package/src/index.ts +1 -1
  109. package/src/types.tsx +20 -33
  110. package/src/views/Stack.tsx +1 -4
  111. package/src/views/Theme.tsx +3 -3
  112. package/src/views/ThemeDebug.tsx +2 -2
  113. package/types/constants/constants.d.ts +0 -15
  114. package/types/constants/constants.d.ts.map +1 -1
  115. package/types/createComponent.d.ts +5 -8
  116. package/types/createComponent.d.ts.map +1 -1
  117. package/types/createTamagui.d.ts.map +1 -1
  118. package/types/helpers/ThemeManager.d.ts +1 -1
  119. package/types/helpers/ThemeManager.d.ts.map +1 -1
  120. package/types/helpers/getSplitStyles.d.ts +3 -7
  121. package/types/helpers/getSplitStyles.d.ts.map +1 -1
  122. package/types/helpers/getVariantExtras.d.ts +1 -1
  123. package/types/helpers/getVariantExtras.d.ts.map +1 -1
  124. package/types/helpers/isTamaguiComponent.d.ts.map +1 -1
  125. package/types/helpers/mergeProps.d.ts +1 -1
  126. package/types/helpers/mergeProps.d.ts.map +1 -1
  127. package/types/helpers/normalizeColor.d.ts.map +1 -1
  128. package/types/helpers/normalizeValueWithProperty.d.ts.map +1 -1
  129. package/types/helpers/{createPropMapper.d.ts → propMapper.d.ts} +3 -3
  130. package/types/helpers/propMapper.d.ts.map +1 -0
  131. package/types/helpers/pseudoDescriptors.d.ts.map +1 -1
  132. package/types/helpers/useShallowSetState.d.ts.map +1 -1
  133. package/types/helpers/withStaticProperties.d.ts.map +1 -1
  134. package/types/hooks/useMedia.d.ts.map +1 -1
  135. package/types/hooks/useStyle.d.ts +2 -2
  136. package/types/hooks/useStyle.d.ts.map +1 -1
  137. package/types/hooks/useTheme.d.ts +7 -13
  138. package/types/hooks/useTheme.d.ts.map +1 -1
  139. package/types/index.d.ts +1 -1
  140. package/types/index.d.ts.map +1 -1
  141. package/types/styled.d.ts +1 -1
  142. package/types/types.d.ts +17 -25
  143. package/types/types.d.ts.map +1 -1
  144. package/types/views/Stack.d.ts.map +1 -1
  145. package/dist/cjs/helpers/createPropMapper.js.map +0 -6
  146. package/dist/cjs/helpers/parseStaticConfig.js +0 -40
  147. package/dist/cjs/helpers/parseStaticConfig.js.map +0 -6
  148. package/dist/cjs/helpers/swapFontFaceOnWeight.js +0 -63
  149. package/dist/cjs/helpers/swapFontFaceOnWeight.js.map +0 -6
  150. package/dist/cjs/hooks/useSafeRef.js +0 -59
  151. package/dist/cjs/hooks/useSafeRef.js.map +0 -6
  152. package/dist/cjs/hooks/useServerHooks.js +0 -36
  153. package/dist/cjs/hooks/useServerHooks.js.map +0 -6
  154. package/dist/esm/helpers/createPropMapper.js.map +0 -6
  155. package/dist/esm/helpers/parseStaticConfig.js +0 -16
  156. package/dist/esm/helpers/parseStaticConfig.js.map +0 -6
  157. package/dist/esm/helpers/swapFontFaceOnWeight.js +0 -39
  158. package/dist/esm/helpers/swapFontFaceOnWeight.js.map +0 -6
  159. package/dist/esm/hooks/useSafeRef.js +0 -35
  160. package/dist/esm/hooks/useSafeRef.js.map +0 -6
  161. package/dist/esm/hooks/useServerHooks.js +0 -11
  162. package/dist/esm/hooks/useServerHooks.js.map +0 -6
  163. package/src/helpers/parseStaticConfig.ts +0 -14
  164. package/src/hooks/useSafeRef.ts +0 -45
  165. package/types/helpers/createPropMapper.d.ts.map +0 -1
  166. package/types/helpers/parseStaticConfig.d.ts +0 -3
  167. package/types/helpers/parseStaticConfig.d.ts.map +0 -1
  168. package/types/helpers/swapFontFaceOnWeight.d.ts +0 -4
  169. package/types/helpers/swapFontFaceOnWeight.d.ts.map +0 -1
  170. package/types/hooks/useSafeRef.d.ts +0 -4
  171. package/types/hooks/useSafeRef.d.ts.map +0 -1
  172. package/types/hooks/useServerHooks.d.ts +0 -4
  173. package/types/hooks/useServerHooks.d.ts.map +0 -1
@@ -1,6 +1,7 @@
1
1
  import { useComposedRefs } from '@tamagui/compose-refs'
2
2
  import { isClient, isServer, isWeb, useIsomorphicLayoutEffect } from '@tamagui/constants'
3
3
  import { validStyles } from '@tamagui/helpers'
4
+ import { useDidFinishSSR } from '@tamagui/use-did-finish-ssr'
4
5
  import React, {
5
6
  Children,
6
7
  Fragment,
@@ -9,6 +10,7 @@ import React, {
9
10
  memo,
10
11
  useCallback,
11
12
  useContext,
13
+ useEffect,
12
14
  useId,
13
15
  useRef,
14
16
  useState,
@@ -21,7 +23,6 @@ import { TextAncestorContext } from './contexts/TextAncestorContext'
21
23
  import { didGetVariableValue, setDidGetVariableValue } from './createVariable'
22
24
  import { useSplitStyles } from './helpers/getSplitStyles'
23
25
  import { mergeProps } from './helpers/mergeProps'
24
- import { parseStaticConfig } from './helpers/parseStaticConfig'
25
26
  import { proxyThemeVariables } from './helpers/proxyThemeVariables'
26
27
  import { themeable } from './helpers/themeable'
27
28
  import { useShallowSetState } from './helpers/useShallowSetState'
@@ -35,7 +36,6 @@ import {
35
36
  SpaceValue,
36
37
  SpacerProps,
37
38
  StaticConfig,
38
- StaticConfigParsed,
39
39
  TamaguiComponent,
40
40
  TamaguiComponentEvents,
41
41
  TamaguiComponentState,
@@ -48,17 +48,7 @@ import { Slot } from './views/Slot'
48
48
  import { useThemedChildren } from './views/Theme'
49
49
  import { ThemeDebug } from './views/ThemeDebug'
50
50
 
51
- // let t
52
- // import { timer } from '@tamagui/timer'
53
- // if (true || process.env.ANALYZE) {
54
- // t = require().timer()
55
- // setTimeout(() => {
56
- // const out = t.print()
57
- // if (isClient) {
58
- // alert(out)
59
- // }
60
- // }, 2000)
61
- // }
51
+ const timer = require('@tamagui/timer').timer()
62
52
 
63
53
  // this appears to fix expo / babel not picking this up sometimes? really odd
64
54
  process.env.TAMAGUI_TARGET
@@ -118,9 +108,7 @@ export function createComponent<
118
108
  ComponentPropTypes extends Object = {},
119
109
  Ref = TamaguiElement,
120
110
  BaseProps = never
121
- >(staticConfigIn: Partial<StaticConfig> | StaticConfigParsed) {
122
- const staticConfig = parseStaticConfig(staticConfigIn)
123
-
111
+ >(staticConfig: StaticConfig) {
124
112
  onConfiguredOnce((conf) => {
125
113
  // one time only setup
126
114
  if (!tamaguiConfig) {
@@ -151,18 +139,22 @@ export function createComponent<
151
139
  const defaultComponentClassName = `is_${staticConfig.componentName}`
152
140
  const defaultProps = staticConfig.defaultProps
153
141
 
154
- if (process.env.NODE_ENV === 'development' && staticConfigIn.defaultProps?.['debug']) {
142
+ if (process.env.NODE_ENV === 'development' && staticConfig.defaultProps?.['debug']) {
155
143
  if (process.env.IS_STATIC !== 'is_static') {
156
144
  // rome-ignore lint/nursery/noConsoleLog: <explanation>
157
145
  console.log(`🐛 [${staticConfig.componentName || 'Component'}]`, {
158
146
  staticConfig,
159
147
  defaultProps,
160
- defaultPropsKeyOrder: Object.keys(defaultProps),
148
+ defaultPropsKeyOrder: defaultProps ? Object.keys(defaultProps) : [],
161
149
  })
162
150
  }
163
151
  }
164
152
 
165
153
  const component = forwardRef<Ref, ComponentPropTypes>((propsIn: any, forwardedRef) => {
154
+ // const shouldTime = staticConfig.defaultProps?.padding === 5
155
+ // let time: any
156
+ // if (shouldTime) time = timer.start()
157
+
166
158
  if (process.env.TAMAGUI_TARGET === 'native') {
167
159
  // todo this could be moved to a cleaner location
168
160
  if (!hasSetupBaseViews) {
@@ -182,7 +174,6 @@ export function createComponent<
182
174
  propsIn['data-test-renders']['current'] += 1
183
175
  }
184
176
  }
185
- // const time = t.start({ quiet: true })
186
177
 
187
178
  // set variants through context
188
179
  // order is after default props but before props
@@ -197,8 +188,8 @@ export function createComponent<
197
188
  // because its after default props but before props this annoying amount of checks
198
189
  propsIn[key] ||
199
190
  propsIn[inverseShorthands[key]] ||
200
- defaultProps[key] ||
201
- defaultProps[inverseShorthands[key]]
191
+ defaultProps?.[key] ||
192
+ defaultProps?.[inverseShorthands[key]]
202
193
  // if not set, use context
203
194
  if (propVal === undefined) {
204
195
  if (contextValue) {
@@ -225,9 +216,8 @@ export function createComponent<
225
216
  // React inserts default props after your props for some reason...
226
217
  // order important so we do loops, you can't just spread because JS does weird things
227
218
  let props: any
228
-
229
219
  if (curDefaultProps) {
230
- props = mergeProps(curDefaultProps, propsIn)[0]
220
+ props = mergeProps(curDefaultProps, propsIn)
231
221
  } else {
232
222
  props = propsIn
233
223
  }
@@ -235,6 +225,8 @@ export function createComponent<
235
225
  const debugProp = props['debug'] as DebugProp
236
226
  const componentName = props.componentName || staticConfig.componentName
237
227
 
228
+ const isHydrated = useDidFinishSSR()
229
+
238
230
  // conditional but if ever true stays true
239
231
  // [animated, inversed]
240
232
  const stateRef = useRef(
@@ -246,6 +238,8 @@ export function createComponent<
246
238
  )
247
239
  stateRef.current ||= {}
248
240
 
241
+ // if (shouldTime) time`stateref`
242
+
249
243
  const hostRef = useRef<TamaguiElement>(null)
250
244
 
251
245
  /**
@@ -259,13 +253,13 @@ export function createComponent<
259
253
  props.animation || (props.style && hasAnimatedStyleValue(props.style))
260
254
  )
261
255
 
256
+ // disable for now still ssr issues
257
+ const supportsCSSVars = animationsConfig?.supportsCSSVars
258
+
262
259
  const willBeAnimated = (() => {
263
- if (isServer) return false
260
+ if (isServer && !supportsCSSVars) return false
264
261
  const curState = stateRef.current
265
262
  const next = !!(hasAnimationProp && !isHOC && useAnimations)
266
- if (next && !curState.hasAnimated) {
267
- curState.hasAnimated = true
268
- }
269
263
  return Boolean(next || curState.hasAnimated)
270
264
  })()
271
265
 
@@ -273,47 +267,43 @@ export function createComponent<
273
267
  const presence = (willBeAnimated && usePresence?.()) || null
274
268
 
275
269
  const hasEnterStyle = !!props.enterStyle
270
+ const needsMount = Boolean((isWeb ? isClient : true) && willBeAnimated)
276
271
 
277
- // disable for now still ssr issues
278
- const supportsCSSVariables = false // ?? animationsConfig?.supportsCSSVariables
272
+ // if (shouldTime) time`pre-use-state`
279
273
 
280
- const needsMount = Boolean(
281
- (isWeb ? willBeAnimated && isClient : true) && willBeAnimated
282
- )
283
-
284
- const initialState = needsMount
285
- ? supportsCSSVariables
274
+ const initialState = willBeAnimated
275
+ ? supportsCSSVars
286
276
  ? defaultComponentStateShouldEnter!
287
277
  : defaultComponentState!
288
278
  : defaultComponentStateMounted!
279
+
289
280
  const states = useState<TamaguiComponentState>(initialState)
290
281
 
291
282
  const state = propsIn.forceStyle
292
283
  ? { ...states[0], [propsIn.forceStyle]: true }
293
284
  : states[0]
294
285
  const setState = states[1]
286
+
287
+ // TODO performance optimization could avoid useCallback and just have this be setStateShallow(setState, state) at call-sites
295
288
  const setStateShallow = useShallowSetState(setState, debugProp, componentName)
296
289
 
290
+ // if (shouldTime) time`use-state`
291
+
297
292
  let isAnimated = willBeAnimated
298
293
 
299
- if (willBeAnimated && !supportsCSSVariables) {
300
- // cheat code to not always pay the cost of triple rendering,
301
- // after a bit we consider this component hydrated
302
- let hasHydrated = false
303
- numRenderedOfType[componentName] ??= 0
304
- if (willBeAnimated) {
305
- if (++numRenderedOfType[componentName] > HYDRATION_CUTOFF) {
306
- hasHydrated = true
307
- }
308
- }
309
- const hasPresenceIsHydrated = presence && hasHydrated
310
- if (!hasPresenceIsHydrated) {
311
- if (isAnimated && (isServer || state.unmounted === true)) {
294
+ if (willBeAnimated && !supportsCSSVars) {
295
+ if (!presence && isHydrated) {
296
+ if (isServer || state.unmounted === true) {
312
297
  isAnimated = false
313
298
  }
314
299
  }
315
300
  }
316
301
 
302
+ // once animated, always animated to preserve hooks
303
+ if (willBeAnimated && !stateRef.current.hasAnimated) {
304
+ stateRef.current.hasAnimated = true
305
+ }
306
+
317
307
  const componentClassName = props.asChild
318
308
  ? ''
319
309
  : props.componentName
@@ -323,6 +313,8 @@ export function createComponent<
323
313
  const languageContext = useContext(FontLanguageContext)
324
314
  const isDisabled = props.disabled ?? props.accessibilityState?.disabled
325
315
 
316
+ // if (shouldTime) time`use-context`
317
+
326
318
  const isTaggable = !Component || typeof Component === 'string'
327
319
  // default to tag, fallback to component (when both strings)
328
320
  const element = isWeb ? (isTaggable ? props.tag || Component : Component) : Component
@@ -367,6 +359,8 @@ export function createComponent<
367
359
  const disableThemeProp = props['data-disable-theme']
368
360
  const disableTheme = (disableThemeProp && !willBeAnimated) || isHOC
369
361
 
362
+ // if (shouldTime) time`theme-props`
363
+
370
364
  const themeStateProps = {
371
365
  name: props.theme,
372
366
  componentName,
@@ -406,17 +400,21 @@ export function createComponent<
406
400
  )
407
401
  // prettier-ignore
408
402
  // rome-ignore lint/nursery/noConsoleLog: <explanation>
409
- console.log({ props, state, staticConfig, elementType, themeStateProps, styledContext: { contextProps: styledContextProps, overriddenContextProps }, presence, isAnimated, isHOC, hasAnimationProp, useAnimations, propsInOrder: Object.keys(propsIn), propsOrder: Object.keys(props), curDefaultPropsOrder: Object.keys(curDefaultProps) })
403
+ console.log({ props, state, staticConfig, elementType, themeStateProps, styledContext: { contextProps: styledContextProps, overriddenContextProps }, presence, isAnimated, isHOC, hasAnimationProp, useAnimations, propsInOrder: Object.keys(propsIn), propsOrder: Object.keys(props) })
410
404
  console.groupEnd()
411
405
  }
412
406
  }
413
407
  }
414
408
 
415
- const themeState = useThemeWithState(themeStateProps)!
409
+ // if (shouldTime) time`pre-theme-media`
410
+
411
+ const [themeState, theme] = useThemeWithState(themeStateProps)
416
412
 
417
413
  elementType = Component || elementType
418
414
  const isStringElement = typeof elementType === 'string'
419
415
 
416
+ // if (shouldTime) time`theme`
417
+
420
418
  const mediaState = useMedia(
421
419
  // @ts-ignore, we just pass a stable object so we can get it later with
422
420
  // should match to the one used in `setMediaShouldUpdate` below
@@ -424,6 +422,8 @@ export function createComponent<
424
422
  debugProp ? { props, staticConfig } : null
425
423
  )
426
424
 
425
+ // if (shouldTime) time`media`
426
+
427
427
  setDidGetVariableValue(false)
428
428
 
429
429
  const resolveVariablesAs =
@@ -435,26 +435,31 @@ export function createComponent<
435
435
  // temp: once we fix above we can disable this
436
436
  const keepStyleSSR = willBeAnimated && animationsConfig?.keepStyleSSR
437
437
 
438
+ const styleProps = {
439
+ mediaState,
440
+ noClassNames,
441
+ hasTextAncestor,
442
+ resolveVariablesAs,
443
+ isExiting,
444
+ isAnimated,
445
+ keepStyleSSR,
446
+ } as const
447
+
438
448
  const splitStyles = useSplitStyles(
439
449
  props,
440
450
  staticConfig,
441
- themeState,
442
- {
443
- ...state,
444
- mediaState,
445
- noClassNames,
446
- hasTextAncestor,
447
- resolveVariablesAs,
448
- isExiting,
449
- isAnimated,
450
- keepStyleSSR,
451
- },
451
+ theme,
452
+ themeState.state.name,
453
+ state,
454
+ styleProps,
452
455
  null,
453
456
  languageContext || undefined,
454
457
  elementType,
455
458
  debugProp
456
459
  )
457
460
 
461
+ // if (shouldTime) time`split-styles`
462
+
458
463
  stateRef.current.isListeningToTheme = splitStyles.dynamicThemeAccess
459
464
 
460
465
  // only listen for changes if we are using raw theme values or media space, or dynamic media (native)
@@ -524,21 +529,17 @@ export function createComponent<
524
529
  style: splitStylesStyle,
525
530
  // style: splitStylesStyle,
526
531
  presence,
527
- state: {
528
- ...state,
529
- isAnimated,
530
- },
531
- theme: themeState.theme,
532
+ componentState: state,
533
+ styleProps,
534
+ theme: themeState.state.theme!,
532
535
  pseudos: pseudos || null,
533
536
  onDidAnimate: props.onDidAnimate,
534
537
  hostRef,
535
538
  staticConfig,
536
539
  })
537
540
 
538
- if (isAnimated) {
539
- if (animations) {
540
- animationStyles = animations.style
541
- }
541
+ if (isAnimated && animations) {
542
+ animationStyles = animations.style
542
543
  }
543
544
  }
544
545
 
@@ -570,6 +571,8 @@ export function createComponent<
570
571
  ...nonTamaguiProps
571
572
  } = viewPropsIn
572
573
 
574
+ // if (shouldTime) time`destructure`
575
+
573
576
  const disabled = props.accessibilityState?.disabled || props.accessibilityDisabled
574
577
 
575
578
  // these can ultimately be for DOM, react-native-web views, or animated views
@@ -595,7 +598,7 @@ export function createComponent<
595
598
  viewProps.ref = useComposedRefs(hostRef as any, forwardedRef)
596
599
 
597
600
  if (process.env.NODE_ENV === 'development') {
598
- if (!isText && isWeb && !isHOC) {
601
+ if (!isReactNative && !isText && isWeb && !isHOC) {
599
602
  Children.toArray(props.children).forEach((item) => {
600
603
  // allow newlines because why not its annoying with mdx
601
604
  if (typeof item === 'string' && item !== '\n') {
@@ -607,74 +610,59 @@ export function createComponent<
607
610
  }
608
611
  }
609
612
 
613
+ // if (shouldTime) time`events-hooks`
614
+
610
615
  const unPress = useCallback(() => {
611
616
  setStateShallow({
612
617
  press: false,
613
618
  pressIn: false,
614
619
  })
615
- }, [setStateShallow])
620
+ }, [])
616
621
 
617
622
  const shouldSetMounted = needsMount && state.unmounted
618
623
 
619
- // combined two effects into one for performance so be careful with logic
620
- // because no need for mouseUp removal effect if its not even mounted yet
624
+ // combined multiple effects into one for performance so be careful with logic
621
625
  useIsomorphicLayoutEffect(() => {
622
- if (!shouldSetMounted) {
623
- return () => {
624
- mouseUps.delete(unPress)
625
- }
626
+ if (shouldSetMounted) {
627
+ const unmounted =
628
+ state.unmounted === true && hasEnterStyle ? 'should-enter' : false
629
+ setStateShallow({
630
+ unmounted,
631
+ })
632
+ return
633
+ // no need for mouseUp removal effect if its not even mounted yet
626
634
  }
627
635
 
628
- const unmounted = state.unmounted === true && hasEnterStyle ? 'should-enter' : false
629
- setStateShallow({
630
- unmounted,
631
- })
636
+ return () => {
637
+ mouseUps.delete(unPress)
638
+ }
632
639
  }, [shouldSetMounted, state.unmounted])
633
640
 
634
- let styles: Record<string, any>[] | undefined
635
- const avoidStyle = keepStyleSSR && state.unmounted === true
636
-
637
- if (!avoidStyle) {
638
- if (isStringElement && shouldAvoidClasses && !shouldForcePseudo) {
639
- styles = {
640
- ...(animationStyles ?? splitStylesStyle),
641
- }
642
- } else {
643
- styles = [animationStyles ?? splitStylesStyle]
644
-
645
- // ugly but for now...
646
- if (shouldForcePseudo) {
647
- const next = {}
648
- styles.forEach((style) => Object.assign(next, style))
649
- // @ts-ignore
650
- Object.assign(splitStyles.style, next)
651
- }
652
- }
653
- }
641
+ const avoidAnimationStyle = keepStyleSSR && state.unmounted === true
654
642
 
655
643
  let fontFamily = isText
656
- ? splitStyles.fontFamily || staticConfig.defaultProps.fontFamily
644
+ ? splitStyles.fontFamily || staticConfig.defaultProps?.fontFamily
657
645
  : null
658
646
  if (fontFamily && fontFamily[0] === '$') {
659
647
  fontFamily = fontFamily.slice(1)
660
648
  }
661
649
  const fontFamilyClassName = fontFamily ? `font_${fontFamily}` : ''
662
650
 
663
- const classList = [
664
- hasEnterStyle && ((state.unmounted && needsMount) || !isClient)
665
- ? 't_will-mount'
666
- : '',
667
- componentName ? componentClassName : '',
668
- fontFamilyClassName,
669
- classNames ? Object.values(classNames).join(' ') : '',
670
- ]
651
+ const style = avoidAnimationStyle
652
+ ? splitStyles.style
653
+ : animationStyles || splitStyles.style
671
654
 
672
- const className = classList.join(' ')
655
+ let className: string | undefined
673
656
 
674
657
  if (process.env.TAMAGUI_TARGET === 'web') {
675
- const style = avoidStyle ? null : animationStyles ?? splitStyles.style
676
-
677
- if (isAnimatedReactNativeWeb && !avoidStyle) {
658
+ const classList = [
659
+ componentName ? componentClassName : '',
660
+ fontFamilyClassName,
661
+ classNames ? Object.values(classNames).join(' ') : '',
662
+ ]
663
+ className = classList.join(' ')
664
+
665
+ if (isAnimatedReactNativeWeb && !avoidAnimationStyle) {
678
666
  viewProps.style = style
679
667
  } else if (isReactNative) {
680
668
  // TODO these shouldn't really return from getSplitStyles when in Native mode
@@ -683,9 +671,14 @@ export function createComponent<
683
671
  cnStyles[name] = name
684
672
  }
685
673
  viewProps.style = [...(Array.isArray(style) ? style : [style]), cnStyles]
674
+ } else {
675
+ viewProps.className = className
676
+ viewProps.style = style
677
+ }
686
678
 
679
+ // turn debug data- props into dataSet in dev mode
680
+ if (isReactNative) {
687
681
  if (process.env.NODE_ENV === 'development') {
688
- // turn debug data- props into dataSet in dev mode
689
682
  Object.keys(viewProps).forEach((key) => {
690
683
  if (key.startsWith('data-')) {
691
684
  viewProps.dataSet ??= {}
@@ -694,13 +687,10 @@ export function createComponent<
694
687
  }
695
688
  })
696
689
  }
697
- } else {
698
- viewProps.className = className
699
- viewProps.style = style
700
690
  }
701
691
  } else {
702
692
  // native assign styles
703
- viewProps.style = styles
693
+ viewProps.style = style
704
694
  }
705
695
 
706
696
  const runtimePressStyle = !disabled && noClassNames && pseudos?.pressStyle
@@ -723,6 +713,8 @@ export function createComponent<
723
713
  (isWeb && noClassNames && 'hoverStyle' in props)
724
714
  )
725
715
 
716
+ // if (shouldTime) time`events-setup`
717
+
726
718
  const events: TamaguiComponentEvents | null =
727
719
  shouldAttach && !isDisabled && !asChild
728
720
  ? {
@@ -789,22 +781,22 @@ export function createComponent<
789
781
  }
790
782
  : null
791
783
 
792
- if (process.env.TAMAGUI_TARGET === 'native') {
793
- if (events) {
794
- // replicating TouchableWithoutFeedback
795
- Object.assign(events, {
796
- cancelable: !props.rejectResponderTermination,
797
- disabled: isDisabled,
798
- hitSlop: props.hitSlop,
799
- delayLongPress: props.delayLongPress,
800
- delayPressIn: props.delayPressIn,
801
- delayPressOut: props.delayPressOut,
802
- focusable: viewProps.focusable ?? true,
803
- minPressDuration: 0,
804
- })
805
- }
784
+ if (process.env.TAMAGUI_TARGET === 'native' && events) {
785
+ // replicating TouchableWithoutFeedback
786
+ Object.assign(events, {
787
+ cancelable: !viewProps.rejectResponderTermination,
788
+ disabled: isDisabled,
789
+ hitSlop: viewProps.hitSlop,
790
+ delayLongPress: viewProps.delayLongPress,
791
+ delayPressIn: viewProps.delayPressIn,
792
+ delayPressOut: viewProps.delayPressOut,
793
+ focusable: viewProps.focusable ?? true,
794
+ minPressDuration: 0,
795
+ })
806
796
  }
807
797
 
798
+ // if (shouldTime) time`events`
799
+
808
800
  if (process.env.NODE_ENV === 'development' && debugProp === 'verbose') {
809
801
  // rome-ignore lint/nursery/noConsoleLog: <explanation>
810
802
  console.log(`events`, { events, isHoverable, attachPress })
@@ -820,6 +812,8 @@ export function createComponent<
820
812
 
821
813
  const direction = props.spaceDirection || 'both'
822
814
 
815
+ // if (shouldTime) time`hooks`
816
+
823
817
  // since we re-render without changing children often for animations or on mount
824
818
  // we memo children here. tested this on the site homepage which has hundreds of components
825
819
  // and i see no difference in startup performance, but i do see it memoing often
@@ -837,13 +831,12 @@ export function createComponent<
837
831
 
838
832
  if (asChild) {
839
833
  elementType = Slot
840
- viewProps = {
841
- ...viewProps,
834
+ Object.assign(viewProps, {
842
835
  onPress,
843
836
  onLongPress,
844
837
  onPressIn,
845
838
  onPressOut,
846
- }
839
+ })
847
840
  }
848
841
 
849
842
  content = createElement(elementType, viewProps, content)
@@ -856,14 +849,12 @@ export function createComponent<
856
849
  // passPropsToChildren: true,
857
850
  })
858
851
 
859
- if (process.env.NODE_ENV === 'development') {
860
- if (props['debug'] === 'visualize') {
861
- content = (
862
- <ThemeDebug themeState={themeState} themeProps={props}>
863
- {content}
864
- </ThemeDebug>
865
- )
866
- }
852
+ if (process.env.NODE_ENV === 'development' && props['debug'] === 'visualize') {
853
+ content = (
854
+ <ThemeDebug themeState={themeState} themeProps={props}>
855
+ {content}
856
+ </ThemeDebug>
857
+ )
867
858
  }
868
859
 
869
860
  if (process.env.TAMAGUI_TARGET === 'web') {
@@ -895,7 +886,11 @@ export function createComponent<
895
886
  if (process.env.NODE_ENV === 'development') {
896
887
  if (debugProp) {
897
888
  const element = typeof elementType === 'string' ? elementType : 'Component'
898
- console.groupCollapsed(`render <${element} /> with props`)
889
+ console.groupCollapsed(
890
+ `render <${element} /> with props`,
891
+ initialState,
892
+ willBeAnimated
893
+ )
899
894
  // rome-ignore lint/nursery/noConsoleLog: <explanation>
900
895
  console.log('viewProps', viewProps)
901
896
  // rome-ignore lint/nursery/noConsoleLog: <explanation>
@@ -909,16 +904,28 @@ export function createComponent<
909
904
  if (typeof window !== 'undefined') {
910
905
  // prettier-ignore
911
906
  // rome-ignore lint/nursery/noConsoleLog: <explanation>
912
- console.log({ state, themeState, isAnimated, isAnimatedReactNativeWeb, defaultProps, viewProps, splitStyles, animationStyles, handlesPressEvents, isStringElement, classNamesIn: props.className?.split(' '), classNamesOut: viewProps.className?.split(' '), events, shouldAttach, styles, pseudos, content, shouldAvoidClasses, avoidClasses: avoidClassesWhileAnimating, animation: props.animation, style: splitStylesStyle, staticConfig, tamaguiConfig, shouldForcePseudo })
907
+ console.log({ state, themeState, isAnimated, isAnimatedReactNativeWeb, defaultProps, viewProps, splitStyles, animationStyles, handlesPressEvents, isStringElement, classNamesIn: props.className?.split(' '), classNamesOut: viewProps.className?.split(' '), events, shouldAttach, pseudos, content, shouldAvoidClasses, avoidClasses: avoidClassesWhileAnimating, animation: props.animation, style: splitStylesStyle, staticConfig, tamaguiConfig, shouldForcePseudo, elementType, initialState })
913
908
  }
914
909
  console.groupEnd()
915
910
  console.groupEnd()
916
911
  }
917
912
  }
918
913
 
914
+ // if (shouldTime) {
915
+ // time`rest`
916
+ // setTimeout(() => {
917
+ // if (!hasLogged) {
918
+ // timer.print()
919
+ // }
920
+ // hasLogged = true
921
+ // }, 1000)
922
+ // }
923
+
919
924
  return content
920
925
  })
921
926
 
927
+ // let hasLogged = false
928
+
922
929
  if (staticConfig.componentName) {
923
930
  component.displayName = staticConfig.componentName
924
931
  }
@@ -967,7 +974,9 @@ export function createComponent<
967
974
  }
968
975
 
969
976
  // for elements to avoid spacing
970
- export const Unspaced = (props: { children?: any }) => props.children
977
+ export function Unspaced(props: { children?: any }) {
978
+ return props.children
979
+ }
971
980
  Unspaced['isUnspaced'] = true
972
981
 
973
982
  // dont used styled() here to avoid circular deps
@@ -251,7 +251,6 @@ export function createTamagui<Conf extends CreateTamaguiProps>(
251
251
  }
252
252
 
253
253
  const designSystem = `._ovs-contain {overscroll-behavior:contain;}
254
- .t_unmounted .t_will-mount {opacity:0;visibility:hidden;}
255
254
  .is_Text .is_Text {display:inline-flex;}
256
255
  ._dsp_contents {display:contents;}
257
256
  ${themeConfig.cssRuleSets.join(separator)}`
@@ -28,7 +28,7 @@ export type ThemeManagerState = {
28
28
  const emptyState: ThemeManagerState = { name: '' }
29
29
 
30
30
  export function getHasThemeUpdatingProps(props: ThemeProps) {
31
- return props.name || props.componentName || props.inverse || props.reset
31
+ return Boolean(props.name || props.componentName || props.inverse || props.reset)
32
32
  }
33
33
 
34
34
  let uid = 0
@@ -139,10 +139,10 @@ export class ThemeManager {
139
139
  }
140
140
 
141
141
  getState(props = this.props, parentManager = this.parentManager) {
142
- return (
142
+ const next =
143
143
  getState(props, parentManager) ||
144
144
  (process.env.TAMAGUI_TARGET === 'native' ? parentManager?.state || null : null)
145
- )
145
+ return next
146
146
  }
147
147
 
148
148
  _allKeys: Set<string> | null = null
@@ -155,9 +155,9 @@ export class ThemeManager {
155
155
  }
156
156
 
157
157
  // gets value going up to parents
158
- getValue(key: string, state?: ThemeManagerState) {
158
+ getValue(key: string, state: ThemeManagerState = this.state) {
159
159
  if (!key) return
160
- let theme = (state || this.state).theme
160
+ let theme = state.theme
161
161
  let manager = this as ThemeManager | null
162
162
  while (theme && manager) {
163
163
  if (key in theme) {
@@ -334,7 +334,11 @@ function getState(
334
334
  }
335
335
  }
336
336
 
337
- if (process.env.NODE_ENV === 'development' && typeof props.debug === 'string') {
337
+ if (
338
+ process.env.NODE_ENV === 'development' &&
339
+ typeof props.debug === 'string' &&
340
+ typeof window !== 'undefined'
341
+ ) {
338
342
  console.warn('ThemeManager.getState():', {
339
343
  result,
340
344
  })