@tamagui/core 1.0.1-beta.184 → 1.0.1-beta.186

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tamagui/core",
3
- "version": "1.0.1-beta.184",
3
+ "version": "1.0.1-beta.186",
4
4
  "source": "src/index.ts",
5
5
  "main": "dist/cjs",
6
6
  "module": "dist/esm",
@@ -28,14 +28,14 @@
28
28
  ],
29
29
  "dependencies": {
30
30
  "@expo/match-media": "^0.3.0",
31
- "@tamagui/compose-refs": "^1.0.1-beta.184",
32
- "@tamagui/helpers": "^1.0.1-beta.184",
33
- "@tamagui/normalize-css-color-lite": "^1.0.1-beta.184",
34
- "@tamagui/rnw": "^1.0.1-beta.184",
35
- "@tamagui/rnw-lite": "^1.0.1-beta.184",
36
- "@tamagui/use-debounce": "^1.0.1-beta.184",
37
- "@tamagui/use-event": "^1.0.1-beta.184",
38
- "@tamagui/use-force-update": "^1.0.1-beta.184",
31
+ "@tamagui/compose-refs": "^1.0.1-beta.186",
32
+ "@tamagui/helpers": "^1.0.1-beta.186",
33
+ "@tamagui/normalize-css-color-lite": "^1.0.1-beta.186",
34
+ "@tamagui/rnw": "^1.0.1-beta.186",
35
+ "@tamagui/rnw-lite": "^1.0.1-beta.186",
36
+ "@tamagui/use-debounce": "^1.0.1-beta.186",
37
+ "@tamagui/use-event": "^1.0.1-beta.186",
38
+ "@tamagui/use-force-update": "^1.0.1-beta.186",
39
39
  "expo-screen-orientation": "^4.3.0",
40
40
  "hyphenate-style-name": "^1.0.4"
41
41
  },
@@ -44,7 +44,7 @@
44
44
  "react-dom": "*"
45
45
  },
46
46
  "devDependencies": {
47
- "@tamagui/build": "^1.0.1-beta.184",
47
+ "@tamagui/build": "^1.0.1-beta.186",
48
48
  "@types/node": "^16.11.9",
49
49
  "@types/react": "^18.0.15",
50
50
  "csstype": "^3.0.10",
@@ -23,3 +23,19 @@ export const useIsomorphicLayoutEffect = isRSC ? idFn : isServer ? useEffect : u
23
23
  export const isChrome = typeof navigator !== 'undefined' && /Chrome/.test(navigator.userAgent || '')
24
24
  export const isWebTouchable = isClient && 'ontouchstart' in window
25
25
  export const isTouchable = !isWeb || isWebTouchable
26
+
27
+ if (process.env.NODE_ENV === 'development') {
28
+ if (!process.env.TAMAGUI_TARGET) {
29
+ // eslint-disable-next-line no-console
30
+ console.warn(`Must set TAMAGUI_TARGET to "web" or "native"`)
31
+ } else if (
32
+ isClient &&
33
+ process.env.TAMAGUI_TARGET !== 'web' &&
34
+ process.env.TAMAGUI_IGNORE_TARGET !== '1'
35
+ ) {
36
+ // eslint-disable-next-line no-console
37
+ console.warn(
38
+ `Must set TAMAGUI_TARGET to "web" for web apps - if you have window defined outside of the browser, set TAMAGUI_IGNORE_TARGET=1 to hide this`
39
+ )
40
+ }
41
+ }
@@ -42,11 +42,7 @@ import { getAllSelectors } from './helpers/insertStyleRule'
42
42
  import { mergeProps } from './helpers/mergeProps'
43
43
  import { proxyThemeVariables } from './helpers/proxyThemeVariables'
44
44
  import { useShallowSetState } from './helpers/useShallowSetState'
45
- import {
46
- addMediaQueryListener,
47
- getInitialMediaState,
48
- removeMediaQueryListener,
49
- } from './hooks/useMedia'
45
+ import { addMediaQueryListener, getCurrentMediaState } from './hooks/useMedia'
50
46
  import { usePressable } from './hooks/usePressable'
51
47
  import { useServerRef, useServerState } from './hooks/useServerHooks'
52
48
  import { getThemeManager, useTheme } from './hooks/useTheme'
@@ -1103,7 +1099,7 @@ export function createComponent<
1103
1099
  // only used by enterStyle
1104
1100
  mounted: false,
1105
1101
  animation: null,
1106
- mediaState: getInitialMediaState(),
1102
+ mediaState: getCurrentMediaState(),
1107
1103
  })
1108
1104
  }
1109
1105
 
@@ -1,4 +1,4 @@
1
- import { useEffect, useMemo, useState } from 'react'
1
+ import { startTransition, useEffect, useMemo, useState } from 'react'
2
2
 
3
3
  import { useIsomorphicLayoutEffect } from '../constants/platform'
4
4
  import { matchMedia } from '../helpers/matchMedia'
@@ -10,6 +10,7 @@ import {
10
10
  TamaguiInternalConfig,
11
11
  } from '../types'
12
12
  import { useSafeRef } from './useSafeRef'
13
+ import { getConfig } from '..'
13
14
 
14
15
  export const mediaState: MediaQueryState =
15
16
  // development time safeguard
@@ -51,10 +52,19 @@ export const getMedia = () => {
51
52
  return mediaState
52
53
  }
53
54
 
54
- const dispose = new Set<Function>()
55
-
56
55
  // for SSR capture it at time of startup
56
+ let currentMediaState: MediaQueryState | null
57
57
  let initialMediaState: MediaQueryState | null
