@tamagui/core 1.0.1-beta.193 → 1.0.1-beta.195
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/dist/cjs/Tamagui.js +4 -2
- package/dist/cjs/Tamagui.js.map +2 -2
- package/dist/cjs/config.js +1 -2
- package/dist/cjs/config.js.map +2 -2
- package/dist/cjs/constants/constants.js +13 -8
- package/dist/cjs/constants/constants.js.map +2 -2
- package/dist/cjs/contexts/TextAncestorContext.js +3 -16
- package/dist/cjs/contexts/TextAncestorContext.js.map +3 -3
- package/dist/cjs/createComponent.js +204 -294
- package/dist/cjs/createComponent.js.map +2 -2
- package/dist/cjs/createTamagui.js +15 -16
- package/dist/cjs/createTamagui.js.map +3 -3
- package/dist/cjs/createVariable.js +1 -2
- package/dist/cjs/createVariable.js.map +2 -2
- package/dist/cjs/helpers/ThemeManager.js +7 -14
- package/dist/cjs/helpers/ThemeManager.js.map +2 -2
- package/dist/cjs/helpers/{createShallowUpdate.js → cache.js} +20 -21
- package/dist/cjs/helpers/cache.js.map +7 -0
- package/dist/cjs/helpers/createMediaStyle.js +14 -8
- package/dist/cjs/helpers/createMediaStyle.js.map +2 -2
- package/dist/cjs/helpers/extendStaticConfig.js +0 -1
- package/dist/cjs/helpers/extendStaticConfig.js.map +2 -2
- package/dist/cjs/helpers/getSplitStyles.js +212 -93
- package/dist/cjs/helpers/getSplitStyles.js.map +3 -3
- package/dist/cjs/helpers/getStylesAtomic.js +16 -36
- package/dist/cjs/helpers/getStylesAtomic.js.map +3 -3
- package/dist/cjs/helpers/insertStyleRule.js +14 -6
- package/dist/cjs/helpers/insertStyleRule.js.map +2 -2
- package/dist/cjs/helpers/matchMedia.js.map +2 -2
- package/dist/cjs/helpers/mergeTransform.js.map +1 -1
- package/dist/cjs/helpers/normalizeValueWithProperty.js +32 -2
- package/dist/cjs/helpers/normalizeValueWithProperty.js.map +2 -2
- package/dist/cjs/helpers/useShallowSetState.js.map +2 -2
- package/dist/cjs/hooks/getThemeUnwrapped.js +1 -3
- package/dist/cjs/hooks/getThemeUnwrapped.js.map +2 -2
- package/dist/cjs/hooks/useElementLayout.js +92 -0
- package/dist/cjs/hooks/useElementLayout.js.map +7 -0
- package/dist/cjs/hooks/useIsTouchDevice.js +2 -10
- package/dist/cjs/hooks/useIsTouchDevice.js.map +2 -2
- package/dist/cjs/hooks/useMedia.js +77 -84
- package/dist/cjs/hooks/useMedia.js.map +2 -2
- package/dist/cjs/hooks/useMedia.test.js +2 -0
- package/dist/cjs/{helpers/validate.js.map → hooks/useMedia.test.js.map} +0 -0
- package/dist/cjs/hooks/usePressablePressResponder.js +370 -0
- package/dist/cjs/hooks/usePressablePressResponder.js.map +7 -0
- package/dist/cjs/hooks/useSafeRef.js +13 -15
- package/dist/cjs/hooks/useSafeRef.js.map +2 -2
- package/dist/cjs/hooks/useTheme.js +3 -4
- package/dist/cjs/hooks/useTheme.js.map +2 -2
- package/dist/cjs/index.js +1 -17
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/static.js +0 -20
- package/dist/cjs/static.js.map +2 -2
- package/dist/cjs/styled.js +4 -22
- package/dist/cjs/styled.js.map +2 -2
- package/dist/cjs/types.js.map +1 -1
- package/dist/cjs/{hooks/useIsSSR.js → views/AbsoluteFill.js} +18 -23
- package/dist/cjs/views/AbsoluteFill.js.map +7 -0
- package/dist/cjs/views/AbsoluteFill.native.js +45 -0
- package/dist/cjs/views/AbsoluteFill.native.js.map +7 -0
- package/dist/cjs/views/FontLanguage.native.js.map +2 -2
- package/dist/cjs/views/Stack.js.map +1 -1
- package/dist/cjs/views/TamaguiProvider.js +3 -2
- package/dist/cjs/views/TamaguiProvider.js.map +2 -2
- package/dist/cjs/views/Text.js.map +1 -1
- package/dist/cjs/views/ThemeReset.js +10 -10
- package/dist/cjs/views/ThemeReset.js.map +2 -2
- package/dist/esm/Tamagui.js +4 -2
- package/dist/esm/Tamagui.js.map +2 -2
- package/dist/esm/config.js +1 -2
- package/dist/esm/config.js.map +2 -2
- package/dist/esm/constants/constants.js +11 -7
- package/dist/esm/constants/constants.js.map +2 -2
- package/dist/esm/contexts/TextAncestorContext.js +2 -13
- package/dist/esm/contexts/TextAncestorContext.js.map +2 -2
- package/dist/esm/createComponent.js +203 -296
- package/dist/esm/createComponent.js.map +2 -2
- package/dist/esm/createTamagui.js +15 -16
- package/dist/esm/createTamagui.js.map +3 -3
- package/dist/esm/createVariable.js +1 -2
- package/dist/esm/createVariable.js.map +2 -2
- package/dist/esm/helpers/ThemeManager.js +7 -14
- package/dist/esm/helpers/ThemeManager.js.map +2 -2
- package/dist/esm/helpers/cache.js +18 -0
- package/dist/esm/helpers/cache.js.map +7 -0
- package/dist/esm/helpers/createMediaStyle.js +14 -8
- package/dist/esm/helpers/createMediaStyle.js.map +2 -2
- package/dist/esm/helpers/extendStaticConfig.js +0 -1
- package/dist/esm/helpers/extendStaticConfig.js.map +2 -2
- package/dist/esm/helpers/getSplitStyles.js +221 -94
- package/dist/esm/helpers/getSplitStyles.js.map +3 -3
- package/dist/esm/helpers/getStylesAtomic.js +13 -26
- package/dist/esm/helpers/getStylesAtomic.js.map +2 -2
- package/dist/esm/helpers/insertStyleRule.js +14 -6
- package/dist/esm/helpers/insertStyleRule.js.map +2 -2
- package/dist/esm/helpers/matchMedia.js.map +2 -2
- package/dist/esm/helpers/mergeTransform.js.map +1 -1
- package/dist/esm/helpers/normalizeValueWithProperty.js +30 -1
- package/dist/esm/helpers/normalizeValueWithProperty.js.map +2 -2
- package/dist/esm/helpers/useShallowSetState.js.map +2 -2
- package/dist/esm/hooks/getThemeUnwrapped.js +1 -3
- package/dist/esm/hooks/getThemeUnwrapped.js.map +2 -2
- package/dist/esm/hooks/useElementLayout.js +66 -0
- package/dist/esm/hooks/useElementLayout.js.map +7 -0
- package/dist/esm/hooks/useIsTouchDevice.js +3 -11
- package/dist/esm/hooks/useIsTouchDevice.js.map +2 -2
- package/dist/esm/hooks/useMedia.js +74 -83
- package/dist/esm/hooks/useMedia.js.map +2 -2
- package/dist/esm/hooks/useMedia.test.js +1 -0
- package/dist/esm/{helpers/validate.js.map → hooks/useMedia.test.js.map} +0 -0
- package/dist/esm/hooks/usePressablePressResponder.js +346 -0
- package/dist/esm/hooks/usePressablePressResponder.js.map +7 -0
- package/dist/esm/hooks/useSafeRef.js +13 -15
- package/dist/esm/hooks/useSafeRef.js.map +2 -2
- package/dist/esm/hooks/useTheme.js +3 -4
- package/dist/esm/hooks/useTheme.js.map +2 -2
- package/dist/esm/index.js +1 -14
- package/dist/esm/index.js.map +2 -2
- package/dist/esm/static.js +0 -14
- package/dist/esm/static.js.map +2 -2
- package/dist/esm/styled.js +4 -22
- package/dist/esm/styled.js.map +2 -2
- package/dist/esm/views/AbsoluteFill.js +17 -0
- package/dist/esm/views/AbsoluteFill.js.map +7 -0
- package/dist/esm/views/AbsoluteFill.native.js +21 -0
- package/dist/esm/views/AbsoluteFill.native.js.map +7 -0
- package/dist/esm/views/FontLanguage.native.js.map +2 -2
- package/dist/esm/views/Stack.js.map +1 -1
- package/dist/esm/views/TamaguiProvider.js +5 -4
- package/dist/esm/views/TamaguiProvider.js.map +2 -2
- package/dist/esm/views/Text.js.map +1 -1
- package/dist/esm/views/ThemeReset.js +10 -10
- package/dist/esm/views/ThemeReset.js.map +2 -2
- package/package.json +14 -14
- package/src/Tamagui.ts +7 -3
- package/src/config.ts +2 -3
- package/src/constants/constants.ts +10 -6
- package/src/contexts/TextAncestorContext.tsx +1 -8
- package/src/createComponent.tsx +256 -421
- package/src/createTamagui.ts +16 -19
- package/src/createVariable.ts +1 -3
- package/src/helpers/ThemeManager.tsx +7 -15
- package/src/helpers/cache.ts +18 -0
- package/src/helpers/createMediaStyle.ts +16 -9
- package/src/helpers/extendStaticConfig.ts +0 -1
- package/src/helpers/getSplitStyles.tsx +257 -151
- package/src/helpers/getStylesAtomic.ts +14 -34
- package/src/helpers/insertStyleRule.tsx +16 -8
- package/src/helpers/matchMedia.ts +1 -0
- package/src/helpers/mergeTransform.ts +1 -1
- package/src/helpers/normalizeValueWithProperty.ts +30 -0
- package/src/helpers/useShallowSetState.tsx +0 -1
- package/src/hooks/getThemeUnwrapped.tsx +1 -2
- package/src/hooks/useElementLayout.tsx +90 -0
- package/src/hooks/useIsTouchDevice.tsx +3 -17
- package/src/hooks/useMedia.tsx +80 -87
- package/src/hooks/useSafeRef.ts +17 -18
- package/src/hooks/useTheme.tsx +4 -4
- package/src/index.ts +1 -11
- package/src/static.ts +0 -10
- package/src/styled.tsx +15 -33
- package/src/types.tsx +58 -55
- package/src/views/FontLanguage.native.tsx +1 -0
- package/src/views/Stack.tsx +1 -1
- package/src/views/TamaguiProvider.tsx +5 -5
- package/src/views/Text.tsx +1 -1
- package/src/views/ThemeReset.tsx +11 -11
- package/types/Tamagui.d.ts +6 -4
- package/types/constants/constants.d.ts +14 -3
- package/types/contexts/TextAncestorContext.d.ts +1 -3
- package/types/createComponent.d.ts +0 -15
- package/types/helpers/ThemeManager.d.ts +2 -3
- package/types/helpers/cache.d.ts +12 -0
- package/types/helpers/calc.d.ts +0 -16
- package/types/helpers/createMediaStyle.d.ts +1 -1
- package/types/helpers/getSplitStyles.d.ts +6 -10
- package/types/helpers/getStylesAtomic.d.ts +1 -5
- package/types/helpers/insertStyleRule.d.ts +2 -2
- package/types/helpers/mergeTransform.d.ts +1 -1
- package/types/helpers/normalizeValueWithProperty.d.ts +1 -0
- package/types/hooks/useElementLayout.d.ts +27 -0
- package/types/hooks/useMedia.d.ts +3 -1
- package/types/hooks/useMedia.test.d.ts +1 -0
- package/types/hooks/usePressablePressResponder.d.ts +84 -0
- package/types/index.d.ts +1 -11
- package/types/static.d.ts +0 -1
- package/types/types.d.ts +42 -44
- package/types/views/AbsoluteFill.d.ts +5 -0
- package/types/views/AbsoluteFill.native.d.ts +3 -0
- package/types/views/Stack.d.ts +1 -1
- package/types/views/Text.d.ts +1 -1
- package/dist/cjs/constants/platform.js +0 -74
- package/dist/cjs/constants/platform.js.map +0 -7
- package/dist/cjs/constants/platform.native.js +0 -62
- package/dist/cjs/constants/platform.native.js.map +0 -7
- package/dist/cjs/helpers/createShallowUpdate.js.map +0 -7
- package/dist/cjs/helpers/validate.js +0 -2
- package/dist/cjs/hooks/useDidFinishSSR.js +0 -60
- package/dist/cjs/hooks/useDidFinishSSR.js.map +0 -7
- package/dist/cjs/hooks/useIsSSR.js.map +0 -7
- package/dist/esm/constants/platform.js +0 -39
- package/dist/esm/constants/platform.js.map +0 -7
- package/dist/esm/constants/platform.native.js +0 -28
- package/dist/esm/constants/platform.native.js.map +0 -7
- package/dist/esm/helpers/createShallowUpdate.js +0 -20
- package/dist/esm/helpers/createShallowUpdate.js.map +0 -7
- package/dist/esm/helpers/validate.js +0 -1
- package/dist/esm/hooks/useDidFinishSSR.js +0 -35
- package/dist/esm/hooks/useDidFinishSSR.js.map +0 -7
- package/dist/esm/hooks/useIsSSR.js +0 -22
- package/dist/esm/hooks/useIsSSR.js.map +0 -7
- package/src/helpers/assignNativePropsToWeb.tsx +0 -178
- package/src/helpers/calc.ts +0 -68
- package/src/helpers/getFont.tsx +0 -43
- package/src/helpers/getStackSize.ts +0 -22
- package/src/helpers/startTransition.ts +0 -4
- package/src/hooks/useConstant.tsx +0 -19
- package/src/hooks/useIsMounted.ts +0 -16
- package/src/hooks/usePressable.tsx +0 -9
- package/src/hooks/useUnmountEffect.ts +0 -5
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { StyleObject, simpleHash } from '@tamagui/helpers'
|
|
7
|
-
import
|
|
8
|
-
import type { TextStyle, ViewStyle } from 'react-native'
|
|
7
|
+
import type { TextStyle, ViewStyle } from '@tamagui/types-react-native'
|
|
9
8
|
|
|
10
9
|
import { getConfig } from '../config'
|
|
11
10
|
import { TamaguiInternalConfig } from '../types'
|
|
11
|
+
import { Style, cache } from './cache'
|
|
12
12
|
import { defaultOffset } from './expandStyles'
|
|
13
13
|
import { normalizeValueWithProperty } from './normalizeValueWithProperty.js'
|
|
14
14
|
import { PseudoDescriptor, pseudoDescriptors } from './pseudoDescriptors'
|
|
@@ -166,31 +166,23 @@ const mapTransform = (transform) => {
|
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
// cache
|
|
170
|
-
type Value = Object | Array<any> | string | number
|
|
171
|
-
export type Style = { [key: string]: Value }
|
|
172
|
-
class Cache {
|
|
173
|
-
values: Record<string, any> = {}
|
|
174
|
-
|
|
175
|
-
get(key: string, valStr: string) {
|
|
176
|
-
return this.values[key]?.[valStr]
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
set(key: string, valStr: string, object: any) {
|
|
180
|
-
this.values[key] ??= {}
|
|
181
|
-
this.values[key][valStr] = object
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
const cache = new Cache()
|
|
185
|
-
|
|
186
169
|
function createDeclarationBlock(style: Style, important = false) {
|
|
187
|
-
let
|
|
170
|
+
let next = ''
|
|
188
171
|
for (const key in style) {
|
|
189
172
|
const prop = hyphenateStyleName(key)
|
|
190
173
|
const value = style[key]
|
|
191
|
-
|
|
174
|
+
next += `${prop}:${value}${important ? ` !important` : ''};`
|
|
192
175
|
}
|
|
193
|
-
return `{${
|
|
176
|
+
return `{${next}}`
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const hcache = {}
|
|
180
|
+
const toHyphenLower = (match: string) => `-${match.toLowerCase()}`
|
|
181
|
+
const hyphenateStyleName = (key: string) => {
|
|
182
|
+
let val = hcache[key]
|
|
183
|
+
if (val) return val
|
|
184
|
+
hcache[key] = val = key.replace(/[A-Z]/g, toHyphenLower)
|
|
185
|
+
return val
|
|
194
186
|
}
|
|
195
187
|
|
|
196
188
|
const pseudoSelectorPrefixes = (() => {
|
|
@@ -239,7 +231,6 @@ function createAtomicRules(
|
|
|
239
231
|
}
|
|
240
232
|
|
|
241
233
|
// Polyfill for additional 'pointer-events' values
|
|
242
|
-
// See d13f78622b233a0afc0c7a200c0a0792c8ca9e58
|
|
243
234
|
case 'pointerEvents': {
|
|
244
235
|
let finalValue = value
|
|
245
236
|
if (value === 'auto' || value === 'box-only') {
|
|
@@ -258,17 +249,6 @@ function createAtomicRules(
|
|
|
258
249
|
break
|
|
259
250
|
}
|
|
260
251
|
|
|
261
|
-
// Polyfill for draft spec
|
|
262
|
-
// https://drafts.csswg.org/css-scrollbars-1/
|
|
263
|
-
case 'scrollbarWidth': {
|
|
264
|
-
if (value === 'none') {
|
|
265
|
-
rules.push(`${selector}::-webkit-scrollbar{display:none}`)
|
|
266
|
-
}
|
|
267
|
-
const block = createDeclarationBlock({ scrollbarWidth: value }, important)
|
|
268
|
-
rules.push(`${selector}${block}`)
|
|
269
|
-
break
|
|
270
|
-
}
|
|
271
|
-
|
|
272
252
|
default: {
|
|
273
253
|
const block = createDeclarationBlock({ [property]: value }, important)
|
|
274
254
|
rules.push(`${selector}${block}`)
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import type { StyleObject } from '@tamagui/helpers'
|
|
6
6
|
|
|
7
|
-
const allSelectors = {}
|
|
8
|
-
const allRules = {}
|
|
7
|
+
const allSelectors: Record<string, string> = {}
|
|
8
|
+
const allRules: Record<string, boolean | string[]> = {}
|
|
9
9
|
export const insertedTransforms = {}
|
|
10
10
|
|
|
11
11
|
export const getAllSelectors = () => allSelectors
|
|
@@ -84,7 +84,7 @@ export function updateInserted() {
|
|
|
84
84
|
const isTransform = identifier.startsWith('_transform')
|
|
85
85
|
const shouldInsert = isTransform ? addTransform(identifier, cssRule.cssText, cssRule) : true
|
|
86
86
|
if (shouldInsert) {
|
|
87
|
-
allSelectors[identifier] =
|
|
87
|
+
allSelectors[identifier] = cssRule.cssText
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
}
|
|
@@ -134,13 +134,21 @@ export type PartialStyleObject = Pick<StyleObject, 'identifier' | 'property' | '
|
|
|
134
134
|
export type RulesToInsert = PartialStyleObject[]
|
|
135
135
|
|
|
136
136
|
export function insertStyleRules(rulesToInsert: RulesToInsert) {
|
|
137
|
-
|
|
137
|
+
if (isClient && !sheet) {
|
|
138
|
+
if (process.env.NODE_ENV === 'development') {
|
|
139
|
+
// eslint-disable-next-line no-console
|
|
140
|
+
console.warn(`Missing sheet`)
|
|
141
|
+
}
|
|
142
|
+
return
|
|
143
|
+
}
|
|
138
144
|
for (const { identifier, rules } of rulesToInsert) {
|
|
139
|
-
if (allSelectors[identifier]
|
|
140
|
-
allSelectors[identifier] = process.env.NODE_ENV === 'development' ? rules :
|
|
145
|
+
if (allSelectors[identifier]) continue
|
|
146
|
+
allSelectors[identifier] = process.env.NODE_ENV === 'development' ? rules.join('\n') : ''
|
|
141
147
|
updateRules(identifier, rules)
|
|
142
|
-
|
|
143
|
-
|
|
148
|
+
if (sheet) {
|
|
149
|
+
for (const rule of rules) {
|
|
150
|
+
sheet.insertRule(rule, sheet.cssRules.length)
|
|
151
|
+
}
|
|
144
152
|
}
|
|
145
153
|
}
|
|
146
154
|
}
|
|
@@ -6,6 +6,7 @@ function matchMediaFallback(query: string): MediaQueryList {
|
|
|
6
6
|
!process.env.IS_STATIC &&
|
|
7
7
|
process.env.TAMAGUI_TARGET !== 'web'
|
|
8
8
|
) {
|
|
9
|
+
// eslint-disable-next-line no-console
|
|
9
10
|
console.log('warning: matchMedia not loading! Native not picking up .native.js files?')
|
|
10
11
|
}
|
|
11
12
|
return {
|
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
* Copyright (c) Nicolas Gallagher licensed under the MIT license.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { getAllSelectors } from './insertStyleRule'
|
|
6
7
|
import { normalizeColor } from './normalizeColor'
|
|
7
8
|
|
|
8
9
|
const cache = {}
|
|
9
10
|
|
|
10
11
|
export function normalizeValueWithProperty(value: any, property?: string): any {
|
|
12
|
+
if (property && unitlessNumbers[property]) {
|
|
13
|
+
return value
|
|
14
|
+
}
|
|
11
15
|
const cached = cache[value]
|
|
12
16
|
if (cached) {
|
|
13
17
|
return cached
|
|
@@ -78,3 +82,29 @@ const unitlessNumbers = {
|
|
|
78
82
|
scaleZ: true,
|
|
79
83
|
shadowOpacity: true,
|
|
80
84
|
}
|
|
85
|
+
|
|
86
|
+
// getting real values for colors for animations (reverse mapped from CSS)
|
|
87
|
+
// this isn't beautiful, but will do relatively fine performance for now
|
|
88
|
+
const rcache = {}
|
|
89
|
+
export function reverseMapClassNameToValue(key: string, className: string) {
|
|
90
|
+
const selectors = getAllSelectors()
|
|
91
|
+
const cssRule = selectors[className]
|
|
92
|
+
if (rcache[cssRule]) return rcache[cssRule]
|
|
93
|
+
if (!cssRule) {
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
const cssVal = cssRule.replace(/.*:/, '').replace(/;.*/, '')
|
|
97
|
+
let res: any
|
|
98
|
+
if (unitlessNumbers[key]) {
|
|
99
|
+
res = +cssVal
|
|
100
|
+
} else if (cssVal.endsWith('px')) {
|
|
101
|
+
res = +cssVal.replace('px', '')
|
|
102
|
+
} else {
|
|
103
|
+
res = cssVal
|
|
104
|
+
}
|
|
105
|
+
if (typeof res === 'string') {
|
|
106
|
+
res = res.trim()
|
|
107
|
+
}
|
|
108
|
+
rcache[cssRule] = res
|
|
109
|
+
return res
|
|
110
|
+
}
|
|
@@ -3,7 +3,6 @@ import React, { useCallback } from 'react'
|
|
|
3
3
|
export function useShallowSetState<State extends Object>(
|
|
4
4
|
setter: React.Dispatch<React.SetStateAction<State>>
|
|
5
5
|
) {
|
|
6
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
7
6
|
return useCallback(
|
|
8
7
|
(next: Partial<State>) => {
|
|
9
8
|
setter((prev) => {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
export const getThemeUnwrapped = (theme: any) => {
|
|
2
2
|
if (!theme) return null
|
|
3
3
|
const first = theme[GetThemeUnwrapped]
|
|
4
|
-
|
|
5
|
-
return theme
|
|
4
|
+
return first?.[GetThemeUnwrapped] || first || theme
|
|
6
5
|
}
|
|
7
6
|
|
|
8
7
|
export const GetThemeUnwrapped = Symbol()
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { useIsomorphicLayoutEffect } from '@tamagui/constants'
|
|
2
|
+
import { getBoundingClientRect } from '@tamagui/react-native-use-responder-events'
|
|
3
|
+
import { useEvent } from '@tamagui/use-event'
|
|
4
|
+
import { RefObject } from 'react'
|
|
5
|
+
|
|
6
|
+
const LayoutHandlers = new WeakMap<Element, Function>()
|
|
7
|
+
|
|
8
|
+
export type LayoutValue = {
|
|
9
|
+
x: number
|
|
10
|
+
y: number
|
|
11
|
+
width: number
|
|
12
|
+
height: number
|
|
13
|
+
left: number
|
|
14
|
+
top: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type LayoutEvent = {
|
|
18
|
+
nativeEvent: {
|
|
19
|
+
layout: LayoutValue
|
|
20
|
+
target: any
|
|
21
|
+
}
|
|
22
|
+
timeStamp: number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let resizeObserver: ResizeObserver | null = null
|
|
26
|
+
|
|
27
|
+
if (typeof window !== 'undefined' && 'ResizeObserver' in window) {
|
|
28
|
+
resizeObserver = new ResizeObserver((entries) => {
|
|
29
|
+
for (const { target } of entries) {
|
|
30
|
+
const onLayout = LayoutHandlers.get(target)
|
|
31
|
+
if (typeof onLayout !== 'function') return
|
|
32
|
+
measureLayout(target as HTMLElement, null, (x, y, width, height, left, top) => {
|
|
33
|
+
onLayout({
|
|
34
|
+
nativeEvent: {
|
|
35
|
+
layout: { x, y, width, height, left, top },
|
|
36
|
+
target,
|
|
37
|
+
},
|
|
38
|
+
timeStamp: Date.now(),
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const getRect = (node: HTMLElement) => {
|
|
46
|
+
const rect = getBoundingClientRect(node)
|
|
47
|
+
if (!rect) return
|
|
48
|
+
const { x, y, top, left } = rect
|
|
49
|
+
return { x, y, width: node.offsetWidth, height: node.offsetHeight, top, left }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const measureLayout = (
|
|
53
|
+
node: HTMLElement,
|
|
54
|
+
relativeTo: HTMLElement | null,
|
|
55
|
+
callback: Function
|
|
56
|
+
) => {
|
|
57
|
+
const relativeNode = relativeTo || node?.parentNode
|
|
58
|
+
if (relativeNode instanceof HTMLElement) {
|
|
59
|
+
setTimeout(() => {
|
|
60
|
+
const relativeRect = getBoundingClientRect(relativeNode)!
|
|
61
|
+
const { height, left, top, width } = getRect(node)!
|
|
62
|
+
const x = left - relativeRect.left
|
|
63
|
+
const y = top - relativeRect.top
|
|
64
|
+
callback(x, y, width, height, left, top)
|
|
65
|
+
}, 0)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const idFn = () => {}
|
|
70
|
+
|
|
71
|
+
export function useElementLayout(
|
|
72
|
+
ref: RefObject<Element>,
|
|
73
|
+
onLayout?: ((e: LayoutEvent) => void) | null
|
|
74
|
+
) {
|
|
75
|
+
const hasLayoutEvent = !!onLayout
|
|
76
|
+
const onLayoutEvent = useEvent(onLayout || idFn)
|
|
77
|
+
|
|
78
|
+
// Observing is done in a separate effect to avoid this effect running
|
|
79
|
+
// when 'onLayout' changes.
|
|
80
|
+
useIsomorphicLayoutEffect(() => {
|
|
81
|
+
if (!resizeObserver || !hasLayoutEvent) return
|
|
82
|
+
const node = ref.current
|
|
83
|
+
if (!node) return
|
|
84
|
+
LayoutHandlers.set(node, onLayoutEvent)
|
|
85
|
+
resizeObserver.observe(node)
|
|
86
|
+
return () => {
|
|
87
|
+
resizeObserver?.unobserve(node)
|
|
88
|
+
}
|
|
89
|
+
}, [ref, hasLayoutEvent])
|
|
90
|
+
}
|
|
@@ -1,20 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
// ssr friendly
|
|
1
|
+
import { isTouchable, isWeb } from '@tamagui/constants'
|
|
2
|
+
import { useDidFinishSSR } from '@tamagui/use-did-finish-ssr'
|
|
5
3
|
|
|
6
4
|
export const useIsTouchDevice = () => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (isWeb && !isServer) {
|
|
10
|
-
// only ever false on web SSR (env), so run effect conditionally
|
|
11
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
12
|
-
useIsomorphicLayoutEffect(() => {
|
|
13
|
-
if (isTouchable) {
|
|
14
|
-
setTouchOnly(true)
|
|
15
|
-
}
|
|
16
|
-
}, [])
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return touchOnly
|
|
5
|
+
return !isWeb ? true : useDidFinishSSR() ? isTouchable : false
|
|
20
6
|
}
|
package/src/hooks/useMedia.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useIsomorphicLayoutEffect } from '@tamagui/constants'
|
|
2
|
-
import {
|
|
2
|
+
import { MutableRefObject, useEffect, useMemo, useState } from 'react'
|
|
3
3
|
|
|
4
4
|
import { getConfig } from '../config'
|
|
5
5
|
import { createProxy } from '../helpers/createProxy'
|
|
@@ -31,20 +31,20 @@ export const mediaState: MediaQueryState =
|
|
|
31
31
|
|
|
32
32
|
type MediaListener = (next: boolean) => void
|
|
33
33
|
|
|
34
|
-
const
|
|
34
|
+
const listeners: { [key: string]: Set<MediaListener> } = {}
|
|
35
35
|
|
|
36
36
|
export function addMediaQueryListener(key: MediaQueryKey, cb: MediaListener) {
|
|
37
37
|
if (process.env.NODE_ENV === 'development' && key[0] === '$') {
|
|
38
38
|
// eslint-disable-next-line no-console
|
|
39
39
|
console.warn(`Warning, listening to media queries shouldn't use the "$" prefix`)
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
listeners[key] = listeners[key] || new Set()
|
|
42
|
+
listeners[key].add(cb)
|
|
43
43
|
return () => removeMediaQueryListener(key, cb)
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
export function removeMediaQueryListener(key: MediaQueryKey, cb: MediaListener) {
|
|
47
|
-
|
|
47
|
+
listeners[key]?.delete(cb)
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
export const mediaQueryConfig: MediaQueries = {}
|
|
@@ -54,16 +54,17 @@ export const getMedia = () => {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
// for SSR capture it at time of startup
|
|
57
|
-
let
|
|
58
|
-
let
|
|
59
|
-
|
|
57
|
+
let curState: MediaQueryState
|
|
58
|
+
let initState: MediaQueryState
|
|
60
59
|
export const getInitialMediaState = () => {
|
|
61
|
-
|
|
62
|
-
return currentMediaState || {}
|
|
63
|
-
}
|
|
64
|
-
return initialMediaState || {}
|
|
60
|
+
return (getConfig().disableSSR ? curState : initState) || {}
|
|
65
61
|
}
|
|
66
62
|
|
|
63
|
+
let mediaKeysOrdered: string[]
|
|
64
|
+
export const getMediaKeyImportance = (key: string) =>
|
|
65
|
+
// + 2 because we set base usedKeys=1 in getSplitStyles and all media go above 1
|
|
66
|
+
mediaKeysOrdered.indexOf(key[0] === '$' ? key.slice(1) : key) + 2
|
|
67
|
+
|
|
67
68
|
const dispose = new Set<Function>()
|
|
68
69
|
|
|
69
70
|
export const configureMedia = (config: TamaguiInternalConfig) => {
|
|
@@ -73,8 +74,9 @@ export const configureMedia = (config: TamaguiInternalConfig) => {
|
|
|
73
74
|
mediaState[key] = mediaQueryDefaultActive?.[key] || false
|
|
74
75
|
}
|
|
75
76
|
Object.assign(mediaQueryConfig, media)
|
|
76
|
-
|
|
77
|
-
|
|
77
|
+
curState = { ...mediaState }
|
|
78
|
+
initState = curState
|
|
79
|
+
mediaKeysOrdered = Object.keys(media)
|
|
78
80
|
if (config.disableSSR) {
|
|
79
81
|
setupMediaListeners()
|
|
80
82
|
}
|
|
@@ -102,40 +104,34 @@ function setupMediaListeners() {
|
|
|
102
104
|
// hmr, undo existing before re-binding
|
|
103
105
|
unlisten()
|
|
104
106
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
// react native needs these deprecated apis for now
|
|
116
|
-
match.addListener(update)
|
|
117
|
-
dispose.add(() => match.removeListener(update))
|
|
107
|
+
for (const key in mediaQueryConfig) {
|
|
108
|
+
const str = mediaObjectToString(mediaQueryConfig[key])
|
|
109
|
+
const getMatch = () => matchMedia(str)
|
|
110
|
+
const match = getMatch()
|
|
111
|
+
if (!match) {
|
|
112
|
+
throw new Error('⚠️ No match')
|
|
113
|
+
}
|
|
114
|
+
// react native needs these deprecated apis for now
|
|
115
|
+
match.addListener(update)
|
|
116
|
+
dispose.add(() => match.removeListener(update))
|
|
118
117
|
|
|
119
|
-
|
|
118
|
+
update()
|
|
120
119
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
120
|
+
function update() {
|
|
121
|
+
const next = !!getMatch().matches
|
|
122
|
+
if (next === mediaState[key]) return
|
|
123
|
+
mediaState[key] = next
|
|
124
|
+
curState = { ...mediaState }
|
|
125
|
+
const cur = listeners[key]
|
|
126
|
+
if (cur?.size) {
|
|
127
|
+
cur.forEach((cb) => cb(next))
|
|
130
128
|
}
|
|
131
129
|
}
|
|
132
|
-
}
|
|
130
|
+
}
|
|
133
131
|
}
|
|
134
132
|
|
|
135
|
-
export function
|
|
136
|
-
if (config.disableSSR)
|
|
137
|
-
return
|
|
138
|
-
}
|
|
133
|
+
export function useMediaListeners(config: TamaguiInternalConfig) {
|
|
134
|
+
if (config.disableSSR) return
|
|
139
135
|
useEffect(() => {
|
|
140
136
|
setupMediaListeners()
|
|
141
137
|
return unlisten
|
|
@@ -145,14 +141,14 @@ export function useMediaQueryListeners(config: TamaguiInternalConfig) {
|
|
|
145
141
|
export function useMedia(): {
|
|
146
142
|
[key in MediaQueryKey]: boolean
|
|
147
143
|
} {
|
|
148
|
-
const [state, setState] = useState<MediaQueryState>(initialMediaState || {})
|
|
149
144
|
const keys = useSafeRef({} as Record<string, boolean>)
|
|
145
|
+
const [state, setState] = useState<MediaQueryState>(() => getMediaState(initState || {}, keys))
|
|
150
146
|
|
|
151
147
|
function updateState() {
|
|
152
148
|
setState((prev) => {
|
|
153
149
|
for (const key in keys.current) {
|
|
154
150
|
if (prev[key] !== mediaState[key]) {
|
|
155
|
-
return { ...mediaState }
|
|
151
|
+
return getMediaState({ ...mediaState }, keys)
|
|
156
152
|
}
|
|
157
153
|
}
|
|
158
154
|
return prev
|
|
@@ -160,34 +156,27 @@ export function useMedia(): {
|
|
|
160
156
|
}
|
|
161
157
|
|
|
162
158
|
useIsomorphicLayoutEffect(() => {
|
|
163
|
-
|
|
159
|
+
updateState()
|
|
160
|
+
const disposers = Object.keys(keys.current).map((key) =>
|
|
164
161
|
addMediaQueryListener(key, updateState)
|
|
165
162
|
)
|
|
166
|
-
updateState()
|
|
167
163
|
return () => {
|
|
168
|
-
|
|
164
|
+
disposers.forEach((cb) => cb())
|
|
169
165
|
}
|
|
170
|
-
})
|
|
166
|
+
}, [keys.current])
|
|
171
167
|
|
|
172
|
-
return
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
keys.current[key] = true
|
|
185
|
-
}
|
|
186
|
-
return Reflect.get(state, key)
|
|
187
|
-
},
|
|
188
|
-
}),
|
|
189
|
-
[state, keys]
|
|
190
|
-
)
|
|
168
|
+
return state
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function getMediaState(state: MediaQueryState, keys: MutableRefObject<Record<string, boolean>>) {
|
|
172
|
+
return new Proxy(state, {
|
|
173
|
+
get(_, key: string) {
|
|
174
|
+
if (!keys.current[key]) {
|
|
175
|
+
keys.current[key] = true
|
|
176
|
+
}
|
|
177
|
+
return Reflect.get(state, key)
|
|
178
|
+
},
|
|
179
|
+
})
|
|
191
180
|
}
|
|
192
181
|
|
|
193
182
|
/**
|
|
@@ -206,44 +195,48 @@ export function useMediaPropsActive<A extends Object>(
|
|
|
206
195
|
const media = useMedia()
|
|
207
196
|
|
|
208
197
|
return useMemo(() => {
|
|
209
|
-
const
|
|
210
|
-
const
|
|
198
|
+
const next = {} as A
|
|
199
|
+
const importancesUsed = {}
|
|
211
200
|
const propNames = Object.keys(props)
|
|
212
|
-
const mediaKeysOrdered = Object.keys(getMedia())
|
|
213
|
-
|
|
214
|
-
function update(k: string, v: any, importance = 0) {
|
|
215
|
-
if (lastSetImportanceForKey[k] > importance) {
|
|
216
|
-
return
|
|
217
|
-
}
|
|
218
|
-
lastSetImportanceForKey[k] = importance
|
|
219
|
-
evaluated[k] = v
|
|
220
|
-
}
|
|
221
201
|
|
|
222
202
|
for (let i = propNames.length - 1; i >= 0; i--) {
|
|
223
203
|
const key = propNames[i]
|
|
224
204
|
const val = props[key]
|
|
225
205
|
if (key[0] === '$') {
|
|
226
|
-
|
|
227
|
-
if (!media[shortKey]) {
|
|
206
|
+
if (!media[key.slice(1)]) {
|
|
228
207
|
continue
|
|
229
208
|
}
|
|
230
209
|
if (val && typeof val === 'object') {
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
update(skey, val[skey], mediaImportance)
|
|
210
|
+
const subKeys = Object.keys(val)
|
|
211
|
+
for (let j = subKeys.length; j--; j >= 0) {
|
|
212
|
+
const subKey = subKeys[j]
|
|
213
|
+
mergeMediaByImportance(next, subKey, val[subKey], importancesUsed)
|
|
236
214
|
}
|
|
237
215
|
}
|
|
238
216
|
} else {
|
|
239
|
-
|
|
217
|
+
mergeMediaByImportance(next, key, val, importancesUsed)
|
|
240
218
|
}
|
|
241
219
|
}
|
|
242
220
|
|
|
243
|
-
return
|
|
221
|
+
return next
|
|
244
222
|
}, [media, props])
|
|
245
223
|
}
|
|
246
224
|
|
|
225
|
+
export function mergeMediaByImportance(
|
|
226
|
+
onto: Record<string, any>,
|
|
227
|
+
key: string,
|
|
228
|
+
value: any,
|
|
229
|
+
importancesUsed: Record<string, number>
|
|
230
|
+
) {
|
|
231
|
+
const importance = getMediaKeyImportance(key)
|
|
232
|
+
if (importancesUsed[key] > importance) {
|
|
233
|
+
return false
|
|
234
|
+
}
|
|
235
|
+
importancesUsed[key] = importance
|
|
236
|
+
onto[key] = value
|
|
237
|
+
return true
|
|
238
|
+
}
|
|
239
|
+
|
|
247
240
|
function camelToHyphen(str: string) {
|
|
248
241
|
return str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`).toLowerCase()
|
|
249
242
|
}
|
package/src/hooks/useSafeRef.ts
CHANGED
|
@@ -3,11 +3,12 @@ import { useRef } from 'react'
|
|
|
3
3
|
|
|
4
4
|
// dai-shi 🙏
|
|
5
5
|
// https://dev.to/uhyo_/a-concurrent-mode-safe-version-of-useref-1325
|
|
6
|
+
// probably can live without it though to save a bit of b
|
|
6
7
|
|
|
7
8
|
type Raw<T> = {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
hold: boolean
|
|
10
|
+
next: T
|
|
11
|
+
cur: T
|
|
11
12
|
ref: { current: T }
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -17,32 +18,30 @@ export const useSafeRef = <T>(initialValue: T) => {
|
|
|
17
18
|
const raw: Raw<T> =
|
|
18
19
|
rawRef.current ??
|
|
19
20
|
(rawRef.current = {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
hold: true,
|
|
22
|
+
next: initialValue,
|
|
23
|
+
cur: initialValue,
|
|
23
24
|
ref: {
|
|
24
25
|
get current() {
|
|
25
|
-
|
|
26
|
-
return raw.currentValue
|
|
27
|
-
} else {
|
|
28
|
-
return raw.comittedValue
|
|
29
|
-
}
|
|
26
|
+
return raw.hold ? raw.cur : raw.next
|
|
30
27
|
},
|
|
31
28
|
set current(v) {
|
|
32
|
-
if (!raw.
|
|
33
|
-
raw.
|
|
29
|
+
if (!raw.hold) {
|
|
30
|
+
raw.next = v
|
|
34
31
|
}
|
|
35
|
-
raw.
|
|
32
|
+
raw.cur = v
|
|
36
33
|
},
|
|
37
34
|
},
|
|
38
35
|
})
|
|
39
36
|
|
|
40
|
-
raw.
|
|
41
|
-
Promise.resolve().then(() =>
|
|
42
|
-
|
|
37
|
+
raw.hold = true
|
|
38
|
+
Promise.resolve().then(() => {
|
|
39
|
+
raw.hold = false
|
|
40
|
+
})
|
|
41
|
+
raw.cur = raw.next
|
|
43
42
|
|
|
44
43
|
useIsomorphicLayoutEffect(() => {
|
|
45
|
-
raw.
|
|
44
|
+
raw.next = raw.cur
|
|
46
45
|
})
|
|
47
46
|
|
|
48
47
|
return raw.ref
|