@tamagui/core 1.0.1-beta.147 → 1.0.1-beta.150
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/constants/platform.js.map +2 -2
- package/dist/cjs/createComponent.js +133 -48
- package/dist/cjs/createComponent.js.map +2 -2
- package/dist/cjs/helpers/getSplitStyles.js +57 -50
- package/dist/cjs/helpers/getSplitStyles.js.map +2 -2
- package/dist/cjs/helpers/mergeTransform.js.map +2 -2
- package/dist/cjs/hooks/useFeatures.js +0 -120
- package/dist/cjs/hooks/useFeatures.js.map +2 -2
- package/dist/cjs/hooks/useTheme.js +3 -2
- package/dist/cjs/hooks/useTheme.js.map +2 -2
- package/dist/cjs/types.js.map +1 -1
- package/dist/esm/constants/platform.js.map +2 -2
- package/dist/esm/createComponent.js +141 -51
- package/dist/esm/createComponent.js.map +2 -2
- package/dist/esm/helpers/getSplitStyles.js +57 -50
- package/dist/esm/helpers/getSplitStyles.js.map +2 -2
- package/dist/esm/helpers/mergeTransform.js.map +2 -2
- package/dist/esm/hooks/useFeatures.js +0 -120
- package/dist/esm/hooks/useFeatures.js.map +2 -2
- package/dist/esm/hooks/useTheme.js +3 -2
- package/dist/esm/hooks/useTheme.js.map +2 -2
- package/package.json +10 -9
- package/src/constants/platform.ts +1 -0
- package/src/createComponent.tsx +218 -57
- package/src/helpers/getSplitStyles.tsx +70 -65
- package/src/helpers/mergeTransform.ts +2 -0
- package/src/hooks/useTheme.tsx +4 -4
- package/src/types.tsx +3 -2
- package/types/helpers/getSplitStyles.d.ts +1 -0
- package/types/hooks/useFeatures.d.ts +0 -1
- package/types/types.d.ts +3 -2
- package/src/hooks/useFeatures.tsx +0 -289
package/src/createComponent.tsx
CHANGED
|
@@ -20,6 +20,7 @@ import React, {
|
|
|
20
20
|
memo,
|
|
21
21
|
useCallback,
|
|
22
22
|
useContext,
|
|
23
|
+
useEffect,
|
|
23
24
|
} from 'react'
|
|
24
25
|
import { StyleSheet, Text, View, ViewStyle } from 'react-native'
|
|
25
26
|
|
|
@@ -32,12 +33,16 @@ import { assignNativePropsToWeb } from './helpers/assignNativePropsToWeb'
|
|
|
32
33
|
import { getReturnVariablesAs } from './helpers/createPropMapper'
|
|
33
34
|
import { createShallowUpdate } from './helpers/createShallowUpdate'
|
|
34
35
|
import { extendStaticConfig, parseStaticConfig } from './helpers/extendStaticConfig'
|
|
35
|
-
import {
|
|
36
|
+
import {
|
|
37
|
+
SplitStyleResult,
|
|
38
|
+
getSubStyle,
|
|
39
|
+
insertSplitStyles,
|
|
40
|
+
useSplitStyles,
|
|
41
|
+
} from './helpers/getSplitStyles'
|
|
36
42
|
import { getAllSelectors } from './helpers/insertStyleRule'
|
|
37
43
|
import { mergeProps } from './helpers/mergeProps'
|
|
38
44
|
import { proxyThemeVariables } from './helpers/proxyThemeVariables'
|
|
39
|
-
import {
|
|
40
|
-
import { mediaState } from './hooks/useMedia'
|
|
45
|
+
import { addMediaQueryListener, mediaState, removeMediaQueryListener } from './hooks/useMedia'
|
|
41
46
|
import { usePressable } from './hooks/usePressable'
|
|
42
47
|
import { useServerRef, useServerState } from './hooks/useServerHooks'
|
|
43
48
|
import { getThemeManager, useTheme } from './hooks/useTheme'
|
|
@@ -54,6 +59,7 @@ import {
|
|
|
54
59
|
TamaguiElement,
|
|
55
60
|
TamaguiInternalConfig,
|
|
56
61
|
UseAnimationHook,
|
|
62
|
+
UseAnimationProps,
|
|
57
63
|
} from './types'
|
|
58
64
|
import { usePressability } from './vendor/Pressability'
|
|
59
65
|
import { Slot, mergeEvent } from './views/Slot'
|
|
@@ -92,6 +98,7 @@ function mergeShorthands({ defaultProps }: StaticConfigParsed, { shorthands }: T
|
|
|
92
98
|
|
|
93
99
|
let initialTheme: any
|
|
94
100
|
let config: TamaguiInternalConfig
|
|
101
|
+
let mediaPropNames: string[] = []
|
|
95
102
|
|
|
96
103
|
export function createComponent<
|
|
97
104
|
ComponentPropTypes extends Object = {},
|
|
@@ -145,7 +152,6 @@ export function createComponent<
|
|
|
145
152
|
|
|
146
153
|
const shouldAvoidClasses = !!(props.animation && avoidClasses)
|
|
147
154
|
const shouldForcePseudo = !!propsIn.forceStyle
|
|
148
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
149
155
|
const hasTextAncestor = !!(isWeb && isText ? useContext(TextAncestorContext) : false)
|
|
150
156
|
const splitStyleState =
|
|
151
157
|
!shouldAvoidClasses && !shouldForcePseudo
|
|
@@ -200,25 +206,114 @@ export function createComponent<
|
|
|
200
206
|
}
|
|
201
207
|
}
|
|
202
208
|
|
|
203
|
-
const { viewProps: viewPropsIn, pseudos, medias, style, classNames } = splitStyles
|
|
209
|
+
const { viewProps: viewPropsIn, pseudos, medias, style, classNames, mediaKeys } = splitStyles
|
|
210
|
+
|
|
211
|
+
// media queries
|
|
212
|
+
useIsomorphicLayoutEffect(() => {
|
|
213
|
+
for (const key of mediaKeys) {
|
|
214
|
+
addMediaQueryListener(key, forceUpdate)
|
|
215
|
+
}
|
|
216
|
+
return () => {
|
|
217
|
+
for (const key of mediaKeys) {
|
|
218
|
+
removeMediaQueryListener(key, forceUpdate)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}, [mediaKeys.join(',')])
|
|
222
|
+
|
|
223
|
+
// animations
|
|
204
224
|
const useAnimations = tamaguiConfig?.animations?.useAnimations as UseAnimationHook | undefined
|
|
205
225
|
const isAnimated = !!(useAnimations && props.animation)
|
|
206
226
|
const hasEnterStyle = !!props.enterStyle
|
|
207
|
-
|
|
208
227
|
const animationFeatureStylesIn = props.animation ? { ...defaultNativeStyle, ...style } : null
|
|
228
|
+
const propsWithAnimation = props as UseAnimationProps
|
|
229
|
+
|
|
230
|
+
// lets make changing the key mandatory for adding/removing animations
|
|
231
|
+
// reason is animations are heavy no way around it, and must be run inline here (🙅 loading as a sub-component)
|
|
232
|
+
// because they need to sync update on first render. it's pretty rare too going to/from no animation => animation
|
|
233
|
+
// so requiring key change on animation change is least-bad option.
|
|
234
|
+
// plus, React use() may let us get away with conditional hooks soon :)
|
|
235
|
+
if (!isRSC && isAnimated) {
|
|
236
|
+
const animationState = useAnimations(propsWithAnimation, {
|
|
237
|
+
state,
|
|
238
|
+
pseudos,
|
|
239
|
+
onDidAnimate: props.onDidAnimate,
|
|
240
|
+
hostRef,
|
|
241
|
+
staticConfig,
|
|
242
|
+
getStyle({ isExiting, isEntering, exitVariant, enterVariant } = {}) {
|
|
243
|
+
// we have to merge such that transforms keys all exist
|
|
244
|
+
const style = animationFeatureStylesIn
|
|
245
|
+
|
|
246
|
+
const enterStyle = isEntering
|
|
247
|
+
? enterVariant && staticConfig.variants?.[enterVariant]['true']
|
|
248
|
+
? getSubStyle(
|
|
249
|
+
'',
|
|
250
|
+
staticConfig.variants?.[enterVariant]['true'],
|
|
251
|
+
staticConfig,
|
|
252
|
+
theme,
|
|
253
|
+
props,
|
|
254
|
+
state,
|
|
255
|
+
tamaguiConfig
|
|
256
|
+
) || pseudos.enterStyle
|
|
257
|
+
: null || pseudos.enterStyle
|
|
258
|
+
: null
|
|
259
|
+
|
|
260
|
+
const exitStyle = isExiting
|
|
261
|
+
? exitVariant && staticConfig.variants?.[exitVariant]['true']
|
|
262
|
+
? getSubStyle(
|
|
263
|
+
'',
|
|
264
|
+
staticConfig.variants?.[exitVariant]['true'],
|
|
265
|
+
staticConfig,
|
|
266
|
+
theme,
|
|
267
|
+
props,
|
|
268
|
+
state,
|
|
269
|
+
tamaguiConfig
|
|
270
|
+
) || pseudos.exitStyle
|
|
271
|
+
: null || pseudos.exitStyle
|
|
272
|
+
: null
|
|
273
|
+
|
|
274
|
+
// if you have hoverStyle={{ scale: 1.1 }} and don't have scale set on the base style
|
|
275
|
+
// no animation will run! this is really confusing. this will look at all variants,
|
|
276
|
+
// and fill in base styles if they don't exist. eg:
|
|
277
|
+
// input:
|
|
278
|
+
// base: {}
|
|
279
|
+
// hoverStyle: { scale: 2 }
|
|
280
|
+
// enterStyle: { x: 100 }
|
|
281
|
+
// output:
|
|
282
|
+
// base: { x: 0, scale: 1 }
|
|
283
|
+
ensureBaseHasDefaults(
|
|
284
|
+
style,
|
|
285
|
+
// enterStyle,
|
|
286
|
+
pseudos.hoverStyle,
|
|
287
|
+
pseudos.focusStyle,
|
|
288
|
+
pseudos.pressStyle,
|
|
289
|
+
pseudos.pressStyle
|
|
290
|
+
)
|
|
209
291
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
292
|
+
enterStyle && isEntering && merge(style, enterStyle)
|
|
293
|
+
state.hover && pseudos.hoverStyle && merge(style, pseudos.hoverStyle)
|
|
294
|
+
state.focus && pseudos.focusStyle && merge(style, pseudos.focusStyle)
|
|
295
|
+
state.press && pseudos.pressStyle && merge(style, pseudos.pressStyle)
|
|
296
|
+
exitStyle && isExiting && merge(style, exitStyle)
|
|
297
|
+
|
|
298
|
+
if (process.env.NODE_ENV === 'development') {
|
|
299
|
+
if (props['debug']) {
|
|
300
|
+
// eslint-disable-next-line no-console
|
|
301
|
+
console.log('animation style', style)
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return style
|
|
306
|
+
},
|
|
307
|
+
//, delay
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
// must be properly memoized
|
|
311
|
+
if (animationState !== state.animation) {
|
|
312
|
+
setStateShallow({
|
|
313
|
+
animation: animationState,
|
|
314
|
+
})
|
|
315
|
+
}
|
|
316
|
+
}
|
|
222
317
|
|
|
223
318
|
const {
|
|
224
319
|
tag,
|
|
@@ -435,7 +530,27 @@ export function createComponent<
|
|
|
435
530
|
|
|
436
531
|
// from react-native-web
|
|
437
532
|
const platformMethodsRef = usePlatformMethods(viewProps)
|
|
438
|
-
|
|
533
|
+
|
|
534
|
+
const shouldSetMounted = Boolean(
|
|
535
|
+
isClient && (hasEnterStyle || props.animation) && !state.mounted
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
const setRef = useMergeRefs(
|
|
539
|
+
hostRef,
|
|
540
|
+
platformMethodsRef,
|
|
541
|
+
forwardedRef as any,
|
|
542
|
+
shouldSetMounted
|
|
543
|
+
? () => {
|
|
544
|
+
// for some reason without some small delay it doesn't animate css
|
|
545
|
+
setTimeout(() => {
|
|
546
|
+
setStateShallow({
|
|
547
|
+
mounted: true,
|
|
548
|
+
})
|
|
549
|
+
}, 10)
|
|
550
|
+
}
|
|
551
|
+
: undefined
|
|
552
|
+
)
|
|
553
|
+
|
|
439
554
|
viewProps.ref = setRef
|
|
440
555
|
}
|
|
441
556
|
|
|
@@ -504,31 +619,14 @@ export function createComponent<
|
|
|
504
619
|
})
|
|
505
620
|
}
|
|
506
621
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
}
|
|
622
|
+
if (!isRSC) {
|
|
623
|
+
useEffect(() => {
|
|
624
|
+
return () => {
|
|
625
|
+
mouseUps.delete(unPress)
|
|
626
|
+
}
|
|
627
|
+
}, [])
|
|
513
628
|
}
|
|
514
629
|
|
|
515
|
-
useIsomorphicLayoutEffect(() => {
|
|
516
|
-
// we need to use state to properly have mounted go from false => true
|
|
517
|
-
if (isClient && (hasEnterStyle || props.animation) && !state.mounted) {
|
|
518
|
-
// for SSR we never set mounted, ensuring enterStyle={{}} is set by default
|
|
519
|
-
setStateShallow({
|
|
520
|
-
mounted: true,
|
|
521
|
-
})
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
internal.current!.isMounted = true
|
|
525
|
-
return () => {
|
|
526
|
-
mouseUps.delete(unPress)
|
|
527
|
-
internal.current!.isMounted = false
|
|
528
|
-
internal.current!.unmountEffects?.forEach((cb) => cb())
|
|
529
|
-
}
|
|
530
|
-
}, [hasEnterStyle, props.animation])
|
|
531
|
-
|
|
532
630
|
let styles: any[]
|
|
533
631
|
|
|
534
632
|
const animationStyles = state.animation ? state.animation.style : null
|
|
@@ -547,11 +645,13 @@ export function createComponent<
|
|
|
547
645
|
]
|
|
548
646
|
if (!animationStyles && initialSplitStyles) {
|
|
549
647
|
const initPseudos = initialSplitStyles.pseudos
|
|
550
|
-
const force = shouldForcePseudo
|
|
551
648
|
!state.mounted && addPseudoToStyles(styles, initPseudos, pseudos, 'enterStyle')
|
|
552
|
-
state.hover &&
|
|
553
|
-
|
|
554
|
-
state.
|
|
649
|
+
state.hover &&
|
|
650
|
+
addPseudoToStyles(styles, initPseudos, pseudos, 'hoverStyle', shouldForcePseudo)
|
|
651
|
+
state.focus &&
|
|
652
|
+
addPseudoToStyles(styles, initPseudos, pseudos, 'focusStyle', shouldForcePseudo)
|
|
653
|
+
state.press &&
|
|
654
|
+
addPseudoToStyles(styles, initPseudos, pseudos, 'pressStyle', shouldForcePseudo)
|
|
555
655
|
}
|
|
556
656
|
// ugly but for now...
|
|
557
657
|
if (shouldForcePseudo) {
|
|
@@ -649,7 +749,6 @@ export function createComponent<
|
|
|
649
749
|
'onMouseLeave' in props)))
|
|
650
750
|
|
|
651
751
|
const unPress = useCallback(() => {
|
|
652
|
-
if (!internal.current!.isMounted) return
|
|
653
752
|
setStateShallow({
|
|
654
753
|
press: false,
|
|
655
754
|
pressIn: false,
|
|
@@ -740,8 +839,9 @@ export function createComponent<
|
|
|
740
839
|
: null
|
|
741
840
|
|
|
742
841
|
let space = spaceProp
|
|
842
|
+
|
|
743
843
|
// find space by media query
|
|
744
|
-
if (
|
|
844
|
+
if (mediaKeys.length) {
|
|
745
845
|
for (const key in mediaState) {
|
|
746
846
|
if (!mediaState[key]) continue
|
|
747
847
|
if (props[key] && props[key].space !== undefined) {
|
|
@@ -855,7 +955,9 @@ export function createComponent<
|
|
|
855
955
|
// only necessary when animating because some AnimatedView which wraps RNW View doesn't forward dataSet className
|
|
856
956
|
const isAnimatedRNWView = isAnimated && typeof elementType !== 'string' // assuming for now as reanimated is only driver
|
|
857
957
|
const shouldWrapWithComponentTheme =
|
|
858
|
-
|
|
958
|
+
!!theme.className &&
|
|
959
|
+
isAnimatedRNWView &&
|
|
960
|
+
getReturnVariablesAs(props, splitStyleState) === 'non-color-value'
|
|
859
961
|
const shouldWrapWithHover = Boolean(events || isRSC) && attachHover
|
|
860
962
|
|
|
861
963
|
if (shouldWrapWithHover || shouldWrapWithComponentTheme) {
|
|
@@ -902,14 +1004,7 @@ export function createComponent<
|
|
|
902
1004
|
}
|
|
903
1005
|
}
|
|
904
1006
|
|
|
905
|
-
return
|
|
906
|
-
<>
|
|
907
|
-
{features.elements}
|
|
908
|
-
{content}
|
|
909
|
-
</>
|
|
910
|
-
) : (
|
|
911
|
-
content
|
|
912
|
-
)
|
|
1007
|
+
return content
|
|
913
1008
|
})
|
|
914
1009
|
|
|
915
1010
|
if (staticConfig.componentName) {
|
|
@@ -1336,3 +1431,69 @@ function mergeConfigDefaultProps(
|
|
|
1336
1431
|
}
|
|
1337
1432
|
return props
|
|
1338
1433
|
}
|
|
1434
|
+
|
|
1435
|
+
const defaults = {
|
|
1436
|
+
left: 0,
|
|
1437
|
+
right: 0,
|
|
1438
|
+
top: 0,
|
|
1439
|
+
bottom: 0,
|
|
1440
|
+
opacity: 1,
|
|
1441
|
+
translateX: 0,
|
|
1442
|
+
translateY: 0,
|
|
1443
|
+
skew: 0,
|
|
1444
|
+
skewX: 0,
|
|
1445
|
+
skewY: 0,
|
|
1446
|
+
scale: 1,
|
|
1447
|
+
rotate: '0deg',
|
|
1448
|
+
rotateY: '0deg',
|
|
1449
|
+
rotateX: '0deg',
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
function ensureBaseHasDefaults(base: ViewStyle, ...pseudos: (ViewStyle | null | undefined)[]) {
|
|
1453
|
+
for (const pseudo of pseudos) {
|
|
1454
|
+
if (!pseudo) continue
|
|
1455
|
+
for (const key in pseudo) {
|
|
1456
|
+
const val = pseudo[key]
|
|
1457
|
+
// can we just use merge() here?
|
|
1458
|
+
if (key === 'transform') {
|
|
1459
|
+
if (typeof val === 'string') {
|
|
1460
|
+
continue
|
|
1461
|
+
}
|
|
1462
|
+
for (const t of val) {
|
|
1463
|
+
const tkey = Object.keys(t)[0]
|
|
1464
|
+
const defaultVal = defaults[tkey]
|
|
1465
|
+
const tDefaultVal = { [tkey]: defaultVal } as any
|
|
1466
|
+
if (!base.transform) {
|
|
1467
|
+
base.transform = [tDefaultVal]
|
|
1468
|
+
} else {
|
|
1469
|
+
if (!base.transform.find((x) => x[tkey])) {
|
|
1470
|
+
base.transform.push(tDefaultVal)
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
} else {
|
|
1475
|
+
if (!(key in base)) {
|
|
1476
|
+
base[key] = defaults[key]
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
function merge(base: ViewStyle, next: ViewStyle) {
|
|
1484
|
+
if (!next.transform || !base.transform) {
|
|
1485
|
+
Object.assign(base, next)
|
|
1486
|
+
return
|
|
1487
|
+
}
|
|
1488
|
+
const { transform, ...rest } = next
|
|
1489
|
+
Object.assign(base, rest)
|
|
1490
|
+
for (const t of transform) {
|
|
1491
|
+
const key = Object.keys(t)[0]
|
|
1492
|
+
const existing = base.transform.find((x) => key in x)
|
|
1493
|
+
if (existing) {
|
|
1494
|
+
existing[key] = t[key]
|
|
1495
|
+
} else {
|
|
1496
|
+
base.transform.push(t)
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
@@ -78,6 +78,7 @@ type StyleSplitter = (
|
|
|
78
78
|
rulesToInsert: RulesToInsert
|
|
79
79
|
viewProps: StackProps
|
|
80
80
|
fontFamily: string | undefined
|
|
81
|
+
mediaKeys: string[]
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
export const PROP_SPLIT = '-'
|
|
@@ -108,12 +109,14 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
108
109
|
) => {
|
|
109
110
|
conf = conf || getConfig()
|
|
110
111
|
const validStyleProps = staticConfig.isText ? stylePropsText : validStyles
|
|
112
|
+
const mediaKeys: string[] = []
|
|
111
113
|
const viewProps: StackProps = {}
|
|
112
114
|
const pseudos: PseudoStyles = {}
|
|
113
115
|
const medias: Record<MediaQueryKey, ViewStyle> = {}
|
|
114
116
|
const usedKeys = new Set<string>()
|
|
115
117
|
const propKeys = Object.keys(props)
|
|
116
|
-
const shouldDoClasses =
|
|
118
|
+
const shouldDoClasses =
|
|
119
|
+
(isWeb || process.env.IS_STATIC === 'is_static') && !state.noClassNames && !props.animation
|
|
117
120
|
const len = propKeys.length
|
|
118
121
|
const rulesToInsert: RulesToInsert = []
|
|
119
122
|
const style: ViewStyle = {}
|
|
@@ -125,54 +128,7 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
125
128
|
let classNames: ClassNamesObject = {}
|
|
126
129
|
// we need to gather these specific to each media query / pseudo
|
|
127
130
|
// value is [hash, val], so ["-jnjad-asdnjk", "scaleX(1) rotate(10deg)"]
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
function mergeClassName(key: string, val: string, isMediaOrPseudo = false) {
|
|
131
|
-
if (process.env.TAMAGUI_TARGET === 'web') {
|
|
132
|
-
// empty classnames passed by compiler sometimes
|
|
133
|
-
if (!val) return
|
|
134
|
-
if (val.startsWith('_transform-')) {
|
|
135
|
-
const namespace: TransformNamespaceKey = isMediaOrPseudo ? key : 'transform'
|
|
136
|
-
|
|
137
|
-
let transform = insertedTransforms[val]
|
|
138
|
-
if (isClient) {
|
|
139
|
-
if (!transform) {
|
|
140
|
-
// HMR or loaded a new chunk
|
|
141
|
-
updateInserted()
|
|
142
|
-
transform = insertedTransforms[val]
|
|
143
|
-
if (process.env.NODE_ENV === 'development') {
|
|
144
|
-
if (!transform) {
|
|
145
|
-
// eslint-disable-next-line no-console
|
|
146
|
-
console.warn('no transform found', { insertedTransforms, val })
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
if (!transform) {
|
|
151
|
-
if (isWeb && val[0] !== '_') {
|
|
152
|
-
// runtime insert
|
|
153
|
-
transform = val
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
|
|
157
|
-
// prettier-ignore
|
|
158
|
-
// eslint-disable-next-line no-console
|
|
159
|
-
console.log(' 🔹 getSplitStyles mergeClassName transform', { key, val, namespace, transform, insertedTransforms })
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
transforms = transforms || {}
|
|
163
|
-
transforms[namespace] = transforms[namespace] || ['', '']
|
|
164
|
-
const identifier = val.replace('_transform', '')
|
|
165
|
-
transforms[namespace][0] += identifier
|
|
166
|
-
// ssr doesn't need to do anything just make the right classname
|
|
167
|
-
if (transform) {
|
|
168
|
-
transforms[namespace][1] += transform
|
|
169
|
-
}
|
|
170
|
-
} else {
|
|
171
|
-
classNames[key] = val
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
131
|
+
const transforms: Record<TransformNamespaceKey, [string, string]> = {}
|
|
176
132
|
// fontFamily is our special baby, ensure we grab the latest set one always
|
|
177
133
|
let fontFamily: string | undefined
|
|
178
134
|
|
|
@@ -237,14 +193,14 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
237
193
|
fullKey += `${PROP_SPLIT}${pseudoShortKey}`
|
|
238
194
|
}
|
|
239
195
|
usedKeys.add(fullKey)
|
|
240
|
-
mergeClassName(fullKey, cn, isMediaOrPseudo)
|
|
196
|
+
mergeClassName(transforms, classNames, fullKey, cn, isMediaOrPseudo)
|
|
241
197
|
} else {
|
|
242
198
|
nonTamaguis += ' ' + cn
|
|
243
199
|
}
|
|
244
200
|
}
|
|
245
201
|
if (nonTamaguis) {
|
|
246
202
|
usedKeys.add(keyInit)
|
|
247
|
-
mergeClassName(keyInit, nonTamaguis)
|
|
203
|
+
mergeClassName(transforms, classNames, keyInit, nonTamaguis)
|
|
248
204
|
}
|
|
249
205
|
continue
|
|
250
206
|
}
|
|
@@ -259,7 +215,7 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
259
215
|
validStyles[keyInit.split(PROP_SPLIT)[0]]
|
|
260
216
|
if (isValidClassName || isMediaOrPseudo) {
|
|
261
217
|
usedKeys.add(keyInit)
|
|
262
|
-
mergeClassName(keyInit, valInit, isMediaOrPseudo)
|
|
218
|
+
mergeClassName(transforms, classNames, keyInit, valInit, isMediaOrPseudo)
|
|
263
219
|
continue
|
|
264
220
|
}
|
|
265
221
|
}
|
|
@@ -350,7 +306,7 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
350
306
|
continue
|
|
351
307
|
}
|
|
352
308
|
pseudos[key] = pseudos[key] || {}
|
|
353
|
-
|
|
309
|
+
const pseudoStyleObject = getSubStyle(
|
|
354
310
|
key,
|
|
355
311
|
val,
|
|
356
312
|
staticConfig,
|
|
@@ -361,15 +317,16 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
361
317
|
languageContext,
|
|
362
318
|
true
|
|
363
319
|
)
|
|
364
|
-
|
|
365
|
-
|
|
320
|
+
pseudos[key] = pseudoStyleObject
|
|
321
|
+
if (shouldDoClasses && key !== 'enterStyle' && key !== 'exitStyle') {
|
|
322
|
+
const pseudoStyles = getAtomicStyle(pseudoStyleObject, pseudoDescriptors[key])
|
|
366
323
|
for (const style of pseudoStyles) {
|
|
367
324
|
const postfix = pseudoDescriptors[key]?.name || key // exitStyle/enterStyle dont have pseudoDescriptors
|
|
368
325
|
const fullKey = `${style.property}${PROP_SPLIT}${postfix}`
|
|
369
326
|
if (!usedKeys.has(fullKey)) {
|
|
370
327
|
usedKeys.add(fullKey)
|
|
371
328
|
addStyleToInsertRules(rulesToInsert, style)
|
|
372
|
-
mergeClassName(fullKey, style.identifier, isMediaOrPseudo)
|
|
329
|
+
mergeClassName(transforms, classNames, fullKey, style.identifier, isMediaOrPseudo)
|
|
373
330
|
}
|
|
374
331
|
}
|
|
375
332
|
}
|
|
@@ -379,6 +336,7 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
379
336
|
// media
|
|
380
337
|
if (isMedia) {
|
|
381
338
|
const mediaKey = key
|
|
339
|
+
mediaKeys.push(key)
|
|
382
340
|
const mediaKeyShort = mediaKey.slice(1)
|
|
383
341
|
|
|
384
342
|
if (!mediaQueryConfig[mediaKeyShort]) {
|
|
@@ -419,7 +377,7 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
419
377
|
if (!usedKeys.has(fullKey)) {
|
|
420
378
|
usedKeys.add(fullKey)
|
|
421
379
|
addStyleToInsertRules(rulesToInsert, out)
|
|
422
|
-
mergeClassName(fullKey, out.identifier, true)
|
|
380
|
+
mergeClassName(transforms, classNames, fullKey, out.identifier, true)
|
|
423
381
|
}
|
|
424
382
|
}
|
|
425
383
|
} else {
|
|
@@ -428,7 +386,14 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
428
386
|
// eslint-disable-next-line no-console
|
|
429
387
|
console.log('apply media style', mediaKey, mediaState)
|
|
430
388
|
}
|
|
431
|
-
|
|
389
|
+
if (shouldDoClasses) {
|
|
390
|
+
Object.assign(medias, mediaStyle)
|
|
391
|
+
} else {
|
|
392
|
+
for (const key in mediaStyle) {
|
|
393
|
+
usedKeys.add(key)
|
|
394
|
+
style[key] = mediaStyle[key]
|
|
395
|
+
}
|
|
396
|
+
}
|
|
432
397
|
}
|
|
433
398
|
}
|
|
434
399
|
continue
|
|
@@ -447,13 +412,7 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
447
412
|
} else if (key in stylePropsTransform) {
|
|
448
413
|
mergeTransform(style, key, val, true)
|
|
449
414
|
} else {
|
|
450
|
-
// if (key === 'pointerEvents') {
|
|
451
|
-
// // pointer events can be box-none which requires css
|
|
452
|
-
// addStyleToInsertRules(out.identifier, out.styleRule)
|
|
453
|
-
// mergeClassName(fullKey, out.identifier, true)
|
|
454
|
-
// } else {
|
|
455
415
|
style[key] = normalizeValueWithProperty(val, key)
|
|
456
|
-
// }
|
|
457
416
|
}
|
|
458
417
|
continue
|
|
459
418
|
}
|
|
@@ -489,7 +448,7 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
489
448
|
// should probably have a few more exceptions here!
|
|
490
449
|
if (key === 'pointerEvents' || !state.dynamicStylesInline) {
|
|
491
450
|
addStyleToInsertRules(rulesToInsert, atomicStyle)
|
|
492
|
-
mergeClassName(key, atomicStyle.identifier)
|
|
451
|
+
mergeClassName(transforms, classNames, key, atomicStyle.identifier)
|
|
493
452
|
} else {
|
|
494
453
|
style[key] = atomicStyle.value
|
|
495
454
|
}
|
|
@@ -568,12 +527,58 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
568
527
|
viewProps,
|
|
569
528
|
style,
|
|
570
529
|
medias,
|
|
530
|
+
mediaKeys,
|
|
571
531
|
pseudos,
|
|
572
532
|
classNames,
|
|
573
533
|
rulesToInsert,
|
|
574
534
|
}
|
|
575
535
|
}
|
|
576
536
|
|
|
537
|
+
function mergeClassName(
|
|
538
|
+
transforms: Record<string, any[]>,
|
|
539
|
+
classNames: Record<string, string>,
|
|
540
|
+
key: string,
|
|
541
|
+
val: string,
|
|
542
|
+
isMediaOrPseudo = false
|
|
543
|
+
) {
|
|
544
|
+
if (process.env.TAMAGUI_TARGET === 'web') {
|
|
545
|
+
// empty classnames passed by compiler sometimes
|
|
546
|
+
if (!val) return
|
|
547
|
+
if (val.startsWith('_transform-')) {
|
|
548
|
+
const namespace: TransformNamespaceKey = isMediaOrPseudo ? key : 'transform'
|
|
549
|
+
let transform = insertedTransforms[val]
|
|
550
|
+
if (isClient) {
|
|
551
|
+
if (!transform) {
|
|
552
|
+
// HMR or loaded a new chunk
|
|
553
|
+
updateInserted()
|
|
554
|
+
transform = insertedTransforms[val]
|
|
555
|
+
if (process.env.NODE_ENV === 'development') {
|
|
556
|
+
if (!transform) {
|
|
557
|
+
// eslint-disable-next-line no-console
|
|
558
|
+
console.warn('no transform found', { insertedTransforms, val })
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
if (!transform) {
|
|
563
|
+
if (isWeb && val[0] !== '_') {
|
|
564
|
+
// runtime insert
|
|
565
|
+
transform = val
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
transforms[namespace] = transforms[namespace] || ['', '']
|
|
570
|
+
const identifier = val.replace('_transform', '')
|
|
571
|
+
transforms[namespace][0] += identifier
|
|
572
|
+
// ssr doesn't need to do anything just make the right classname
|
|
573
|
+
if (transform) {
|
|
574
|
+
transforms[namespace][1] += transform
|
|
575
|
+
}
|
|
576
|
+
} else {
|
|
577
|
+
classNames[key] = val
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
577
582
|
/**
|
|
578
583
|
* getSubStyle calls propMapper with props
|
|
579
584
|
* those should be specific to the substyle, but fallback to the base props
|
|
@@ -4,10 +4,12 @@ export const mergeTransform = (obj: ViewStyle, key: string, val: any, backwards
|
|
|
4
4
|
obj.transform ||= []
|
|
5
5
|
obj.transform[backwards ? 'unshift' : 'push']({ [mapTransformKeys[key] || key]: val } as any)
|
|
6
6
|
}
|
|
7
|
+
|
|
7
8
|
const mapTransformKeys = {
|
|
8
9
|
x: 'translateX',
|
|
9
10
|
y: 'translateY',
|
|
10
11
|
}
|
|
12
|
+
|
|
11
13
|
export const invertMapTransformKeys = {
|
|
12
14
|
translateX: 'x',
|
|
13
15
|
translateY: 'y',
|
package/src/hooks/useTheme.tsx
CHANGED
|
@@ -220,16 +220,13 @@ export const useChangeThemeEffect = (
|
|
|
220
220
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
221
221
|
const forceUpdate = forceUpdateProp || useForceUpdate()
|
|
222
222
|
|
|
223
|
-
const themeManager = useConstant
|
|
223
|
+
const themeManager = useConstant(() => {
|
|
224
224
|
return new ThemeManager(next.name, next.theme, parentManager, reset)
|
|
225
225
|
})
|
|
226
226
|
|
|
227
227
|
// if not SSR
|
|
228
228
|
if (!isSSR) {
|
|
229
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
230
229
|
useLayoutEffect(() => {
|
|
231
|
-
if (!themeManager) return
|
|
232
|
-
|
|
233
230
|
activeThemeManagers.add(themeManager)
|
|
234
231
|
|
|
235
232
|
if (next?.name) {
|
|
@@ -240,6 +237,9 @@ export const useChangeThemeEffect = (
|
|
|
240
237
|
const next = parentManager.getNextTheme(getThemeProps, debug)
|
|
241
238
|
if (!next) return
|
|
242
239
|
if (themeManager.update(next)) {
|
|
240
|
+
if (process.env.NODE_ENV === 'development' && debug) {
|
|
241
|
+
console.log('Changed theme', componentName, next, { props })
|
|
242
|
+
}
|
|
243
243
|
forceUpdate()
|
|
244
244
|
}
|
|
245
245
|
})
|
package/src/types.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// TODO split this into own package @tamagui/types to share with animations packages
|
|
2
2
|
|
|
3
3
|
import { Properties } from 'csstype'
|
|
4
|
-
import React from 'react'
|
|
4
|
+
import React, { RefObject } from 'react'
|
|
5
5
|
import {
|
|
6
6
|
GestureResponderEvent,
|
|
7
7
|
Image,
|
|
@@ -1242,6 +1242,7 @@ export type AnimationDriver<A extends AnimationConfig = AnimationConfig> = {
|
|
|
1242
1242
|
export type UseAnimationProps = TamaguiComponentPropsBase & Record<string, any>
|
|
1243
1243
|
|
|
1244
1244
|
export type UseAnimationHelpers = {
|
|
1245
|
+
hostRef: RefObject<HTMLElement | View>
|
|
1245
1246
|
staticConfig: StaticConfigParsed
|
|
1246
1247
|
getStyle: (props?: {
|
|
1247
1248
|
isEntering?: boolean
|
|
@@ -1262,6 +1263,6 @@ export type UseAnimationHelpers = {
|
|
|
1262
1263
|
export type UseAnimationHook = (
|
|
1263
1264
|
props: UseAnimationProps,
|
|
1264
1265
|
helpers: UseAnimationHelpers
|
|
1265
|
-
) => {
|
|
1266
|
+
) => null | {
|
|
1266
1267
|
style?: StackStylePropsBase | StackStylePropsBase[]
|
|
1267
1268
|
}
|