@tamagui/web 1.129.18 → 1.130.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 (99) hide show
  1. package/dist/cjs/createComponent.cjs +65 -46
  2. package/dist/cjs/createComponent.js +51 -33
  3. package/dist/cjs/createComponent.js.map +1 -1
  4. package/dist/cjs/createComponent.native.js +49 -30
  5. package/dist/cjs/createComponent.native.js.map +2 -2
  6. package/dist/cjs/helpers/getSplitStyles.cjs +8 -3
  7. package/dist/cjs/helpers/getSplitStyles.js +9 -3
  8. package/dist/cjs/helpers/getSplitStyles.js.map +1 -1
  9. package/dist/cjs/helpers/getSplitStyles.native.js +5 -1
  10. package/dist/cjs/helpers/getSplitStyles.native.js.map +2 -2
  11. package/dist/cjs/helpers/mergeProps.cjs +13 -9
  12. package/dist/cjs/helpers/mergeProps.js +17 -9
  13. package/dist/cjs/helpers/mergeProps.js.map +1 -1
  14. package/dist/cjs/helpers/mergeProps.native.js +20 -9
  15. package/dist/cjs/helpers/mergeProps.native.js.map +2 -2
  16. package/dist/cjs/hooks/useComponentState.cjs +1 -1
  17. package/dist/cjs/hooks/useComponentState.js +1 -1
  18. package/dist/cjs/hooks/useComponentState.js.map +1 -1
  19. package/dist/cjs/hooks/useComponentState.native.js +1 -1
  20. package/dist/cjs/hooks/useComponentState.native.js.map +2 -2
  21. package/dist/cjs/hooks/useProps.cjs +2 -2
  22. package/dist/cjs/hooks/useProps.js +7 -2
  23. package/dist/cjs/hooks/useProps.js.map +1 -1
  24. package/dist/cjs/hooks/useProps.native.js +3 -3
  25. package/dist/cjs/hooks/useProps.native.js.map +1 -1
  26. package/dist/cjs/hooks/useThemeState.cjs +2 -1
  27. package/dist/cjs/hooks/useThemeState.js +3 -1
  28. package/dist/cjs/hooks/useThemeState.js.map +1 -1
  29. package/dist/cjs/hooks/useThemeState.native.js +6 -1
  30. package/dist/cjs/hooks/useThemeState.native.js.map +2 -2
  31. package/dist/cjs/views/Theme.cjs +10 -7
  32. package/dist/cjs/views/Theme.js +21 -7
  33. package/dist/cjs/views/Theme.js.map +1 -1
  34. package/dist/cjs/views/Theme.native.js +7 -7
  35. package/dist/cjs/views/Theme.native.js.map +2 -2
  36. package/dist/esm/createComponent.js +51 -33
  37. package/dist/esm/createComponent.js.map +1 -1
  38. package/dist/esm/createComponent.mjs +65 -46
  39. package/dist/esm/createComponent.mjs.map +1 -1
  40. package/dist/esm/createComponent.native.js +63 -42
  41. package/dist/esm/createComponent.native.js.map +1 -1
  42. package/dist/esm/helpers/getSplitStyles.js +9 -3
  43. package/dist/esm/helpers/getSplitStyles.js.map +1 -1
  44. package/dist/esm/helpers/getSplitStyles.mjs +8 -3
  45. package/dist/esm/helpers/getSplitStyles.mjs.map +1 -1
  46. package/dist/esm/helpers/getSplitStyles.native.js +3 -1
  47. package/dist/esm/helpers/getSplitStyles.native.js.map +1 -1
  48. package/dist/esm/helpers/mergeProps.js +17 -9
  49. package/dist/esm/helpers/mergeProps.js.map +1 -1
  50. package/dist/esm/helpers/mergeProps.mjs +13 -9
  51. package/dist/esm/helpers/mergeProps.mjs.map +1 -1
  52. package/dist/esm/helpers/mergeProps.native.js +18 -9
  53. package/dist/esm/helpers/mergeProps.native.js.map +1 -1
  54. package/dist/esm/hooks/useComponentState.js +1 -1
  55. package/dist/esm/hooks/useComponentState.js.map +1 -1
  56. package/dist/esm/hooks/useComponentState.mjs +1 -1
  57. package/dist/esm/hooks/useComponentState.mjs.map +1 -1
  58. package/dist/esm/hooks/useComponentState.native.js +1 -1
  59. package/dist/esm/hooks/useProps.js +7 -2
  60. package/dist/esm/hooks/useProps.js.map +1 -1
  61. package/dist/esm/hooks/useProps.mjs +2 -2
  62. package/dist/esm/hooks/useProps.mjs.map +1 -1
  63. package/dist/esm/hooks/useProps.native.js +2 -2
  64. package/dist/esm/hooks/useProps.native.js.map +1 -1
  65. package/dist/esm/hooks/useThemeState.js +3 -1
  66. package/dist/esm/hooks/useThemeState.js.map +1 -1
  67. package/dist/esm/hooks/useThemeState.mjs +2 -1
  68. package/dist/esm/hooks/useThemeState.mjs.map +1 -1
  69. package/dist/esm/hooks/useThemeState.native.js +2 -1
  70. package/dist/esm/hooks/useThemeState.native.js.map +1 -1
  71. package/dist/esm/views/Theme.js +21 -7
  72. package/dist/esm/views/Theme.js.map +1 -1
  73. package/dist/esm/views/Theme.mjs +10 -7
  74. package/dist/esm/views/Theme.mjs.map +1 -1
  75. package/dist/esm/views/Theme.native.js +10 -6
  76. package/dist/esm/views/Theme.native.js.map +1 -1
  77. package/package.json +12 -12
  78. package/src/createComponent.tsx +181 -137
  79. package/src/helpers/getSplitStyles.tsx +16 -3
  80. package/src/helpers/mergeProps.ts +53 -4
  81. package/src/hooks/useComponentState.ts +1 -0
  82. package/src/hooks/useProps.tsx +7 -2
  83. package/src/hooks/useThemeState.ts +7 -2
  84. package/src/setupHooks.ts +1 -1
  85. package/src/types.tsx +16 -2
  86. package/src/views/Theme.tsx +40 -21
  87. package/types/createComponent.d.ts.map +1 -1
  88. package/types/helpers/getSplitStyles.d.ts +1 -1
  89. package/types/helpers/getSplitStyles.d.ts.map +1 -1
  90. package/types/helpers/mergeProps.d.ts +19 -0
  91. package/types/helpers/mergeProps.d.ts.map +1 -1
  92. package/types/hooks/useProps.d.ts.map +1 -1
  93. package/types/hooks/useThemeState.d.ts.map +1 -1
  94. package/types/setupHooks.d.ts +1 -1
  95. package/types/setupHooks.d.ts.map +1 -1
  96. package/types/types.d.ts +13 -4
  97. package/types/types.d.ts.map +1 -1
  98. package/types/views/Theme.d.ts +4 -2
  99. package/types/views/Theme.d.ts.map +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tamagui/web",