58
+ // fairly concurrent mode sketchy but such an edge case ok for now
59
+ let hasFinishedInitialRender = false
60
+ export const getCurrentMediaState = () => {
61
+ if (getConfig().disableSSR || hasFinishedInitialRender) {
62
+ return currentMediaState || {}
63
+ }
64
+ return initialMediaState || {}
65
+ }
66
+
67
+ const dispose = new Set<Function>()
58
68
 
59
69
  export const configureMedia = (config: TamaguiInternalConfig) => {
60
70
  const { media, mediaQueryDefaultActive } = config
@@ -63,14 +73,13 @@ export const configureMedia = (config: TamaguiInternalConfig) => {
63
73
  mediaState[key] = mediaQueryDefaultActive?.[key] || false
64
74
  }
65
75
  Object.assign(mediaQueryConfig, media)
66
- initialMediaState = { ...mediaState }
76
+ currentMediaState = { ...mediaState }
77
+ initialMediaState = currentMediaState
67
78
  if (config.disableSSR) {
68
79
  setupMediaListeners()
69
80
  }
70
81
  }
71
82
 
72
- export const getInitialMediaState = () => initialMediaState
73
-
74
83
  function unlisten() {
75
84
  dispose.forEach((cb) => cb())
76
85
  dispose.clear()
@@ -93,31 +102,39 @@ function setupMediaListeners() {
93
102
  // hmr, undo existing before re-binding
94
103
  unlisten()
95
104
 
96
- for (const key in mediaQueryConfig) {
97
- const str = mediaObjectToString(mediaQueryConfig[key])
98
- const getMatch = () => matchMedia(str)
99
- const match = getMatch()
100
- if (!match) {
101
- throw new Error('⚠️ No match')
102
- }
103
- // react native needs these deprecated apis for now
104
- match.addListener(update)
105
- dispose.add(() => match.removeListener(update))
106
-
107
- update()
108
-
109
- function update() {
110
- const next = !!getMatch().matches
111
- if (next === mediaState[key]) return
112
- mediaState[key] = next
113
- const listeners = mediaQueryListeners[key]
114
- if (listeners?.size) {
115
- listeners.forEach((cb) => cb(next))
105
+ // theoretically this should make media reactions smoother but potentially delayed?
106
+ // but i believe consistent, so that's a nicer default (we'll see)
107
+ startTransition(() => {
108
+ for (const key in mediaQueryConfig) {
109
+ const str = mediaObjectToString(mediaQueryConfig[key])
110
+ const getMatch = () => matchMedia(str)
111
+ const match = getMatch()
112
+ if (!match) {
113
+ throw new Error('⚠️ No match')
114
+ }
115
+ // react native needs these deprecated apis for now
116
+ match.addListener(update)
117
+ dispose.add(() => match.removeListener(update))
118
+
119
+ update()
120
+
121
+ function update() {
122
+ const next = !!getMatch().matches
123
+ if (next === mediaState[key]) return
124
+ mediaState[key] = next
125
+ currentMediaState = { ...mediaState }
126
+ const listeners = mediaQueryListeners[key]
127
+ if (listeners?.size) {
128
+ listeners.forEach((cb) => cb(next))
129
+ }
116
130
  }
117
131
  }
118
- }
132
+ })
119
133
  }
120
134
 
135
+ const onIdle =
136
+ typeof requestIdleCallback === 'undefined' ? (cb) => setTimeout(cb, 100) : requestIdleCallback
137
+
121
138
  export function useMediaQueryListeners(config: TamaguiInternalConfig) {
122
139
  if (config.disableSSR) {
123
140
  return
@@ -125,6 +142,11 @@ export function useMediaQueryListeners(config: TamaguiInternalConfig) {
125
142
 
126
143
  useEffect(() => {
127
144
  setupMediaListeners()
145
+
146
+ onIdle(() => {
147
+ hasFinishedInitialRender = true
148
+ })
149
+
128
150
  return unlisten
129
151
  }, [])
130
152
  }
@@ -132,7 +154,7 @@ export function useMediaQueryListeners(config: TamaguiInternalConfig) {
132
154
  export function useMedia(): {
133
155
  [key in MediaQueryKey]: boolean
134
156
  } {
135
- const [state, setState] = useState(initialMediaState || {})
157
+ const [state, setState] = useState(getCurrentMediaState())
136
158
  const keys = useSafeRef({} as Record<string, boolean>)
137
159
 
138
160
  function updateState() {
@@ -161,7 +183,7 @@ export function useMedia(): {
161
183
  new Proxy(state, {
162
184
  get(_, key: string) {
163
185
  if (process.env.NODE_ENV === 'development') {
164
- if (!initialMediaState) {
186
+ if (!currentMediaState) {
165
187
  throw new Error(
166
188
  `To use useMedia() you must pass in media configuration to createTamagui, none was found.`
167
189
  )
@@ -5,8 +5,8 @@ export declare function addMediaQueryListener(key: MediaQueryKey, cb: MediaListe
5
5
  export declare function removeMediaQueryListener(key: MediaQueryKey, cb: MediaListener): void;
6
6
  export declare const mediaQueryConfig: MediaQueries;
7
7
  export declare const getMedia: () => MediaQueryState;
8
+ export declare const getCurrentMediaState: () => MediaQueryState;
8
9
  export declare const configureMedia: (config: TamaguiInternalConfig) => void;
9
- export declare const getInitialMediaState: () => MediaQueryState | null;
10
10
  export declare function useMediaQueryListeners(config: TamaguiInternalConfig): void;
11
11
  export declare function useMedia(): {
12
12
  [key in MediaQueryKey]: boolean;