@tamagui/core 1.0.0-alpha.7 → 1.0.0-alpha.8

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 (128) hide show
  1. package/dist/cjs/constants/constants.js +50 -0
  2. package/dist/cjs/constants/constants.js.map +7 -0
  3. package/dist/cjs/constants/platform.js +43 -0
  4. package/dist/cjs/constants/platform.js.map +7 -0
  5. package/dist/cjs/constants/pseudos.js +25 -0
  6. package/dist/cjs/constants/pseudos.js.map +7 -0
  7. package/dist/cjs/constants/rnw.js +28 -0
  8. package/dist/cjs/constants/rnw.js.map +7 -0
  9. package/dist/cjs/createComponent.js +531 -0
  10. package/dist/cjs/createComponent.js.map +7 -0
  11. package/dist/cjs/createFont.js +50 -0
  12. package/dist/cjs/createFont.js.map +7 -0
  13. package/dist/cjs/createShorthands.js +16 -0
  14. package/dist/cjs/createShorthands.js.map +7 -0
  15. package/dist/cjs/createTamagui.js +206 -0
  16. package/dist/cjs/createTamagui.js.map +7 -0
  17. package/dist/cjs/createTheme.js +42 -0
  18. package/dist/cjs/createTheme.js.map +7 -0
  19. package/dist/cjs/createTokens.js +55 -0
  20. package/dist/cjs/createTokens.js.map +7 -0
  21. package/dist/cjs/createVariable.js +47 -0
  22. package/dist/cjs/createVariable.js.map +7 -0
  23. package/dist/cjs/helpers/addStylesUsingClassname.js +79 -0
  24. package/dist/cjs/helpers/addStylesUsingClassname.js.map +7 -0
  25. package/dist/cjs/helpers/createMediaStyle.js +56 -0
  26. package/dist/cjs/helpers/createMediaStyle.js.map +7 -0
  27. package/dist/cjs/helpers/createPropMapper.js +190 -0
  28. package/dist/cjs/helpers/createPropMapper.js.map +7 -0
  29. package/dist/cjs/helpers/createTamaguiProvider.js +74 -0
  30. package/dist/cjs/helpers/createTamaguiProvider.js.map +7 -0
  31. package/dist/cjs/helpers/extendStaticConfig.js +82 -0
  32. package/dist/cjs/helpers/extendStaticConfig.js.map +7 -0
  33. package/dist/cjs/helpers/fixNativeShadow.js +14 -0
  34. package/dist/cjs/helpers/fixNativeShadow.js.map +7 -0
  35. package/dist/cjs/helpers/fixNativeShadow.native.js +36 -0
  36. package/dist/cjs/helpers/fixNativeShadow.native.js.map +7 -0
  37. package/dist/cjs/helpers/getSplitStyles.js +180 -0
  38. package/dist/cjs/helpers/getSplitStyles.js.map +7 -0
  39. package/dist/cjs/helpers/getStylesAtomic.js +117 -0
  40. package/dist/cjs/helpers/getStylesAtomic.js.map +7 -0
  41. package/dist/cjs/helpers/getStylesAtomic.native.js +16 -0
  42. package/dist/cjs/helpers/getStylesAtomic.native.js.map +7 -0
  43. package/dist/cjs/helpers/insertStyleRule.js +46 -0
  44. package/dist/cjs/helpers/insertStyleRule.js.map +7 -0
  45. package/dist/cjs/helpers/isObj.js +13 -0
  46. package/dist/cjs/helpers/isObj.js.map +7 -0
  47. package/dist/cjs/helpers/isTamaguiElement.js +33 -0
  48. package/dist/cjs/helpers/isTamaguiElement.js.map +7 -0
  49. package/dist/cjs/helpers/matchMedia.js +24 -0
  50. package/dist/cjs/helpers/matchMedia.js.map +7 -0
  51. package/dist/cjs/helpers/matchMedia.native.js +31 -0
  52. package/dist/cjs/helpers/matchMedia.native.js.map +7 -0
  53. package/dist/cjs/helpers/themeable.js +78 -0
  54. package/dist/cjs/helpers/themeable.js.map +7 -0
  55. package/dist/cjs/helpers/validate.js +82 -0
  56. package/dist/cjs/helpers/validate.js.map +7 -0
  57. package/dist/cjs/hooks/useConstant.js +37 -0
  58. package/dist/cjs/hooks/useConstant.js.map +7 -0
  59. package/dist/cjs/hooks/useFeatures.js +100 -0
  60. package/dist/cjs/hooks/useFeatures.js.map +7 -0
  61. package/dist/cjs/hooks/useMedia.js +204 -0
  62. package/dist/cjs/hooks/useMedia.js.map +7 -0
  63. package/dist/cjs/hooks/usePressable.js +50 -0
  64. package/dist/cjs/hooks/usePressable.js.map +7 -0
  65. package/dist/cjs/hooks/useTheme.js +111 -0
  66. package/dist/cjs/hooks/useTheme.js.map +7 -0
  67. package/dist/cjs/index.js +55 -0
  68. package/dist/cjs/index.js.map +7 -0
  69. package/dist/cjs/static/postProcessStyles.js +40 -0
  70. package/dist/cjs/static/postProcessStyles.js.map +7 -0
  71. package/dist/cjs/static.js +34 -0
  72. package/dist/cjs/static.js.map +7 -0
  73. package/dist/cjs/styled.js +72 -0
  74. package/dist/cjs/styled.js.map +7 -0
  75. package/dist/cjs/types.js +4 -0
  76. package/dist/cjs/types.js.map +7 -0
  77. package/dist/cjs/views/Animated.js +129 -0
  78. package/dist/cjs/views/Animated.js.map +7 -0
  79. package/dist/cjs/views/Stack.js +51 -0
  80. package/dist/cjs/views/Stack.js.map +7 -0
  81. package/dist/cjs/views/Text.js +93 -0
  82. package/dist/cjs/views/Text.js.map +7 -0
  83. package/dist/cjs/views/TextAncestorContext.js +41 -0
  84. package/dist/cjs/views/TextAncestorContext.js.map +7 -0
  85. package/dist/cjs/views/Theme.js +88 -0
  86. package/dist/cjs/views/Theme.js.map +7 -0
  87. package/dist/cjs/views/ThemeContext.js +29 -0
  88. package/dist/cjs/views/ThemeContext.js.map +7 -0
  89. package/dist/cjs/views/ThemeInverse.js +48 -0
  90. package/dist/cjs/views/ThemeInverse.js.map +7 -0
  91. package/dist/cjs/views/ThemeManagerContext.js +84 -0
  92. package/dist/cjs/views/ThemeManagerContext.js.map +7 -0
  93. package/dist/cjs/views/ThemeProvider.js +67 -0
  94. package/dist/cjs/views/ThemeProvider.js.map +7 -0
  95. package/dist/createComponent.js +7 -3
  96. package/dist/createComponent.js.map +2 -2
  97. package/dist/createTamagui.js +4 -2
  98. package/dist/createTamagui.js.map +2 -2
  99. package/dist/helpers/createPropMapper.js +2 -2
  100. package/dist/helpers/createPropMapper.js.map +1 -1
  101. package/dist/helpers/getSplitStyles.js +12 -10
  102. package/dist/helpers/getSplitStyles.js.map +2 -2
  103. package/dist/helpers/matchMedia.js +3 -0
  104. package/dist/helpers/matchMedia.js.map +2 -2
  105. package/dist/helpers/matchMedia.native.js +1 -0
  106. package/dist/helpers/matchMedia.native.js.map +2 -2
  107. package/dist/hooks/useFeatures.js +39 -51
  108. package/dist/hooks/useFeatures.js.map +2 -2
  109. package/dist/hooks/useMedia.js.map +1 -1
  110. package/dist/hooks/useTheme.js +5 -9
  111. package/dist/hooks/useTheme.js.map +2 -2
  112. package/dist/index.cjs +51 -60
  113. package/dist/index.cjs.map +2 -2
  114. package/dist/views/ThemeManagerContext.js +4 -4
  115. package/dist/views/ThemeManagerContext.js.map +2 -2
  116. package/package.json +11 -10
  117. package/src/createComponent.tsx +7 -3
  118. package/src/createTamagui.ts +3 -1
  119. package/src/helpers/createPropMapper.ts +2 -2
  120. package/src/helpers/getSplitStyles.tsx +13 -10
  121. package/src/helpers/matchMedia.native.ts +3 -0
  122. package/src/helpers/matchMedia.ts +9 -1
  123. package/src/hooks/useFeatures.tsx +54 -53
  124. package/src/hooks/useMedia.tsx +1 -1
  125. package/src/hooks/useTheme.tsx +7 -8
  126. package/src/types.tsx +2 -2
  127. package/src/views/ThemeManagerContext.tsx +7 -5
  128. package/types.d.ts +7 -4
