@tamagui/core 1.0.1-beta.214 → 1.0.1-beta.216

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 (49) hide show
  1. package/dist/cjs/constants/isDevTools.js +9 -1
  2. package/dist/cjs/constants/isDevTools.js.map +2 -2
  3. package/dist/cjs/createComponent.js +82 -156
  4. package/dist/cjs/createComponent.js.map +3 -3
  5. package/dist/cjs/helpers/createPropMapper.js.map +2 -2
  6. package/dist/cjs/helpers/getSplitStyles.js +74 -47
  7. package/dist/cjs/helpers/getSplitStyles.js.map +2 -2
  8. package/dist/cjs/helpers/getStylesAtomic.js +5 -1
  9. package/dist/cjs/helpers/getStylesAtomic.js.map +2 -2
  10. package/dist/cjs/helpers/normalizeValueWithProperty.js +9 -5
  11. package/dist/cjs/helpers/normalizeValueWithProperty.js.map +2 -2
  12. package/dist/cjs/helpers/pseudoDescriptors.js +10 -0
  13. package/dist/cjs/helpers/pseudoDescriptors.js.map +2 -2
  14. package/dist/cjs/helpers/useShallowSetState.js +1 -1
  15. package/dist/cjs/helpers/useShallowSetState.js.map +2 -2
  16. package/dist/cjs/types.js.map +1 -1
  17. package/dist/cjs/views/TamaguiProvider.js +2 -5
  18. package/dist/cjs/views/TamaguiProvider.js.map +3 -3
  19. package/dist/esm/constants/isDevTools.js +9 -1
  20. package/dist/esm/constants/isDevTools.js.map +2 -2
  21. package/dist/esm/createComponent.js +83 -156
  22. package/dist/esm/createComponent.js.map +3 -3
  23. package/dist/esm/helpers/createPropMapper.js.map +2 -2
  24. package/dist/esm/helpers/getSplitStyles.js +75 -48
  25. package/dist/esm/helpers/getSplitStyles.js.map +2 -2
  26. package/dist/esm/helpers/getStylesAtomic.js +5 -1
  27. package/dist/esm/helpers/getStylesAtomic.js.map +2 -2
  28. package/dist/esm/helpers/normalizeValueWithProperty.js +9 -5
  29. package/dist/esm/helpers/normalizeValueWithProperty.js.map +2 -2
  30. package/dist/esm/helpers/pseudoDescriptors.js +10 -0
  31. package/dist/esm/helpers/pseudoDescriptors.js.map +2 -2
  32. package/dist/esm/helpers/useShallowSetState.js +1 -1
  33. package/dist/esm/helpers/useShallowSetState.js.map +2 -2
  34. package/dist/esm/views/TamaguiProvider.js +2 -5
  35. package/dist/esm/views/TamaguiProvider.js.map +3 -3
  36. package/package.json +12 -12
  37. package/src/constants/isDevTools.ts +10 -4
  38. package/src/createComponent.tsx +101 -208
  39. package/src/helpers/createPropMapper.ts +1 -0
  40. package/src/helpers/getSplitStyles.tsx +91 -57
  41. package/src/helpers/getStylesAtomic.ts +7 -2
  42. package/src/helpers/normalizeValueWithProperty.ts +11 -5
  43. package/src/helpers/pseudoDescriptors.ts +24 -3
  44. package/src/helpers/useShallowSetState.tsx +1 -1
  45. package/src/types.tsx +1 -1
  46. package/src/views/TamaguiProvider.tsx +5 -6
  47. package/types/helpers/getSplitStyles.d.ts +1 -1
  48. package/types/helpers/pseudoDescriptors.d.ts +8 -14
  49. package/types/types.d.ts +1 -1