3
- "version": "1.129.18",
3
+ "version": "1.130.0",
4
4
  "source": "src/index.ts",
5
5
  "main": "dist/cjs",
6
6
  "module": "dist/esm",
@@ -27,16 +27,16 @@
27
27
  "reset.css"
28
28
  ],
29
29
  "dependencies": {
30
- "@tamagui/compose-refs": "1.129.18",
31
- "@tamagui/constants": "1.129.18",
32
- "@tamagui/helpers": "1.129.18",
33
- "@tamagui/is-equal-shallow": "1.129.18",
34
- "@tamagui/normalize-css-color": "1.129.18",
35
- "@tamagui/timer": "1.129.18",
36
- "@tamagui/types": "1.129.18",
37
- "@tamagui/use-did-finish-ssr": "1.129.18",
38
- "@tamagui/use-event": "1.129.18",
39
- "@tamagui/use-force-update": "1.129.18"
30
+ "@tamagui/compose-refs": "1.130.0",
31
+ "@tamagui/constants": "1.130.0",
32
+ "@tamagui/helpers": "1.130.0",
33
+ "@tamagui/is-equal-shallow": "1.130.0",
34
+ "@tamagui/normalize-css-color": "1.130.0",
35
+ "@tamagui/timer": "1.130.0",
36
+ "@tamagui/types": "1.130.0",
37
+ "@tamagui/use-did-finish-ssr": "1.130.0",
38
+ "@tamagui/use-event": "1.130.0",
39
+ "@tamagui/use-force-update": "1.130.0"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "react": "*",
@@ -44,7 +44,7 @@
44
44
  "react-native": "*"
45
45
  },