@@ -7,7 +7,7 @@ class ThemeManager {
7
7
  this.parentName = null;
8
8
  this.keys = new Map();
9
9
  this.listeners = new Map();
10
- this.callbacks = new Set();
10
+ this.themeListeners = new Set();
11
11
  this.theme = null;
12
12
  }
13
13
  setActiveTheme({
@@ -36,12 +36,12 @@ class ThemeManager {
36
36
  this.listeners.get(uuid)?.();
37
37
  }
38
38
  }
39
- this.callbacks.forEach((cb) => cb(this.name));
39
+ this.themeListeners.forEach((cb) => cb(this.name, this));
40
40
  }
41
41
  onChangeTheme(cb) {
42
- this.callbacks.add(cb);
42
+ this.themeListeners.add(cb);
43
43
  return () => {
44
- this.callbacks.delete(cb);
44
+ this.themeListeners.delete(cb);
45
45
  };
46
46
  }
47
47
  onUpdate(uuid, cb) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/views/ThemeManagerContext.tsx"],
4
- "sourcesContent": ["import { createContext } from 'react'\n\nexport class ThemeManager {\n name: string | null = 'light'\n parentName: string | null = null\n keys = new Map<any, Set<string>>()\n listeners = new Map<any, Function>()\n callbacks = new Set<Function>()\n theme = null\n\n setActiveTheme({\n name,\n theme,\n parentName,\n }: {\n parentName?: string | null\n name: string | null\n theme?: any\n }) {\n if (name === this.name) return\n this.name = name\n this.theme = theme\n this.parentName = parentName || null\n this.update()\n }\n\n track(uuid: any, keys: Set<string>) {\n if (!this.name) return\n this.keys.set(uuid, keys)\n }\n\n update() {\n if (!this.name) {\n this.keys.clear()\n }\n for (const [uuid, keys] of this.keys.entries()) {\n if (keys.size) {\n this.listeners.get(uuid)?.()\n }\n }\n this.callbacks.forEach((cb) => cb(this.name))\n }\n\n onChangeTheme(cb: (name: string | null) => void) {\n this.callbacks.add(cb)\n return () => {\n this.callbacks.delete(cb)\n }\n }\n\n onUpdate(uuid: any, cb: Function) {\n this.listeners.set(uuid, cb)\n return () => {\n this.listeners.delete(uuid)\n this.keys.delete(uuid)\n }\n }\n}\n\nexport const ThemeManagerContext = createContext<ThemeManager>(new ThemeManager())\n"],
5
- "mappings": ";;AAAA;AAEO,mBAAmB;AAAA,EAAnB,cAFP;AAGE,gBAAsB;AACtB,sBAA4B;AAC5B,gBAAO,IAAI;AACX,qBAAY,IAAI;AAChB,qBAAY,IAAI;AAChB,iBAAQ;AAAA;AAAA,EAER,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,KAKC;AACD,QAAI,SAAS,KAAK;AAAM;AACxB,SAAK,OAAO;AACZ,SAAK,QAAQ;AACb,SAAK,aAAa,cAAc;AAChC,SAAK;AAAA;AAAA,EAGP,MAAM,MAAW,MAAmB;AAClC,QAAI,CAAC,KAAK;AAAM;AAChB,SAAK,KAAK,IAAI,MAAM;AAAA;AAAA,EAGtB,SAAS;AACP,QAAI,CAAC,KAAK,MAAM;AACd,WAAK,KAAK;AAAA;AAEZ,eAAW,CAAC,MAAM,SAAS,KAAK,KAAK,WAAW;AAC9C,UAAI,KAAK,MAAM;AACb,aAAK,UAAU,IAAI;AAAA;AAAA;AAGvB,SAAK,UAAU,QAAQ,CAAC,OAAO,GAAG,KAAK;AAAA;AAAA,EAGzC,cAAc,IAAmC;AAC/C,SAAK,UAAU,IAAI;AACnB,WAAO,MAAM;AACX,WAAK,UAAU,OAAO;AAAA;AAAA;AAAA,EAI1B,SAAS,MAAW,IAAc;AAChC,SAAK,UAAU,IAAI,MAAM;AACzB,WAAO,MAAM;AACX,WAAK,UAAU,OAAO;AACtB,WAAK,KAAK,OAAO;AAAA;AAAA;AAAA;AApDhB;AAyDA,MAAM,sBAAsB,cAA4B,IAAI;",
4
+ "sourcesContent": ["import { createContext } from 'react'\n\ntype ThemeListener = (name: string | null, themeManager: ThemeManager) => void\n\nexport class ThemeManager {\n name: string | null = 'light'\n parentName: string | null = null\n keys = new Map<any, Set<string>>()\n listeners = new Map<any, Function>()\n themeListeners = new Set<ThemeListener>()\n theme = null\n\n setActiveTheme({\n name,\n theme,\n parentName,\n }: {\n parentName?: string | null\n name: string | null\n theme?: any\n }) {\n if (name === this.name) return\n this.name = name\n this.theme = theme\n this.parentName = parentName || null\n this.update()\n }\n\n track(uuid: any, keys: Set<string>) {\n if (!this.name) return\n this.keys.set(uuid, keys)\n }\n\n update() {\n if (!this.name) {\n this.keys.clear()\n }\n for (const [uuid, keys] of this.keys.entries()) {\n if (keys.size) {\n this.listeners.get(uuid)?.()\n }\n }\n this.themeListeners.forEach((cb) => cb(this.name, this))\n }\n\n onChangeTheme(cb: ThemeListener) {\n this.themeListeners.add(cb)\n return () => {\n this.themeListeners.delete(cb)\n }\n }\n\n onUpdate(uuid: any, cb: Function) {\n this.listeners.set(uuid, cb)\n return () => {\n this.listeners.delete(uuid)\n this.keys.delete(uuid)\n }\n }\n}\n\nexport const ThemeManagerContext = createContext<ThemeManager>(new ThemeManager())\n"],
5
+ "mappings": ";;AAAA;AAIO,mBAAmB;AAAA,EAAnB,cAJP;AAKE,gBAAsB;AACtB,sBAA4B;AAC5B,gBAAO,IAAI;AACX,qBAAY,IAAI;AAChB,0BAAiB,IAAI;AACrB,iBAAQ;AAAA;AAAA,EAER,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,KAKC;AACD,QAAI,SAAS,KAAK;AAAM;AACxB,SAAK,OAAO;AACZ,SAAK,QAAQ;AACb,SAAK,aAAa,cAAc;AAChC,SAAK;AAAA;AAAA,EAGP,MAAM,MAAW,MAAmB;AAClC,QAAI,CAAC,KAAK;AAAM;AAChB,SAAK,KAAK,IAAI,MAAM;AAAA;AAAA,EAGtB,SAAS;AACP,QAAI,CAAC,KAAK,MAAM;AACd,WAAK,KAAK;AAAA;AAEZ,eAAW,CAAC,MAAM,SAAS,KAAK,KAAK,WAAW;AAC9C,UAAI,KAAK,MAAM;AACb,aAAK,UAAU,IAAI;AAAA;AAAA;AAGvB,SAAK,eAAe,QAAQ,CAAC,OAAO,GAAG,KAAK,MAAM;AAAA;AAAA,EAGpD,cAAc,IAAmB;AAC/B,SAAK,eAAe,IAAI;AACxB,WAAO,MAAM;AACX,WAAK,eAAe,OAAO;AAAA;AAAA;AAAA,EAI/B,SAAS,MAAW,IAAc;AAChC,SAAK,UAAU,IAAI,MAAM;AACzB,WAAO,MAAM;AACX,WAAK,UAAU,OAAO;AACtB,WAAK,KAAK,OAAO;AAAA;AAAA;AAAA;AApDhB;AAyDA,MAAM,sBAAsB,cAA4B,IAAI;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,23 +1,24 @@
1
1
  {
2
2
  "name": "@tamagui/core",
3
- "version": "1.0.0-alpha.7",
3
+ "version": "1.0.0-alpha.8",
4
4
  "source": "src/index.ts",
5
- "main": "dist/index.cjs",
6
- "module": "dist/index.js",
5
+ "main": "dist/cjs",
6
+ "module": "dist",
7
7
  "typings": "types.d.ts",
8
8
  "scripts": {
9
- "build": "tamagui-build",
10
- "watch": "tamagui-build --watch"
9
+ "build": "tamagui-build --separate",
10
+ "watch": "tamagui-build --separate --watch"
11
11
  },
12
12
  "files": [
13
+ "_",
13
14
  "types.d.ts",
14
15
  "dist",
15
16
  "src"
16
17
  ],
17
18
  "dependencies": {
18
- "@tamagui/helpers": "^1.0.0-alpha.5",
19
- "@tamagui/use-debounce": "^1.0.0-alpha.6",
20
- "@tamagui/use-force-update": "^1.0.0-alpha.5",
19
+ "@tamagui/helpers": "^1.0.0-alpha.8",
20
+ "@tamagui/use-debounce": "^1.0.0-alpha.8",
21
+ "@tamagui/use-force-update": "^1.0.0-alpha.8",
21
22
  "react": "*",
22
23
  "react-dom": "*"
23
24
  },
@@ -25,7 +26,7 @@
25
26
  "react-native-web": "*"
26
27
  },