@@ -7,7 +7,7 @@ function useShallowSetState(setter, debug, debugName) {
7
7
  if (prev[key] !== next[key]) {
8
8
  if (process.env.NODE_ENV === "development") {
9
9
  if (debug === "verbose") {
10
- console.warn(`update ${debugName}`, next);
10
+ console.log(` \u25B2 setState ${debugName}`, next);
11
11
  }
12
12
  }
13
13
  return { ...prev, ...next };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/helpers/useShallowSetState.tsx"],
4
- "sourcesContent": ["import React, { useCallback } from 'react'\n\nexport function useShallowSetState<State extends Object>(\n setter: React.Dispatch<React.SetStateAction<State>>,\n debug?: boolean | 'verbose',\n debugName?: string\n) {\n return useCallback(\n (next: Partial<State>) => {\n setter((prev) => {\n for (const key in next) {\n if (prev[key] !== next[key]) {\n if (process.env.NODE_ENV === 'development') {\n if (debug === 'verbose') {\n // eslint-disable-next-line no-console\n console.warn(`update ${debugName}`, next)\n }\n }\n return { ...prev, ...next }\n }\n }\n return prev\n })\n },\n [setter]\n )\n}\n"],
5
- "mappings": "AAAA,SAAgB,mBAAmB;AAE5B,SAAS,mBACd,QACA,OACA,WACA;AACA,SAAO;AAAA,IACL,CAAC,SAAyB;AACxB,aAAO,CAAC,SAAS;AACf,mBAAW,OAAO,MAAM;AACtB,cAAI,KAAK,SAAS,KAAK,MAAM;AAC3B,gBAAI,QAAQ,IAAI,aAAa,eAAe;AAC1C,kBAAI,UAAU,WAAW;AAEvB,wBAAQ,KAAK,UAAU,aAAa,IAAI;AAAA,cAC1C;AAAA,YACF;AACA,mBAAO,EAAE,GAAG,MAAM,GAAG,KAAK;AAAA,UAC5B;AAAA,QACF;AACA,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AACF;",
4
+ "sourcesContent": ["import React, { useCallback } from 'react'\n\nexport function useShallowSetState<State extends Object>(\n setter: React.Dispatch<React.SetStateAction<State>>,\n debug?: boolean | 'verbose',\n debugName?: string\n) {\n return useCallback(\n (next: Partial<State>) => {\n setter((prev) => {\n for (const key in next) {\n if (prev[key] !== next[key]) {\n if (process.env.NODE_ENV === 'development') {\n if (debug === 'verbose') {\n // eslint-disable-next-line no-console\n console.log(` \u25B2 setState ${debugName}`, next)\n }\n }\n return { ...prev, ...next }\n }\n }\n return prev\n })\n },\n [setter]\n )\n}\n"],
5
+ "mappings": "AAAA,SAAgB,mBAAmB;AAE5B,SAAS,mBACd,QACA,OACA,WACA;AACA,SAAO;AAAA,IACL,CAAC,SAAyB;AACxB,aAAO,CAAC,SAAS;AACf,mBAAW,OAAO,MAAM;AACtB,cAAI,KAAK,SAAS,KAAK,MAAM;AAC3B,gBAAI,QAAQ,IAAI,aAAa,eAAe;AAC1C,kBAAI,UAAU,WAAW;AAEvB,wBAAQ,IAAI,oBAAe,aAAa,IAAI;AAAA,cAC9C;AAAA,YACF;AACA,mBAAO,EAAE,GAAG,MAAM,GAAG,KAAK;AAAA,UAC5B;AAAA,QACF;AACA,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AACF;",
6
6
  "names": []
7
7
  }
@@ -5,7 +5,6 @@ import { ButtonInsideButtonContext } from "../contexts/ButtonInsideButtonContext
5
5
  import { TextAncestorContext } from "../contexts/TextAncestorContext";
6
6
  import { useMediaListeners } from "../hooks/useMedia";
7
7
  import { ThemeProvider } from "./ThemeProvider";
8
- import { getConfig } from "..";
9
8
  function TamaguiProvider({
10
9
  children,
11
10
  disableInjectCSS,
@@ -13,10 +12,9 @@ function TamaguiProvider({
13
12
  ...themePropsProvider
14
13
  }) {
15
14
  if (isRSC) {
16
- const { themes: themes2 } = getConfig();
17
15
  return /* @__PURE__ */ jsx("span", {
18
16
  style: { display: "contents" },
19
- className: `t_${Object.keys(themes2)[0] || "light"}`,
17
+ className: `t_${Object.keys(config.themes)[0] || "light"}`,
20
18
  children
21
19
  });
22
20
  }
@@ -35,7 +33,6 @@ function TamaguiProvider({
35
33
  };
36
34
  }, [config, disableInjectCSS]);
37
35
  }
38
- const { themes } = getConfig();
39
36
  return /* @__PURE__ */ jsx(ButtonInsideButtonContext.Provider, {
40
37
  value: false,
41
38
  children: /* @__PURE__ */ jsx(TextAncestorContext.Provider, {
@@ -44,7 +41,7 @@ function TamaguiProvider({
44
41
  themeClassNameOnRoot: config.themeClassNameOnRoot,
45
42
  disableRootThemeClass: config.disableRootThemeClass,
46
43
  ...themePropsProvider,
47
- defaultTheme: themePropsProvider.defaultTheme ?? Object.keys(themes)[0],
44
+ defaultTheme: themePropsProvider.defaultTheme ?? Object.keys(config.themes)[0],
48
45
  children
49
46
  })
50
47
  })
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/views/TamaguiProvider.tsx"],
4
- "sourcesContent": ["import { isClient, isRSC, isServer } from '@tamagui/constants'\nimport * as React from 'react'\n\nimport { ButtonInsideButtonContext } from '../contexts/ButtonInsideButtonContext'\nimport { TextAncestorContext } from '../contexts/TextAncestorContext'\nimport { useMediaListeners } from '../hooks/useMedia'\nimport type { TamaguiProviderProps } from '../types'\nimport { ThemeProvider } from './ThemeProvider'\nimport { getConfig } from '..'\n\nexport function TamaguiProvider({\n children,\n disableInjectCSS,\n config,\n ...themePropsProvider\n}: TamaguiProviderProps) {\n if (isRSC) {\n const { themes } = getConfig()\n return (\n <span style={{ display: 'contents' }} className={`t_${Object.keys(themes)[0] || 'light'}`}>\n {children}\n </span>\n )\n }\n\n if (!isServer) {\n useMediaListeners(config)\n }\n\n if (isClient) {\n // inject CSS if asked to (not SSR compliant)\n // eslint-disable-next-line react-hooks/rules-of-hooks\n React.useLayoutEffect(() => {\n if (disableInjectCSS) return\n const style = document.createElement('style')\n style.appendChild(document.createTextNode(config.getCSS()))\n document.head.appendChild(style)\n return () => {\n document.head.removeChild(style)\n }\n }, [config, disableInjectCSS])\n }\n\n const { themes } = getConfig()\n\n return (\n <ButtonInsideButtonContext.Provider value={false}>\n <TextAncestorContext.Provider value={false}>\n <ThemeProvider\n themeClassNameOnRoot={config.themeClassNameOnRoot}\n disableRootThemeClass={config.disableRootThemeClass}\n {...themePropsProvider}\n defaultTheme={themePropsProvider.defaultTheme ?? Object.keys(themes)[0]}\n >\n {children}\n </ThemeProvider>\n </TextAncestorContext.Provider>\n </ButtonInsideButtonContext.Provider>\n )\n}\n"],
5
- "mappings": "AAmBM;AAnBN,SAAS,UAAU,OAAO,gBAAgB;AAC1C,YAAY,WAAW;AAEvB,SAAS,iCAAiC;AAC1C,SAAS,2BAA2B;AACpC,SAAS,yBAAyB;AAElC,SAAS,qBAAqB;AAC9B,SAAS,iBAAiB;AAEnB,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,KACG;AACL,GAAyB;AACvB,MAAI,OAAO;AACT,UAAM,EAAE,QAAAA,QAAO,IAAI,UAAU;AAC7B,WACE,oBAAC;AAAA,MAAK,OAAO,EAAE,SAAS,WAAW;AAAA,MAAG,WAAW,KAAK,OAAO,KAAKA,OAAM,EAAE,MAAM;AAAA,MAC7E;AAAA,KACH;AAAA,EAEJ;AAEA,MAAI,CAAC,UAAU;AACb,sBAAkB,MAAM;AAAA,EAC1B;AAEA,MAAI,UAAU;AAGZ,UAAM,gBAAgB,MAAM;AAC1B,UAAI;AAAkB;AACtB,YAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,YAAM,YAAY,SAAS,eAAe,OAAO,OAAO,CAAC,CAAC;AAC1D,eAAS,KAAK,YAAY,KAAK;AAC/B,aAAO,MAAM;AACX,iBAAS,KAAK,YAAY,KAAK;AAAA,MACjC;AAAA,IACF,GAAG,CAAC,QAAQ,gBAAgB,CAAC;AAAA,EAC/B;AAEA,QAAM,EAAE,OAAO,IAAI,UAAU;AAE7B,SACE,oBAAC,0BAA0B,UAA1B;AAAA,IAAmC,OAAO;AAAA,IACzC,8BAAC,oBAAoB,UAApB;AAAA,MAA6B,OAAO;AAAA,MACnC,8BAAC;AAAA,QACC,sBAAsB,OAAO;AAAA,QAC7B,uBAAuB,OAAO;AAAA,QAC7B,GAAG;AAAA,QACJ,cAAc,mBAAmB,gBAAgB,OAAO,KAAK,MAAM,EAAE;AAAA,QAEpE;AAAA,OACH;AAAA,KACF;AAAA,GACF;AAEJ;",
6
- "names": ["themes"]
4
+ "sourcesContent": ["import { isClient, isRSC, isServer } from '@tamagui/constants'\nimport * as React from 'react'\n\nimport { ButtonInsideButtonContext } from '../contexts/ButtonInsideButtonContext'\nimport { TextAncestorContext } from '../contexts/TextAncestorContext'\nimport { useMediaListeners } from '../hooks/useMedia'\nimport type { TamaguiProviderProps } from '../types'\nimport { ThemeProvider } from './ThemeProvider'\n\nexport function TamaguiProvider({\n children,\n disableInjectCSS,\n config,\n ...themePropsProvider\n}: TamaguiProviderProps) {\n if (isRSC) {\n return (\n <span\n style={{ display: 'contents' }}\n className={`t_${Object.keys(config.themes)[0] || 'light'}`}\n >\n {children}\n </span>\n )\n }\n\n if (!isServer) {\n useMediaListeners(config)\n }\n\n if (isClient) {\n // inject CSS if asked to (not SSR compliant)\n // eslint-disable-next-line react-hooks/rules-of-hooks\n React.useLayoutEffect(() => {\n if (disableInjectCSS) return\n const style = document.createElement('style')\n style.appendChild(document.createTextNode(config.getCSS()))\n document.head.appendChild(style)\n return () => {\n document.head.removeChild(style)\n }\n }, [config, disableInjectCSS])\n }\n\n return (\n <ButtonInsideButtonContext.Provider value={false}>\n <TextAncestorContext.Provider value={false}>\n <ThemeProvider\n themeClassNameOnRoot={config.themeClassNameOnRoot}\n disableRootThemeClass={config.disableRootThemeClass}\n {...themePropsProvider}\n defaultTheme={themePropsProvider.defaultTheme ?? Object.keys(config.themes)[0]}\n >\n {children}\n </ThemeProvider>\n </TextAncestorContext.Provider>\n </ButtonInsideButtonContext.Provider>\n )\n}\n"],
5
+ "mappings": "AAiBM;AAjBN,SAAS,UAAU,OAAO,gBAAgB;AAC1C,YAAY,WAAW;AAEvB,SAAS,iCAAiC;AAC1C,SAAS,2BAA2B;AACpC,SAAS,yBAAyB;AAElC,SAAS,qBAAqB;AAEvB,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,KACG;AACL,GAAyB;AACvB,MAAI,OAAO;AACT,WACE,oBAAC;AAAA,MACC,OAAO,EAAE,SAAS,WAAW;AAAA,MAC7B,WAAW,KAAK,OAAO,KAAK,OAAO,MAAM,EAAE,MAAM;AAAA,MAEhD;AAAA,KACH;AAAA,EAEJ;AAEA,MAAI,CAAC,UAAU;AACb,sBAAkB,MAAM;AAAA,EAC1B;AAEA,MAAI,UAAU;AAGZ,UAAM,gBAAgB,MAAM;AAC1B,UAAI;AAAkB;AACtB,YAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,YAAM,YAAY,SAAS,eAAe,OAAO,OAAO,CAAC,CAAC;AAC1D,eAAS,KAAK,YAAY,KAAK;AAC/B,aAAO,MAAM;AACX,iBAAS,KAAK,YAAY,KAAK;AAAA,MACjC;AAAA,IACF,GAAG,CAAC,QAAQ,gBAAgB,CAAC;AAAA,EAC/B;AAEA,SACE,oBAAC,0BAA0B,UAA1B;AAAA,IAAmC,OAAO;AAAA,IACzC,8BAAC,oBAAoB,UAApB;AAAA,MAA6B,OAAO;AAAA,MACnC,8BAAC;AAAA,QACC,sBAAsB,OAAO;AAAA,QAC7B,uBAAuB,OAAO;AAAA,QAC7B,GAAG;AAAA,QACJ,cAAc,mBAAmB,gBAAgB,OAAO,KAAK,OAAO,MAAM,EAAE;AAAA,QAE3E;AAAA,OACH;AAAA,KACF;AAAA,GACF;AAEJ;",
6
+ "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tamagui/core",
3
- "version": "1.0.1-beta.214",
3
+ "version": "1.0.1-beta.216",
4
4
  "source": "src/index.ts",
5
5
  "main": "dist/cjs",
6
6
  "module": "dist/esm",
@@ -28,23 +28,23 @@
28
28
  ],
29
29
  "dependencies": {
30
30
  "@expo/match-media": "^0.3.0",
31
- "@tamagui/compose-refs": "^1.0.1-beta.214",
32
- "@tamagui/constants": "^1.0.1-beta.214",
33
- "@tamagui/helpers": "^1.0.1-beta.214",
34
- "@tamagui/normalize-css-color-lite": "^1.0.1-beta.214",
35
- "@tamagui/react-native-use-pressable": "^1.0.1-beta.214",
36
- "@tamagui/react-native-use-responder-events": "^1.0.1-beta.214",
37
- "@tamagui/types-react-native": "^1.0.1-beta.214",
38
- "@tamagui/use-did-finish-ssr": "^1.0.1-beta.214",
39
- "@tamagui/use-event": "^1.0.1-beta.214",
40
- "@tamagui/use-force-update": "^1.0.1-beta.214"
31
+ "@tamagui/compose-refs": "^1.0.1-beta.216",
32
+ "@tamagui/constants": "^1.0.1-beta.216",
33
+ "@tamagui/helpers": "^1.0.1-beta.216",
34
+ "@tamagui/normalize-css-color-lite": "^1.0.1-beta.216",
35
+ "@tamagui/react-native-use-pressable": "^1.0.1-beta.216",
36
+ "@tamagui/react-native-use-responder-events": "^1.0.1-beta.216",
37
+ "@tamagui/types-react-native": "^1.0.1-beta.216",
38
+ "@tamagui/use-did-finish-ssr": "^1.0.1-beta.216",
39
+ "@tamagui/use-event": "^1.0.1-beta.216",
40
+ "@tamagui/use-force-update": "^1.0.1-beta.216"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "react": "*",
44
44
  "react-dom": "*"
45
45
  },
46
46
  "devDependencies": {
47
- "@tamagui/build": "^1.0.1-beta.214",
47
+ "@tamagui/build": "^1.0.1-beta.216",
48
48
  "@types/node": "^16.11.9",
49
49
  "@types/react": "^18.0.15",
50
50
  "@types/react-native": "^0.69.2",
@@ -1,6 +1,12 @@
1
1
  // for verbose logging outside node/cli
2
2
 
3
- export const isDevTools =
4
- process.env.NODE_ENV === 'development'
5
- ? new Function('try {return this===window;}catch(e){ return false;}')()
6
- : false
3
+ export const isDevTools = (() => {
4
+ if (process.env.NODE_ENV === 'development') {
5
+ try {
6
+ return new Function('try {return this===window;}catch(e){ return false;}')()
7
+ } catch {
8
+ //
9
+ }
10
+ }
11
+ return false
12
+ })()
@@ -3,6 +3,7 @@ import { isClient, isRSC, isWeb, useIsomorphicLayoutEffect } from '@tamagui/cons
3
3
  /* eslint-disable react-hooks/rules-of-hooks */
4
4
  import {
5
5
  composeEventHandlers,
6
+ stylePropsTransform,
6
7
  stylePropsView,
7
8
  validPseudoKeys,
8
9
  validStyles,
@@ -36,7 +37,9 @@ import {
36
37
  } from './helpers/getSplitStyles'
37
38
  import { getAllSelectors } from './helpers/insertStyleRule'
38
39
  import { mergeProps } from './helpers/mergeProps'
40
+ import { mergeTransform } from './helpers/mergeTransform'
39
41
  import { proxyThemeVariables } from './helpers/proxyThemeVariables'
42
+ import { pseudoDescriptors } from './helpers/pseudoDescriptors'
40
43
  import { useShallowSetState } from './helpers/useShallowSetState'
41
44
  import { getRect, measureLayout, useElementLayout } from './hooks/useElementLayout'
42
45
  import { addMediaQueryListener, getInitialMediaState } from './hooks/useMedia'
@@ -46,6 +49,7 @@ import {
46
49
  SpaceDirection,
47
50
  SpaceTokens,
48
51
  SpacerProps,
52
+ SplitStyleState,
49
53
  StaticConfig,
50
54
  StaticConfigParsed,
51
55
  StylableComponent,
@@ -162,16 +166,6 @@ export function createComponent<
162
166
  ? `is_${props.componentName}`
163
167
  : defaultComponentClassName
164
168
 
165
- if (debugProp) {
166
- // eslint-disable-next-line no-console
167
- console.log(`render ${componentName}`)
168
- }
169
-
170
- const forceUpdate = useForceUpdate()
171
- const theme = useTheme(props.theme, componentName, props, forceUpdate)
172
-
173
- // time`useTheme`
174
-
175
169
  /**
176
170
  * Component state for tracking animations, pseudos
177
171
  */
@@ -185,14 +179,46 @@ export function createComponent<
185
179
  const setState = states[1]
186
180
  const setStateShallow = useShallowSetState(setState, debugProp, componentName)
187
181
 
188
- const shouldSetMounted = needsMount && !state.mounted
182
+ const useAnimations = tamaguiConfig.animations?.useAnimations as UseAnimationHook | undefined
183
+ // conditional but if ever true stays true
184
+ const hasEverAnimated = useRef(false)
185
+ const isAnimated = (() => {
186
+ const next = !!(useAnimations && props.animation)
187
+ if (next && !hasEverAnimated.current) {
188
+ hasEverAnimated.current = true
189
+ }
190
+ return next || hasEverAnimated.current
191
+ })()
192
+ const isReactNative = Boolean(
193
+ staticConfig.isReactNative || (isAnimated && tamaguiConfig.animations.isReactNative)
194
+ )
195
+
196
+ if (process.env.NODE_ENV === 'development') {
197
+ if (props['debug']) {
198
+ const name = `${
199
+ componentName || Component?.displayName || Component?.name || '[Unnamed Component]'
200
+ }`
201
+ const type = isReactNative ? '(rnw)' : ''
202
+ const dataIs = propsIn['data-is'] || ''
203
+ const banner = `${name}${dataIs ? ` ${dataIs}` : ''} ${type}`
204
+ // eslint-disable-next-line no-console
205
+ console.group(`%c ${banner}`, 'background: yellow;')
206
+ // eslint-disable-next-line no-console
207
+ console.log(`state`, state)
208
+ }
209
+ }
210
+
211
+ const forceUpdate = useForceUpdate()
212
+ const theme = useTheme(props.theme, componentName, props, forceUpdate)
213
+
214
+ const shouldSetMounted = needsMount && state.unmounted
189
215
  const setMounted = shouldSetMounted
190
216
  ? () => {
191
217
  // for some reason without some small delay it doesn't animate css
192
218
  setTimeout(
193
219
  () => {
194
220
  setStateShallow({
195
- mounted: true,
221
+ unmounted: false,
196
222
  })
197
223
  },
198
224
  isWeb ? 10 : 0
@@ -201,41 +227,14 @@ export function createComponent<
201
227
  : undefined
202
228
 
203
229
  const shouldAvoidClasses =
204
- !!(props.animation && avoidClassesWhileAnimating) || !staticConfig.acceptsClassName
230
+ !isWeb || !!(props.animation && avoidClassesWhileAnimating) || !staticConfig.acceptsClassName
205
231
 
206
232
  const shouldForcePseudo = !!propsIn.forceStyle
207
233
  const hasTextAncestor = !!(isWeb && isText ? useContext(TextAncestorContext) : false)
208
- const splitStyleState =
209
- !shouldAvoidClasses && !shouldForcePseudo
210
- ? {
211
- ...state,
212
- hasTextAncestor,
213
- dynamicStylesInline: true,
214
- }
215
- : ({
216
- ...state,
217
- noClassNames: true,
218
- dynamicStylesInline: true,
219
- hasTextAncestor,
220
- resolveVariablesAs: 'value',
221
- } as const)
222
-
234
+ const noClassNames = shouldAvoidClasses || shouldForcePseudo
223
235
  const languageContext = isRSC ? null : useContext(FontLanguageContext)
224
-
225
236
  const isDisabled = props.disabled ?? props.accessibilityState?.disabled
226
237
 
227
- const useAnimations = tamaguiConfig.animations?.useAnimations as UseAnimationHook | undefined
228
-
229
- // conditional but if ever true stays true
230
- const hasEverAnimated = useRef(false)
231
- const isAnimated = (() => {
232
- const next = !!(useAnimations && props.animation)
233
- if (next && !hasEverAnimated.current) {
234
- hasEverAnimated.current = true
235
- }
236
- return next || hasEverAnimated.current
237
- })()
238
-
239
238
  const isTaggable = !Component || typeof Component === 'string'
240
239
  // default to tag, fallback to component (when both strings)
241
240
  const element = isWeb
@@ -255,6 +254,13 @@ export function createComponent<
255
254
 
256
255
  // time`setupStateConf`
257
256
 
257
+ const splitStyleState: SplitStyleState = {
258
+ ...state,
259
+ noClassNames,
260
+ dynamicStylesInline: noClassNames,
261
+ hasTextAncestor,
262
+ resolveVariablesAs: 'value',
263
+ }
258
264
  const splitStyles = useSplitStyles(
259
265
  props,
260
266
  staticConfig,
@@ -271,9 +277,6 @@ export function createComponent<
271
277
  const hostRef = useServerRef<TamaguiElement>(null)
272
278
 
273
279
  // animation setup
274
- const isReactNative = Boolean(
275
- staticConfig.isReactNative || (isAnimated && tamaguiConfig.animations.isReactNative)
276
- )
277
280
  const isAnimatedReactNativeWeb = isAnimated && avoidClassesWhileAnimating
278
281
 
279
282
  if (process.env.NODE_ENV === 'development') {
@@ -283,22 +286,15 @@ export function createComponent<
283
286
  }
284
287
 
285
288
  if (debugProp) {
286
- const name = `${
287
- componentName || Component?.displayName || Component?.name || '[Unnamed Component]'
288
- }`
289
- const type = isReactNative ? 'rnw' : 'tamagui'
290
- const banner = `${name} ${propsIn['data-is'] || ''} ${type}`
291
289
  // eslint-disable-next-line no-console
292
- console.group(`%c 🐛 ${banner}`, 'background: yellow;')
290
+ console.groupCollapsed('props')
293
291
  // eslint-disable-next-line no-console
294
- console.groupCollapsed('initial props/state')
295
- // eslint-disable-next-line no-console
296
- console.log('propsIn', propsIn, 'turned into', props, 'order', Object.keys(props))
292
+ console.log('props in', propsIn, 'mapped to', props, 'in order', Object.keys(props))
297
293
  // eslint-disable-next-line no-console
298
294
  console.log('splitStyles', splitStyles)
299
295
  // eslint-disable-next-line no-console
300
296
  console.log('className', Object.values(splitStyles.classNames))
301
- if (typeof window !== 'undefined') {
297
+ if (isClient) {
302
298
  // eslint-disable-next-line no-console
303
299
  console.log('ref', hostRef, '(click to view)')
304
300
  }
@@ -320,9 +316,6 @@ export function createComponent<
320
316
  mediaKeys,
321
317
  } = splitStyles
322
318
 
323
- const animationFeatureStylesIn = props.animation
324
- ? { ...defaultNativeStyle, ...splitStylesStyle }
325
- : null
326
319
  const propsWithAnimation = props as UseAnimationProps
327
320
 
328
321
  // once you set animation prop don't remove it, you can set to undefined/false
@@ -336,9 +329,14 @@ export function createComponent<
336
329
  hostRef,
337
330
  staticConfig,
338
331
  getStyle({ isExiting, isEntering, exitVariant, enterVariant } = {}) {
332
+ // TODO this function can mostly be moved entirely inside getSplitStyles
333
+ // I think theres bugs in merge(), and we can remove that fn entirely then
334
+ // also i think we need to merge both the exitVariant AND psuedos.exitStyle right now it chooses one
335
+
339
336
  // we have to merge such that transforms keys all exist
340
- const style = animationFeatureStylesIn
337
+ const animationStyle = { ...defaultNativeStyle, ...splitStylesStyle }
341
338
 
339
+ // allows for enter/exit variants on styled()
342
340
  const enterStyle = isEntering
343
341
  ? enterVariant && staticConfig.variants?.[enterVariant]['true']
344
342
  ? getSubStyle(
@@ -349,8 +347,8 @@ export function createComponent<
349
347
  props,
350
348
  state,
351
349
  tamaguiConfig
352
- ) || pseudos.enterStyle
353
- : pseudos.enterStyle
350
+ )
351
+ : null
354
352
  : null
355
353
 
356
354
  const exitStyle = isExiting
@@ -363,41 +361,18 @@ export function createComponent<
363
361
  props,
364
362
  state,
365
363
  tamaguiConfig
366
- ) || pseudos.exitStyle
364
+ )
367
365
  : pseudos.exitStyle
368
366
  : null
369
367
 
370
- // if you have hoverStyle={{ scale: 1.1 }} and don't have scale set on the base style
371
- // no animation will run! this is really confusing. this will look at all variants,
372
- // and fill in base styles if they don't exist. eg:
373
- // input:
374
- // base: {}
375
- // hoverStyle: { scale: 2 }
376
- // enterStyle: { x: 100 }
377
- // output:
378
- // base: { x: 0, scale: 1 }
379
- ensureBaseHasDefaults(
380
- style,
381
- // enterStyle,
382
- pseudos.hoverStyle,
383
- pseudos.focusStyle,
384
- pseudos.pressStyle
385
- )
386
-
387
- enterStyle && isEntering && merge(style, enterStyle)
388
- state.hover && pseudos.hoverStyle && merge(style, pseudos.hoverStyle)
389
- state.focus && pseudos.focusStyle && merge(style, pseudos.focusStyle)
390
- state.press && pseudos.pressStyle && merge(style, pseudos.pressStyle)
391
- exitStyle && isExiting && merge(style, exitStyle)
392
-
393
- if (process.env.NODE_ENV === 'development') {
394
- if (debugProp === 'verbose') {
395
- // eslint-disable-next-line no-console
396
- console.log('animation style', style)
397
- }
368
+ if (isEntering && enterStyle) {
369
+ merge(animationStyle, enterStyle)
370
+ }
371
+ if (isExiting && exitStyle) {
372
+ merge(animationStyle, exitStyle)
398
373
  }
399
374
 
400
- return style
375
+ return animationStyle
401
376
  },
402
377
  //, delay
403
378
  })
@@ -628,16 +603,7 @@ export function createComponent<
628
603
  }
629
604
  } else {
630
605
  styles = [isWeb ? null : defaultNativeStyle, animationStyles ?? splitStylesStyle, medias]
631
- if (!animationStyles && initialSplitStyles) {
632
- const initPseudos = initialSplitStyles.pseudos
633
- !state.mounted && addPseudoToStyles(styles, initPseudos, pseudos, 'enterStyle')
634
- state.hover &&
635
- addPseudoToStyles(styles, initPseudos, pseudos, 'hoverStyle', shouldForcePseudo)
636
- state.focus &&
637
- addPseudoToStyles(styles, initPseudos, pseudos, 'focusStyle', shouldForcePseudo)
638
- state.press &&
639
- addPseudoToStyles(styles, initPseudos, pseudos, 'pressStyle', shouldForcePseudo)
640
- }
606
+
641
607
  // ugly but for now...
642
608
  if (shouldForcePseudo) {
643
609
  const next = {}
@@ -723,19 +689,14 @@ export function createComponent<
723
689
 
724
690
  // TODO need to loop active variants and see if they have matchin pseudos and apply as well
725
691
  const initialPseudos = initialSplitStyles?.pseudos
726
- const attachPress = !!(
727
- pseudos?.pressStyle ||
728
- initialPseudos?.pressStyle ||
729
- onPress ||
730
- onPressOut ||
731
- onPressIn ||
732
- onClick
733
- )
692
+ const runtimePressStyle = noClassNames && (pseudos?.pressStyle || initialPseudos?.pressStyle)
693
+ const attachPress = !!(runtimePressStyle || onPress || onPressOut || onPressIn || onClick)
734
694
 
735
695
  const isHoverable = isWeb
696
+ const runtimeHoverStyle = noClassNames && (pseudos?.hoverStyle || initialPseudos.hoverStyle)
736
697
  const attachHover =
737
698
  isHoverable &&
738
- !!((pseudos && pseudos.hoverStyle) || onHoverIn || onHoverOut || onMouseEnter || onMouseLeave)
699
+ !!(runtimeHoverStyle || onHoverIn || onHoverOut || onMouseEnter || onMouseLeave)
739
700
 
740
701
  const handlesPressEvents = !isWeb && !asChild
741
702
 
@@ -768,7 +729,7 @@ export function createComponent<
768
729
  onMouseUp?.(e)
769
730
  }
770
731
  : undefined,
771
- ...(isHoverable && {
732
+ ...(attachHover && {
772
733
  onMouseEnter: attachHover
773
734
  ? (e) => {
774
735
  const next: Partial<typeof state> = {}
@@ -894,10 +855,7 @@ export function createComponent<
894
855
  // EVENTS native
895
856
  if (process.env.TAMAGUI_TARGET === 'native') {
896
857
  // add focus events
897
- const attachFocus = !!(
898
- (pseudos && pseudos.focusStyle) ||
899
- (initialPseudos && initialPseudos.focusStyle)
900
- )
858
+ const attachFocus = !!(pseudos.focusStyle || (initialPseudos && initialPseudos.focusStyle))
901
859
  if (attachFocus) {
902
860
  viewProps.onFocus = mergeEvent(viewProps.onFocus, () => {
903
861
  setStateShallow({ focus: true })
@@ -909,11 +867,8 @@ export function createComponent<
909
867
 
910
868
  // use Pressability to get smooth unPress when you press + hold + move out
911
869
  // only ever create once, use .configure() to update later
912
- const pressability = usePressability(events)
870
+ const pressability = usePressability(events ? { ...events, hitSlop } : {})
913
871
  if (attachPress && events) {
914
- if (hitSlop) {
915
- viewProps.hitSlop = hitSlop
916
- }
917
872
  for (const key in pressability) {
918
873
  const og = props[key]
919
874
  const val = pressability[key]
@@ -989,12 +944,12 @@ export function createComponent<
989
944
  press: false,
990
945
  pressIn: false,
991
946
  focus: false,
992
- mounted: false,
947
+ unmounted: true,
993
948
  mediaState: getMediaStateObject(getInitialMediaState()),
994
949
  }
995
950
  defaultComponentStateMounted = {
996
951
  ...defaultComponentState,
997
- mounted: true,
952
+ unmounted: false,
998
953
  }
999
954
  }
1000
955
 
@@ -1052,14 +1007,13 @@ export function createComponent<
1052
1007
  staticConfig,
1053
1008
  initialTheme,
1054
1009
  {
1055
- mounted: true,
1010
+ unmounted: false,
1056
1011
  hover: false,
1057
1012
  press: false,
1058
1013
  pressIn: false,
1059
1014
  focus: false,
1060
1015
  resolveVariablesAs: 'both',
1061
1016
  noClassNames,
1062
- keepVariantsAsProps: true,
1063
1017
  },
1064
1018
  undefined,
1065
1019
  undefined,
@@ -1071,7 +1025,9 @@ export function createComponent<
1071
1025
  // otherwise it confuses variant functions getting className props
1072
1026
  const [defaults, defaultsClassnames] = mergeProps(
1073
1027
  component.defaultProps as any,
1074
- initialSplitStyles.viewProps,
1028
+ isWeb
1029
+ ? { ...initialSplitStyles.pseudos, ...initialSplitStyles.viewProps }
1030
+ : initialSplitStyles.viewProps,
1075
1031
  true
1076
1032
  // conf.inverseShorthands
1077
1033
  )
@@ -1102,6 +1058,17 @@ export function createComponent<
1102
1058
 
1103
1059
  if (Object.keys(defaults).length) {
1104
1060
  tamaguiDefaultProps = defaults
1061
+
1062
+ // temp bugfix, splitStyles isn't returning variables when resolveVariablesAs == 'both'
1063
+ if (!isWeb) {
1064
+ Object.keys(pseudoDescriptors).forEach((k) => {
1065
+ if (ourProps[k]) {
1066
+ // @ts-ignore
1067
+ initialSplitStyles.pseudos[k] = null
1068
+ tamaguiDefaultProps[k] = ourProps[k]
1069
+ }
1070
+ })
1071
+ }
1105
1072
  }
1106
1073
 
1107
1074
  // add debug logs
@@ -1244,7 +1211,6 @@ export function spacedChildren({
1244
1211
  for (const [index, child] of childrenList.entries()) {
1245
1212
  const isEmpty =
1246
1213
  child === null || child === undefined || (Array.isArray(child) && child.length === 0)
1247
-
1248
1214
  // push them all, but wrap some in Fragment
1249
1215
  if (isEmpty || !child || (child['key'] && !isZStack)) {
1250
1216
  final.push(child)
@@ -1255,14 +1221,9 @@ export function spacedChildren({
1255
1221
  }
1256
1222
 
1257
1223
  // first child unspaced avoid insert space
1258
- if (isUnspaced(child) && index === 0) {
1259
- continue
1260
- }
1261
-
1224
+ if (isUnspaced(child) && index === 0) continue
1262
1225
  // no spacing on ZStack
1263
- if (isZStack) {
1264
- continue
1265
- }
1226
+ if (isZStack) continue
1266
1227
 
1267
1228
  const next = childrenList[index + 1]
1268
1229
 
@@ -1330,23 +1291,6 @@ function isUnspaced(child: React.ReactNode) {
1330
1291
  return child?.['type']?.['isVisuallyHidden'] || child?.['type']?.['isUnspaced']
1331
1292
  }
1332
1293
 
1333
- function addPseudoToStyles(
1334
- styles: any[],
1335
- initialPseudos: SplitStyleResult['pseudos'],
1336
- pseudos: any,
1337
- name: string,
1338
- force = false
1339
- ) {
1340
- // on web use pseudo object { hoverStyle } to keep specificity with concatClassName
1341
- const pseudoStyle = pseudos[name]
1342
- const shouldNestObject = isWeb && name !== 'enterStyle' && name !== 'exitStyle'
1343
- const defaultPseudoStyle = initialPseudos[name]
1344
- const style = defaultPseudoStyle ? { ...defaultPseudoStyle, ...pseudoStyle } : pseudoStyle
1345
- if (style) {
1346
- styles.push(shouldNestObject && !force ? { [name]: style } : style)
1347
- }
1348
- }
1349
-
1350
1294
  const DefaultProps = new Map()
1351
1295
 
1352
1296
  function mergeConfigDefaultProps(
@@ -1385,68 +1329,17 @@ function mergeConfigDefaultProps(
1385
1329
  return props
1386
1330
  }
1387
1331
 
1388
- const defaults = {
1389
- left: 0,
1390
- right: 0,
1391
- top: 0,
1392
- bottom: 0,
1393
- opacity: 1,
1394
- translateX: 0,
1395
- translateY: 0,
1396
- skew: 0,
1397
- skewX: 0,
1398
- skewY: 0,
1399
- scale: 1,
1400
- rotate: '0deg',
1401
- rotateY: '0deg',
1402
- rotateX: '0deg',
1403
- }
1404
-
1405
- function ensureBaseHasDefaults(base: ViewStyle, ...pseudos: (ViewStyle | null | undefined)[]) {
1406
- for (const pseudo of pseudos) {
1407
- if (!pseudo) continue
1408
- for (const key in pseudo) {
1409
- const val = pseudo[key]
1410
- // can we just use merge() here?
1411
- if (key === 'transform') {
1412
- if (typeof val === 'string') {
1413
- continue
1414
- }
1415
- for (const t of val) {
1416
- const tkey = Object.keys(t)[0]
1417
- const defaultVal = defaults[tkey]
1418
- const tDefaultVal = { [tkey]: defaultVal } as any
1419
- if (!base.transform) {
1420
- base.transform = [tDefaultVal]
1421
- } else {
1422
- if (!base.transform.find((x) => x[tkey])) {
1423
- base.transform.push(tDefaultVal)
1424
- }
1425
- }
1426
- }
1427
- } else {
1428
- if (!(key in base)) {
1429
- base[key] = defaults[key]
1430
- }
1431
- }
1432
- }
1433
- }
1434
- }
1435
-
1332
+ // TODO need to delete existing prop because of weirdness in how we do this
1333
+ // real solution is to handle all this in getSplitStyle and have animation drviers
1334
+ // return a useAnimationIsExiting() so we can pass that as part of state: { exiting: true }
1335
+ // then we can remove this function and the getStyle() altogether
1436
1336
  function merge(base: ViewStyle, next: ViewStyle) {
1437
- if (!next.transform || !base.transform) {
1438
- Object.assign(base, next)
1439
- return
1440
- }
1441
- const { transform, ...rest } = next
1442
- Object.assign(base, rest)
1443
- for (const t of transform) {
1444
- const key = Object.keys(t)[0]
1445
- const existing = base.transform.find((x) => key in x)
1446
- if (existing) {
1447
- existing[key] = t[key]
1337
+ for (const key in next) {
1338
+ const val = next[key]
1339
+ if (key in stylePropsTransform) {
1340
+ mergeTransform(base, key, val, true)
1448
1341
  } else {
1449
- base.transform.push(t)
1342
+ base[key] = val
1450
1343
  }
1451
1344
  }
1452
1345
  }