46
46
  "devDependencies": {
47
- "@tamagui/build": "1.129.18",
47
+ "@tamagui/build": "1.130.0",
48
48
  "@testing-library/react": "^16.1.0",
49
49
  "csstype": "^3.0.10",
50
50
  "react": "*",
@@ -9,7 +9,7 @@ import {
9
9
  } from '@tamagui/constants'
10
10
  import { composeEventHandlers, validStyles } from '@tamagui/helpers'
11
11
  import { isEqualShallow } from '@tamagui/is-equal-shallow'
12
- import React, { type RefObject, useEffect, useId, useMemo } from 'react'
12
+ import React, { useMemo } from 'react'
13
13
  import { devConfig, onConfiguredOnce } from './config'
14
14
  import { stackDefaultStyles } from './constants/constants'
15
15
  import { isDevTools } from './constants/isDevTools'
@@ -33,13 +33,13 @@ import type { TamaguiComponentState } from './interfaces/TamaguiComponentState'
33
33
  import type { WebOnlyPressEvents } from './interfaces/WebOnlyPressEvents'
34
34
  import { hooks } from './setupHooks'
35
35
  import type {
36
+ AllGroupContexts,
36
37
  ComponentGroupEmitter,
37
- ComponentGroupState,
38
38
  DebugProp,
39
- AllGroupContexts,
40
39
  GroupStateListener,
41
40
  LayoutEvent,
42
41
  PseudoGroupState,
42
+ SingleGroupContext,
43
43
  SizeTokens,
44
44
  SpaceDirection,
45
45
  SpacerProps,
@@ -50,7 +50,6 @@ import type {
50
50
  StaticConfig,
51
51
  StyleableOptions,
52
52
  TamaguiComponent,
53
- TamaguiComponentStateRef,
54
53
  TamaguiElement,
55
54
  TamaguiInternalConfig,
56
55
  TextProps,
@@ -58,7 +57,6 @@ import type {
58
57
  UseAnimationProps,
59
58
  UseStyleEmitter,
60
59
  UseThemeWithStateProps,
61
- SingleGroupContext,
62
60
  } from './types'
63
61
  import { Slot } from './views/Slot'
64
62
  import { getThemedChildren } from './views/Theme'
@@ -317,20 +315,34 @@ export function createComponent<
317
315
 
318
316
  if (process.env.NODE_ENV === 'development' && isClient) {
319
317
  React.useEffect(() => {
318
+ let node: HTMLElement | undefined
320
319
  let overlay: HTMLSpanElement | null = null
321
320
 
321
+ const remove = () => {
322
+ if (overlay) {
323
+ try {
324
+ overlay.parentNode?.removeChild(overlay)
325
+ overlay = null
326
+ } catch {
327
+ // may have unmounted
328
+ }
329
+ }
330
+ }
331
+
322
332
  const debugVisualizerHandler = (show = false) => {
323
- const node = stateRef.current.host as HTMLElement
333
+ node = stateRef.current.host as HTMLElement | undefined
324
334
  if (!node) return
325
335
 
326
336
  if (show) {
327
- overlay = document.createElement('span')
328
- overlay.style.inset = '0px'
329
- overlay.style.zIndex = '1000000'
330
- overlay.style.position = 'absolute'
331
- overlay.style.borderColor = 'red'
332
- overlay.style.borderWidth = '1px'
333
- overlay.style.borderStyle = 'dotted'
337
+ if (!overlay) {
338
+ overlay = document.createElement('span')
339
+ overlay.style.inset = '0px'
340
+ overlay.style.zIndex = '1000000'
341
+ overlay.style.position = 'absolute'
342
+ overlay.style.borderColor = 'red'
343
+ overlay.style.borderWidth = '1px'
344
+ overlay.style.borderStyle = 'dotted'
345
+ }
334
346
 
335
347
  const dataAt = node.getAttribute('data-at') || ''
336
348
  const dataIn = node.getAttribute('data-in') || ''
@@ -345,20 +357,18 @@ export function createComponent<
345
357
  tooltip.style.fontSize = '12px'
346
358
  tooltip.style.lineHeight = '12px'
347
359
  tooltip.style.fontFamily = 'monospace'
348
- tooltip.style['webkitFontSmoothing'] = 'none'
349
360
  tooltip.innerText = `${componentName || ''} ${dataAt} ${dataIn}`.trim()
350
361
 
351
362
  overlay.appendChild(tooltip)
352
363
  node.appendChild(overlay)
353
364
  } else {
354
- if (overlay) {
355
- node.removeChild(overlay)
356
- }
365
+ remove()
357
366
  }
358
367
  }
359
368
  debugKeyListeners ||= new Set()
360
369
  debugKeyListeners.add(debugVisualizerHandler)
361
370
  return () => {
371
+ remove()
362
372
  debugKeyListeners?.delete(debugVisualizerHandler)
363
373
  }
364
374
  }, [componentName])
@@ -408,7 +418,7 @@ export function createComponent<
408
418
 
409
419
  // create new context with groups, or else sublings will grab the same one
410
420
  const allGroupContexts = useMemo((): AllGroupContexts | null => {
411
- if (!groupName) {
421
+ if (!groupName || props.passThrough) {
412
422
  return groupContextParent
413
423
  }
414
424
 
@@ -622,11 +632,13 @@ export function createComponent<
622
632
  debugProp
623
633
  )
624
634
 
635
+ // splitStyles === null === passThrough
636
+
625
637
  const groupContext = groupName ? allGroupContexts?.[groupName] || null : null
626
638
 
627
639
  // one tiny mutation 🙏 get width/height optimistically from raw values if possible
628
640
  // if set hardcoded it avoids extra renders
629
- if (groupContext) {
641
+ if (splitStyles && groupContext) {
630
642
  const groupState = groupContext?.state
631
643
  if (groupState && groupState.layout === undefined) {
632
644
  if (splitStyles.style?.width || splitStyles.style?.height) {
@@ -640,116 +652,124 @@ export function createComponent<
640
652
 
641
653
  // avoids re-rendering if animation driver supports it
642
654
  // TODO believe we need to set some sort of "pendingState" in case it re-renders
643
- if ((hasAnimationProp || groupName) && animationDriver?.avoidReRenders) {
644
- const styleListener = stateRef.current.useStyleListener
645
- const ogSetStateShallow = setStateShallow
655
+ if (splitStyles) {
656
+ if ((!hasAnimationProp || groupName) && animationDriver?.avoidReRenders) {
657
+ const useStyleListener = stateRef.current.useStyleListener
658
+ const ogSetStateShallow = setStateShallow
646
659
 
647
- stateRef.current.setStateShallow = (nextOrGetNext) => {
648
- const prev = NextState.get(stateRef) || state
649
- const next =
650
- typeof nextOrGetNext === 'function' ? nextOrGetNext(prev) : nextOrGetNext
660
+ stateRef.current.setStateShallow = (nextOrGetNext) => {
661
+ const prev = NextState.get(stateRef) || state
662
+ const next =
663
+ typeof nextOrGetNext === 'function' ? nextOrGetNext(prev) : nextOrGetNext
651
664
 
652
- if (next === prev || isEqualShallow(prev, next)) {
653
- return
654
- }
665
+ if (next === prev || isEqualShallow(prev, next)) {
666
+ return
667
+ }
655
668
 
656
- // one thing we have to handle here and where it gets a bit more complex is group styles
657
- const canAvoidReRender = Object.keys(next).every((key) =>
658
- avoidReRenderKeys.has(key)
659
- )
669
+ // one thing we have to handle here and where it gets a bit more complex is group styles
670
+ const canAvoidReRender = Object.keys(next).every((key) =>
671
+ avoidReRenderKeys.has(key)
672
+ )
660
673
 
661
- if (canAvoidReRender) {
662
- const updatedState = {
663
- ...prev,
664
- ...next,
665
- }
666
- NextState.set(stateRef, updatedState)
667
-
668
- if (
669
- process.env.NODE_ENV === 'development' &&
670
- debugProp &&
671
- debugProp !== 'profile'
672
- ) {
673
- console.groupCollapsed(`[⚡️] avoid setState`, next, { updatedState, props })
674
- console.info(stateRef.current.host)
675
- console.groupEnd()
676
- }
674
+ if (canAvoidReRender) {
675
+ const updatedState = {
676
+ ...prev,
677
+ ...next,
678
+ }
679
+ NextState.set(stateRef, updatedState)
680
+
681
+ if (
682
+ process.env.NODE_ENV === 'development' &&
683
+ debugProp &&
684
+ debugProp !== 'profile'
685
+ ) {
686
+ console.groupCollapsed(`[⚡️] avoid setState`, next, { updatedState, props })
687
+ console.info(stateRef.current.host)
688
+ console.groupEnd()
689
+ }
677
690
 
678
- const {
679
- group,
680
- hasDynGroupChildren,
681
- unmounted,
682
- animation,
683
- ...childrenGroupState
684
- } = updatedState
685
-
686
- // update before getting styles
687
- if (groupContext) {
688
- notifyGroupSubscribers(
689
- groupContext,
690
- stateRef.current.group || null,
691
- childrenGroupState
692
- )
693
- }
691
+ const {
692
+ group,
693
+ hasDynGroupChildren,
694
+ unmounted,
695
+ animation,
696
+ ...childrenGroupState
697
+ } = updatedState
698
+
699
+ // update before getting styles
700
+ if (groupContext) {
701
+ notifyGroupSubscribers(
702
+ groupContext,
703
+ stateRef.current.group || null,
704
+ childrenGroupState
705
+ )
706
+ }
694
707
 
695
- // we just emit and return for group without animation ^
696
- if (!hasAnimationProp || !styleListener) {
697
- return
698
- }
708
+ // we just emit and return for group without animation ^
709
+ if (!hasAnimationProp || !useStyleListener) {
710
+ return
711
+ }
699
712
 
700
- const nextStyles = getSplitStyles(
701
- props,
702
- staticConfig,
703
- theme,
704
- themeName,
705
- updatedState,
706
- styleProps,
707
- null,
708
- componentContext,
709
- allGroupContexts,
710
- elementType,
711
- startedUnhydrated,
712
- debugProp
713
- )
713
+ const nextStyles = getSplitStyles(
714
+ props,
715
+ staticConfig,
716
+ theme,
717
+ themeName,
718
+ updatedState,
719
+ styleProps,
720
+ null,
721
+ componentContext,
722
+ allGroupContexts,
723
+ elementType,
724
+ startedUnhydrated,
725
+ debugProp
726
+ )
714
727
 
715
- styleListener(nextStyles.style as any)
716
- } else {
717
- if (
718
- process.env.NODE_ENV === 'development' &&
719
- debugProp &&
720
- debugProp !== 'profile'
721
- ) {
722
- console.info(`[🐌] re-render`, { canAvoidReRender, next })
728
+ useStyleListener((nextStyles?.style || {}) as any)
729
+ } else {
730
+ if (
731
+ process.env.NODE_ENV === 'development' &&
732
+ debugProp &&
733
+ debugProp !== 'profile'
734
+ ) {
735
+ console.info(`[🐌] re-render`, { canAvoidReRender, next })
736
+ }
737
+ ogSetStateShallow(next)
723
738
  }
724
- ogSetStateShallow(next)
725
739
  }
726
- }
727
740
 
728
- // needs to capture latest props (it's called from memoized `events`)
729
- setStateShallow = (state) => {
730
- stateRef.current.setStateShallow?.(state)
741
+ // needs to capture latest props (it's called from memoized `events`)
742
+ setStateShallow = (state) => {
743
+ stateRef.current.setStateShallow?.(state)
744
+ }
731
745
  }
732
746
  }
733
747
 
734
748
  if (process.env.NODE_ENV === 'development' && time) time`split-styles`
735
749
 
736
750
  // hide strategy will set this opacity = 0 until measured
737
- if (props.group && props.untilMeasured === 'hide' && !stateRef.current.hasMeasured) {
738
- splitStyles.style ||= {}
739
- splitStyles.style.opacity = 0
740
- }
751
+ if (splitStyles) {
752
+ if (
753
+ props.group &&
754
+ props.untilMeasured === 'hide' &&
755
+ !stateRef.current.hasMeasured
756
+ ) {
757
+ splitStyles.style ||= {}
758
+ splitStyles.style.opacity = 0
759
+ }
741
760
 
742
- if (splitStyles.dynamicThemeAccess != null) {
743
- stateRef.current.isListeningToTheme = splitStyles.dynamicThemeAccess
761
+ if (splitStyles.dynamicThemeAccess != null) {
762
+ stateRef.current.isListeningToTheme = splitStyles.dynamicThemeAccess
763
+ }
744
764
  }
745
765
 
746
766
  // only listen for changes if we are using raw theme values or media space, or dynamic media (native)
747
767
  // array = space media breakpoints
748
- const hasRuntimeMediaKeys = splitStyles.hasMedia && splitStyles.hasMedia !== true
768
+ const hasRuntimeMediaKeys = splitStyles?.hasMedia && splitStyles.hasMedia !== true
749
769
  const shouldListenForMedia =
750
770
  didGetVariableValue() ||
751
771
  hasRuntimeMediaKeys ||
752
- (noClass && splitStyles.hasMedia === true)
772
+ (noClass && splitStyles?.hasMedia === true)
753
773
 
754
774
  const mediaListeningKeys = hasRuntimeMediaKeys
755
775
  ? (splitStyles.hasMedia as Set<string>)
@@ -766,7 +786,9 @@ export function createComponent<
766
786
  style: splitStylesStyle,
767
787
  classNames,
768
788
  space,
769
- } = splitStyles
789
+ pseudoGroups,
790
+ mediaGroups,
791
+ } = splitStyles || {}
770
792
 
771
793
  const propsWithAnimation = props as UseAnimationProps
772
794
 
@@ -794,7 +816,7 @@ export function createComponent<
794
816
  onClick,
795
817
  theme: _themeProp,
796
818
  ...nonTamaguiProps
797
- } = viewPropsIn
819
+ } = viewPropsIn || {}
798
820
 
799
821
  // these can ultimately be for DOM, react-native-web views, or animated views
800
822
  // so the type is pretty loose
@@ -844,17 +866,19 @@ export function createComponent<
844
866
  stateRef,
845
867
  })
846
868
 
847
- if (isHydrated && animations) {
848
- animationStyles = animations.style
849
- viewProps.style = animationStyles
850
- if (animations.className) {
851
- viewProps.className = `${state.unmounted === 'should-enter' ? 't_unmounted ' : ''}${viewProps.className || ''} ${animations.className}`
852
- }
853
- // @ts-ignore
869
+ if (animations) {
854
870
  if (animations.ref) {
855
871
  // @ts-ignore
856
872
  animatedRef = animations.ref
857
873
  }
874
+
875
+ if (isHydrated && animations) {
876
+ animationStyles = animations.style
877
+ viewProps.style = animationStyles
878
+ if (animations.className) {
879
+ viewProps.className = `${state.unmounted === 'should-enter' ? 't_unmounted ' : ''}${viewProps.className || ''} ${animations.className}`
880
+ }
881
+ }
858
882
  }
859
883
 
860
884
  if (process.env.NODE_ENV === 'development' && time) time`animations`
@@ -868,7 +892,7 @@ export function createComponent<
868
892
 
869
893
  if (process.env.NODE_ENV === 'development' && time) time`destructure`
870
894
 
871
- if (groupContext) {
895
+ if (splitStyles && groupContext) {
872
896
  nonTamaguiProps.onLayout = composeEventHandlers(
873
897
  nonTamaguiProps.onLayout,
874
898
  (e: LayoutEvent) => {
@@ -923,12 +947,6 @@ export function createComponent<
923
947
 
924
948
  if (process.env.NODE_ENV === 'development' && time) time`events-hooks`
925
949
 
926
- // combined multiple effects into one for performance so be careful with logic
927
- // should not be a layout effect because otherwise it wont render the initial state
928
- // for example css driver needs to render once with the first styles, then again with the next
929
- // if its a layout effect it will just skip that first <render >output
930
- const { pseudoGroups, mediaGroups } = splitStyles
931
-
932
950
  const unPress = () => {
933
951
  setStateShallow({ press: false, pressIn: false })
934
952
  }
@@ -944,9 +962,11 @@ export function createComponent<
944
962
  }
945
963
  return styleObject
946
964
  }
947
- const computed = cssStyleDeclarationToObject(
948
- getComputedStyle(stateRef.current.host! as Element)
949
- )
965
+ const computed = stateRef.current.host
966
+ ? cssStyleDeclarationToObject(
967
+ getComputedStyle(stateRef.current.host as Element)
968
+ )
969
+ : {}
950
970
  console.groupCollapsed(`Rendered > (opacity: ${computed.opacity})`)
951
971
  console.warn(stateRef.current.host)
952
972
  console.warn(computed)
@@ -1214,7 +1234,7 @@ export function createComponent<
1214
1234
  if (process.env.NODE_ENV === 'development' && time) time`hooks`
1215
1235
 
1216
1236
  let content =
1217
- !children || asChild
1237
+ !children || asChild || !splitStyles
1218
1238
  ? children
1219
1239
  : spacedChildren({
1220
1240
  separator,
@@ -1258,6 +1278,17 @@ export function createComponent<
1258
1278
 
1259
1279
  if (process.env.NODE_ENV === 'development' && time) time`use-children`
1260
1280
 
1281
+ // passthrough mode - only pass style display contents, nothing else
1282
+ if (!splitStyles) {
1283
+ elementType = 'span'
1284
+ content = propsIn.children
1285
+ viewProps = {
1286
+ style: {
1287
+ display: 'contents',
1288
+ },
1289
+ }
1290
+ }
1291
+
1261
1292
  if (useChildrenResult) {
1262
1293
  content = useChildrenResult
1263
1294
  } else {
@@ -1266,14 +1297,25 @@ export function createComponent<
1266
1297
 
1267
1298
  // needs to reset the presence state for nested children
1268
1299
  const ResetPresence = config?.animations?.ResetPresence
1269
- if (
1270
- ResetPresence &&
1271
- willBeAnimated &&
1272
- (hasEnterStyle || presenceState) &&
1273
- content &&
1274
- typeof content !== 'string'
1275
- ) {
1276
- content = <ResetPresence>{content}</ResetPresence>
1300
+ const needsReset = Boolean(
1301
+ // not when passing down to child
1302
+ !asChild &&
1303
+ // not when passThrough
1304
+ splitStyles &&
1305
+ // not when HOC
1306
+ !isHOC &&
1307
+ ResetPresence &&
1308
+ willBeAnimated &&
1309
+ (hasEnterStyle || presenceState)
1310
+ )
1311
+ // avoid re-parenting
1312
+ const hasEverReset = stateRef.current.hasEverResetPresence
1313
+ if (needsReset && !hasEverReset) {
1314
+ stateRef.current.hasEverResetPresence = true
1315
+ }
1316
+ const renderReset = needsReset || hasEverReset
1317
+ if (renderReset && ResetPresence) {
1318
+ content = <ResetPresence disabled={!needsReset}>{content}</ResetPresence>
1277
1319
  }
1278
1320
 
1279
1321
  if (process.env.NODE_ENV === 'development' && time) time`create-element`
@@ -1297,9 +1339,10 @@ export function createComponent<
1297
1339
 
1298
1340
  if (process.env.NODE_ENV === 'development' && time) time`group-context`
1299
1341
 
1300
- content = disableTheme
1301
- ? content
1302
- : getThemedChildren(themeState, content, themeStateProps, false, stateRef)
1342
+ content =
1343
+ disableTheme || !splitStyles
1344
+ ? content
1345
+ : getThemedChildren(themeState, content, themeStateProps, false, stateRef)
1303
1346
 
1304
1347
  if (process.env.NODE_ENV === 'development' && time) time`themed-children`
1305
1348
 
@@ -1308,7 +1351,7 @@ export function createComponent<
1308
1351
  content = (
1309
1352
  <span
1310
1353
  className="_dsp_contents"
1311
- {...(isHydrated && events && getWebEvents(events))}
1354
+ {...(splitStyles && isHydrated && events && getWebEvents(events))}
1312
1355
  >
1313
1356
  {content}
1314
1357
  </span>
@@ -1342,6 +1385,7 @@ export function createComponent<
1342
1385
  if (process.env.TAMAGUI_TARGET === 'web' && startedUnhydrated) {
1343
1386
  // breaking rules of hooks but startedUnhydrated NEVER changes
1344
1387
  const styleTags = useMemo(() => {
1388
+ if (!splitStyles) return
1345
1389
  return getStyleTags(Object.values(splitStyles.rulesToInsert))
1346
1390
  }, [])
1347
1391
  // this is only to appease react hydration really
@@ -1494,7 +1538,7 @@ export function createComponent<
1494
1538
 
1495
1539
  out = options?.disableTheme ? out : themeable(out, extendedConfig, true)
1496
1540
 
1497
- if (process.env.TAMAGUI_MEMOIZE_STYLEABLE) {
1541
+ if (extendedConfig.memo || process.env.TAMAGUI_MEMOIZE_STYLEABLE) {
1498
1542
  out = React.memo(out)
1499
1543
  }
1500
1544
 
@@ -97,7 +97,7 @@ type StyleSplitter = (
97
97
  elementType?: string,
98
98
  startedUnhydrated?: boolean,
99
99
  debug?: DebugProp
100
- ) => GetStyleResult
100
+ ) => null | GetStyleResult
101
101
 
102
102
  export const PROP_SPLIT = '-'
103
103
 
@@ -147,6 +147,10 @@ export const getSplitStyles: StyleSplitter = (
147
147
  conf = conf || getConfig()
148
148
  const animationDriver = componentContext?.animationDriver || conf.animations
149
149
 
150
+ if (props.passThrough) {
151
+ return null
152
+ }
153
+
150
154
  // a bit icky, we need no normalize but not fully
151
155
  if (
152
156
  isWeb &&
@@ -579,6 +583,10 @@ export const getSplitStyles: StyleSplitter = (
579
583
 
580
584
  passDownProp(viewProps, keyInit, valInit, isMediaOrPseudo)
581
585
 
586
+ if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
587
+ console.groupEnd()
588
+ }
589
+
582
590
  // if it's a variant here, we have a two layer variant...
583
591
  // aka styled(Input, { unstyled: true, variants: { unstyled: {} } })
584
592
  // which now has it's own unstyled + the child unstyled...
@@ -591,6 +599,9 @@ export const getSplitStyles: StyleSplitter = (
591
599
  // after shouldPassThrough
592
600
  if (!noSkip) {
593
601
  if (keyInit in skipProps) {
602
+ if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
603
+ console.groupEnd()
604
+ }
594
605
  continue
595
606
  }
596
607
  }
@@ -1517,8 +1528,10 @@ export const useSplitStyles: StyleSplitter = (a, b, c, d, e, f, g, h, i, j, k, l
1517
1528
 
1518
1529
  if (process.env.TAMAGUI_TARGET !== 'native') {
1519
1530
  useInsertEffectCompat(() => {
1520
- insertStyleRules(res.rulesToInsert)
1521
- }, [res.rulesToInsert])
1531
+ if (res) {
1532
+ insertStyleRules(res.rulesToInsert)
1533
+ }
1534
+ }, [res?.rulesToInsert])
1522
1535
  }
1523
1536
 
1524
1537
  return res