27
28
  "devDependencies": {
28
- "@tamagui/build": "^1.0.0-alpha.2",
29
+ "@tamagui/build": "^1.0.0-alpha.8",
29
30
  "@tamagui/ow": "^0.28.1",
30
31
  "@types/react": "^17.0.35",
31
32
  "esbuild": "^0.11.20",
@@ -37,5 +38,5 @@
37
38
  "engines": {
38
39
  "node": ">=16"
39
40
  },
40
- "gitHead": "13694a98d31535846699004532630788177537e9"
41
+ "gitHead": "ecb0afe6782276b1f2ece90320fd2748f2f05c93"
41
42
  }
@@ -477,7 +477,7 @@ export function createComponent<A extends Object = DefaultProps>(
477
477
  } else {
478
478
  if (!hasWarnedOnce) {
479
479
  hasWarnedOnce = true
480
- console.log('⚠️ we need to account for default styles for media queries')
480
+ console.log('⚠️ TODO account for default styles for media queries')
481
481
  }
482
482
  }
483
483
  // @ts-ignore
@@ -500,10 +500,14 @@ export function createComponent<A extends Object = DefaultProps>(
500
500
  const res = component as any as StaticComponent<A, void>
501
501
 
502
502
  // add extractable HoC
503
- res['extractable'] = (Component: any) => {
503
+ res['extractable'] = (Component: any, conf?: StaticConfig) => {
504
504
  Component['staticConfig'] = extendStaticConfig(res, {
505
+ ...conf,
505
506
  neverFlatten: true,
506
- defaultProps: Component.defaultProps,
507
+ defaultProps: {
508
+ ...Component.defaultProps,
509
+ ...conf?.defaultProps,
510
+ },
507
511
  })
508
512
  return Component
509
513
  }
@@ -28,7 +28,9 @@ export type CreateTamaguiProps = TamaguiProviderProps &
28
28
  let conf: TamaguiInternalConfig | null
29
29
 
30
30
  export const getHasConfigured = () => !!conf
31
- export const getTamaguiConfig = () => conf!
31
+
32
+ export const getTamagui = () => conf!
33
+ export const getTokens = () => conf!.tokensParsed
32
34
 
33
35
  type ConfigListener = (conf: TamaguiInternalConfig) => void
34
36
  const configListeners = new Set<ConfigListener>()
@@ -1,4 +1,4 @@
1
- import { getTamaguiConfig } from '../createTamagui'
1
+ import { getTamagui } from '../createTamagui'
2
2
  import { Variable } from '../createVariable'
3
3
  import { StaticConfig, TamaguiInternalConfig } from '../types'
4
4
  import { isObj } from './isObj'
@@ -9,7 +9,7 @@ export const createPropMapper = (c: StaticConfig) => {
9
9
  const defaultProps = c.defaultProps || {}
10
10
 
11
11
  return (key: string, value: any, theme: any, props: any) => {
12
- const conf = getTamaguiConfig()
12
+ const conf = getTamagui()
13
13
  if (!conf) {
14
14
  console.trace('no conf! err')
15
15
  return
@@ -8,7 +8,7 @@ import {
8
8
  import { ViewStyle } from 'react-native'
9
9
 
10
10
  import { isWeb } from '../constants/platform'
11
- import { mediaQueryConfig } from '../hooks/useMedia'
11
+ import { mediaQueryConfig, mediaState } from '../hooks/useMedia'
12
12
  import { StaticConfigParsed, ThemeObject } from '../types'
13
13
  import { createMediaStyle } from './createMediaStyle'
14
14
  import { fixNativeShadow } from './fixNativeShadow'
@@ -53,14 +53,15 @@ export const getSplitStyles = (
53
53
  const mediaProps = { ...props, ...valInit }
54
54
  // TODO media + hover
55
55
  const mediaStyle = getSubStyle(valInit, staticConfig, theme, props)
56
- const mediaStyles = getStylesAtomic(mediaStyle)
57
- if (process.env.NODE_ENV === 'development') {
58
- if (props['debug']) {
59
- console.log('mediaStyles', keyInit, { mediaProps, mediaStyle, mediaStyles })
56
+
57
+ if (isWeb) {
58
+ const mediaStyles = getStylesAtomic(mediaStyle)
59
+ if (process.env.NODE_ENV === 'development') {
60
+ if (props['debug']) {
61
+ console.log('mediaStyles', keyInit, { mediaProps, mediaStyle, mediaStyles })
62
+ }
60
63
  }
61
- }
62
- for (const style of mediaStyles) {
63
- if (isWeb) {
64
+ for (const style of mediaStyles) {
64
65
  const out = createMediaStyle(style, mediaKey, mediaQueryConfig)
65
66
  classNames = classNames || []
66
67
  classNames.push(out.identifier)
@@ -69,8 +70,10 @@ export const getSplitStyles = (
69
70
  if (process.env.NODE_ENV === 'development' && props['debug']) {
70
71
  console.log('mediaProp', style.identifier, out, mediaProps, mediaStyle, mediaStyles)
71
72
  }
72
- } else {
73
- console.log('TODO native media style logic')
73
+ }
74
+ } else {
75
+ if (mediaState[mediaKey]) {
76
+ style.push(mediaStyle)
74
77
  }
75
78
  }
76
79
  continue
@@ -1,3 +1,6 @@
1
1
  import MediaQueryList from '@expo/match-media/build/MediaQueryList.js'
2
2
 
3
3
  export const matchMedia = (media: string) => new MediaQueryList(media)
4
+
5
+ // @ts-ignore
6
+ globalThis['matchMedia'] = matchMedia
@@ -2,7 +2,15 @@ export const matchMedia =
2
2
  (typeof window !== 'undefined' && window.matchMedia) ||
3
3
  (function matchMediaFallback(query: string) {
4
4
  return {
5
- addListener() {},
5
+ addListener() {
6
+ if (
7
+ process.env.NODE_ENV === 'development' &&
8
+ !process.env.IS_STATIC &&
9
+ process.env.TAMAGUI_TARGET !== 'web'
10
+ ) {
11
+ console.log('warning: matchMedia not loading! Is native picking up .native.js files?')
12
+ }
13
+ },
6
14
  removeListener() {},
7
15
  matches: false,
8
16
  }
@@ -1,51 +1,66 @@
1
1
  import React from 'react'
2
2
 
3
3
  import { isWeb, useIsomorphicLayoutEffect } from '../constants/platform'
4
- import { addMediaQueryListener, removeMediaQueryListener } from './useMedia'
4
+ import { addMediaQueryListener, mediaState, removeMediaQueryListener } from './useMedia'
5
5
 
6
- // only needed on native
7
- // dynamic loading of features to avoid heavy views
6
+ type FeatureDefinition = {
7
+ isEnabled: (props: any) => boolean
8
+ Component: any
9
+ }
8
10
 
9
- const createDefinition = ({ Component, propNames }: { Component; propNames: string[] }) => ({
11
+ const createDefinition = ({
12
+ Component,
13
+ propNames,
14
+ }: {
15
+ Component: any
16
+ propNames: string[]
17
+ }): FeatureDefinition => ({
10
18
  isEnabled: (props: any) => propNames.some((name) => !!props[name]),
11
19
  Component,
12
20
  })
13
21
 
14
- const mediaQueryPropNames = [
15
- '$xs',
16
- '$sm',
17
- '$md',
18
- '$lg',
19
- '$xl',
20
- '$xxl',
21
- '$pointerCoarse',
22
- '$hoverNone',
23
- '$tall',
24
- '$short',
25
- '$gtSm',
26
- '$notXs',
27
- '$gtMd',
28
- '$gtLg',
29
- ]
22
+ let featureDefinitions: Record<string, FeatureDefinition> | null = null
30
23
 
31
- const featureDefinitions = {
32
- measureLayout: createDefinition({
33
- Component: (props) => {
34
- console.log('measure', props)
35
- return null
36
- },
37
- propNames: ['onLayout'],
38
- }),
24
+ export const useFeatures = (props: any, utils?: { forceUpdate?: Function }) => {
25
+ if (!featureDefinitions) {
26
+ featureDefinitions = loadFeatures()
27
+ }
28
+ const features: JSX.Element[] = []
29
+ for (const name in featureDefinitions) {
30
+ const { isEnabled, Component } = featureDefinitions[name]
31
+ if (isEnabled(props) && Component) {
32
+ features.push(<Component key={name} {...props} _utils={utils} />)
33
+ }
34
+ }
35
+ return features
36
+ }
39
37
 
40
- // will update the parent whenever media query changes
41
- mediaQuery: createDefinition({
42
- Component: (props) => {
43
- if (isWeb) {
44
- // no need for media queries are inserted and run in css
45
- return
46
- }
38
+ function loadFeatures(): Record<string, FeatureDefinition> {
39
+ return {
40
+ // TODO
41
+ // measureLayout: createDefinition({
42
+ // Component: (props) => {
43
+ // console.log('measure', props)
44
+ // return null
45
+ // },
46
+ // propNames: ['onLayout'],
47
+ // }),
48
+
49
+ // will update the parent whenever media query changes
50
+ // no need on web, media queries are inserted and run in css
51
+ ...(!isWeb && {
52
+ mediaQuery: loadMediaQueryFeature(),
53
+ }),
54
+ }
55
+ }
56
+
57
+ function loadMediaQueryFeature() {
58
+ const mediaPropNames = Object.keys(mediaState)
59
+
60
+ return createDefinition({
61
+ Component: (props: any) => {
62
+ const keys = mediaPropNames.flatMap((x) => (x in props ? x.slice(1) : []))
47
63
 
48
- const keys = mediaQueryPropNames.flatMap((x) => (x in props ? x.slice(1) : []))
49
64
  useIsomorphicLayoutEffect(() => {
50
65
  for (const key of keys) {
51
66
  addMediaQueryListener(key, props._utils.forceUpdate)
@@ -56,23 +71,9 @@ const featureDefinitions = {
56
71
  }
57
72
  }
58
73
  }, [keys.join(',')])
74
+
59
75
  return null
60
76
  },
61
- propNames: mediaQueryPropNames,
62
- }),
63
- }
64
-
65
- const featureNames = Object.keys(featureDefinitions)
66
- const numFeatures = featureNames.length
67
-
68
- export const useFeatures = (props: any, utils?: { forceUpdate?: Function }) => {
69
- const features: JSX.Element[] = []
70
- for (let i = 0; i < numFeatures; i++) {
71
- const name = featureNames[i]
72
- const { isEnabled, Component } = featureDefinitions[name] as any //FeatureDefinition
73
- if (isEnabled(props) && Component) {
74
- features.push(<Component key={name} {...props} _utils={utils} />)
75
- }
76
- }
77
- return features
77
+ propNames: mediaPropNames,
78
+ })
78
79
  }
@@ -1,7 +1,7 @@
1
1
  import { useForceUpdate } from '@tamagui/use-force-update'
2
2
  import { useRef } from 'react'
3
3
 
4
- import { useIsomorphicLayoutEffect } from '../constants/platform'
4
+ import { isWeb, useIsomorphicLayoutEffect } from '../constants/platform'
5
5
  import { matchMedia } from '../helpers/matchMedia'
6
6
  import {
7
7
  ConfigureMediaQueryOptions,
@@ -1,5 +1,5 @@
1
1
  import { useForceUpdate } from '@tamagui/use-force-update'
2
- import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'
2
+ import React, { useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'
3
3
 
4
4
  import { useIsomorphicLayoutEffect } from '../constants/platform'
5
5
  import { Variable } from '../createVariable'
@@ -24,17 +24,16 @@ const areEqualSets = (a: Set<string>, b: Set<string>) => {
24
24
  return true
25
25
  }
26
26
 
27
- export const useThemeName = () => {
27
+ export const useThemeName = (opts?: { parent?: true }) => {
28
28
  const parent = useContext(ThemeManagerContext)
29
29
  const [name, setName] = useState(parent.name)
30
- useEffect(() => {
31
- return parent.onChangeTheme((next) => {
32
- setName((prev) => {
33
- if (prev === next) return prev
34
- return next
35
- })
30
+
31
+ useLayoutEffect(() => {
32
+ return parent.onChangeTheme((next, manager) => {
33
+ setName(opts?.parent ? manager.parentName : next)
36
34
  })
37
35
  }, [parent])
36
+
38
37
  return name || 'light'
39
38
  }
40
39
 
package/src/types.tsx CHANGED
@@ -88,7 +88,7 @@ export type Shorthands = TamaguiConfig['shorthands']
88
88
  export type Media = TamaguiConfig['media']
89
89
  export type Themes = TamaguiConfig['themes']
90
90
  // themes
91
- export type ThemeName = keyof Themes extends `${infer Prefix}-light`
91
+ export type ThemeName = keyof Themes extends `${infer Prefix}-${string}`
92
92
  ? Prefix | keyof Themes
93
93
  : keyof Themes
94
94
  export type ThemeKeys = keyof ThemeObject
@@ -320,7 +320,7 @@ export type StaticComponent<
320
320
  * If you create a styled frame component this is a HoC to extract
321
321
  * styles from all parents.
322
322
  */
323
- extractable: <X>(a: X) => X
323
+ extractable: <X>(a: X, opts?: StaticConfig) => X
324
324
  }
325
325
 
326
326
  export type TamaguiProviderProps = Partial<Omit<ThemeProviderProps, 'children'>> & {
@@ -1,11 +1,13 @@
1
1
  import { createContext } from 'react'
2
2
 
3
+ type ThemeListener = (name: string | null, themeManager: ThemeManager) => void
4
+
3
5
  export class ThemeManager {
4
6
  name: string | null = 'light'
5
7
  parentName: string | null = null
6
8
  keys = new Map<any, Set<string>>()
7
9
  listeners = new Map<any, Function>()
8
- callbacks = new Set<Function>()
10
+ themeListeners = new Set<ThemeListener>()
9
11
  theme = null
10
12
 
11
13
  setActiveTheme({
@@ -38,13 +40,13 @@ export class ThemeManager {
38
40
  this.listeners.get(uuid)?.()
39
41
  }
40
42
  }
41
- this.callbacks.forEach((cb) => cb(this.name))
43
+ this.themeListeners.forEach((cb) => cb(this.name, this))
42
44
  }
43
45
 
44
- onChangeTheme(cb: (name: string | null) => void) {
45
- this.callbacks.add(cb)
46
+ onChangeTheme(cb: ThemeListener) {
47
+ this.themeListeners.add(cb)
46
48
  return () => {
47
- this.callbacks.delete(cb)
49
+ this.themeListeners.delete(cb)
48
50
  }
49
51
  }
50
52
 
package/types.d.ts CHANGED
@@ -86,7 +86,7 @@ export declare type Tokens = TamaguiConfig["tokens"];
86
86
  export declare type Shorthands = TamaguiConfig["shorthands"];
87
87
  export declare type Media = TamaguiConfig["media"];
88
88
  export declare type Themes = TamaguiConfig["themes"];
89
- export declare type ThemeName = keyof Themes extends `${infer Prefix}-light` ? Prefix | keyof Themes : keyof Themes;
89
+ export declare type ThemeName = keyof Themes extends `${infer Prefix}-${string}` ? Prefix | keyof Themes : keyof Themes;
90
90
  export declare type ThemeKeys = keyof ThemeObject;
91
91
  export declare type ThemeKeyVariables = `$${ThemeKeys}`;
92
92
  export declare type TamaguiInternalConfig<A extends GenericTokens = GenericTokens, B extends GenericThemes = GenericThemes, C extends GenericShorthands = GenericShorthands, D extends GenericMedia = GenericMedia> = CreateTamaguiConfig<A, B, C, D> & {
@@ -199,7 +199,7 @@ export declare type TextProps = Omit<ReactTextProps, "style"> & TextStyleProps &
199
199
  export declare type StaticComponent<Props = any, VariantProps = any, StaticConfParsed = StaticConfigParsed, ParentVariantProps = any> = React.FunctionComponent<Props> & {
200
200
  staticConfig: StaticConfParsed;
201
201
  variantProps?: VariantProps;
202
- extractable: <X>(a: X) => X;
202
+ extractable: <X>(a: X, opts?: StaticConfig) => X;
203
203
  };
204
204
  export declare type TamaguiProviderProps = Partial<Omit<ThemeProviderProps, "children">> & {
205
205
  initialWindowMetrics?: any;
@@ -353,7 +353,7 @@ export declare type CreateTamaguiProps = TamaguiProviderProps & Omit<GenericTama
353
353
  mediaQueryDefaultActive?: MediaQueryKey[];
354
354
  };
355
355
  export declare const getHasConfigured: () => boolean;
356
- export declare const getTamaguiConfig: () => TamaguiInternalConfig<CreateTokens, {
356
+ export declare const getTamagui: () => TamaguiInternalConfig<CreateTokens, {
357
357
  [key: string]: {
358
358
  bg: string | Variable;
359
359
  bg2: string | Variable;
@@ -373,6 +373,7 @@ export declare const getTamaguiConfig: () => TamaguiInternalConfig<CreateTokens,
373
373
  [key: string]: string | number;
374
374
  };
375
375
  }>;
376
+ export declare const getTokens: () => CreateTokens;
376
377
  export declare type ConfigListener = (conf: TamaguiInternalConfig) => void;
377
378
  export declare const onConfiguredOnce: (cb: ConfigListener) => void;
378
379
  export declare function createTamagui<Conf extends CreateTamaguiProps>(config: Conf): Conf extends CreateTamaguiConfig<infer A, infer B, infer C, infer D> ? TamaguiInternalConfig<A, B, C, D> : unknown;
@@ -509,7 +510,9 @@ export declare const useMedia: () => {
509
510
  [x: string]: boolean;
510
511
  };
511
512
  export declare function mediaObjectToString(query: string | MediaQueryObject): string;
512
- export declare const useThemeName: () => string;
513
+ export declare const useThemeName: (opts?: {
514
+ parent?: true | undefined;
515
+ } | undefined) => string;
513
516
  export declare const useDefaultThemeName: () => string | number;
514
517
  export declare const useTheme: () => {
515
518
  bg: string | Variable;