@tamagui/core 1.0.1-beta.149 → 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/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/package.json +10 -10
- package/src/constants/platform.ts +1 -0
- package/src/createComponent.tsx +218 -56
- package/src/helpers/getSplitStyles.tsx +70 -65
- package/src/helpers/mergeTransform.ts +2 -0
- 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 = {},
|
|
@@ -199,25 +206,114 @@ export function createComponent<
|
|
|
199
206
|
}
|
|
200
207
|
}
|
|
201
208
|
|
|
202
|
-
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
|
|
203
224
|
const useAnimations = tamaguiConfig?.animations?.useAnimations as UseAnimationHook | undefined
|
|
204
225
|
const isAnimated = !!(useAnimations && props.animation)
|
|
205
226
|
const hasEnterStyle = !!props.enterStyle
|
|
206
|
-
|
|
207
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
|
+
)
|
|
208
291
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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
|
+
}
|
|
221
317
|
|
|
222
318
|
const {
|
|
223
319
|
tag,
|
|
@@ -434,7 +530,27 @@ export function createComponent<
|
|
|
434
530
|
|
|
435
531
|
// from react-native-web
|
|
436
532
|
const platformMethodsRef = usePlatformMethods(viewProps)
|
|
437
|
-
|
|
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
|
+
|
|
438
554
|
viewProps.ref = setRef
|
|
439
555
|
}
|
|
440
556
|
|
|
@@ -503,31 +619,14 @@ export function createComponent<
|
|
|
503
619
|
})
|
|
504
620
|
}
|
|
505
621
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
}
|
|
622
|
+
if (!isRSC) {
|
|
623
|
+
useEffect(() => {
|
|
624
|
+
return () => {
|
|
625
|
+
mouseUps.delete(unPress)
|
|
626
|
+
}
|
|
627
|
+
}, [])
|
|
512
628
|
}
|
|
513
629
|
|
|
514
|
-
useIsomorphicLayoutEffect(() => {
|
|
515
|
-
// we need to use state to properly have mounted go from false => true
|
|
516
|
-
if (isClient && (hasEnterStyle || props.animation) && !state.mounted) {
|
|
517
|
-
// for SSR we never set mounted, ensuring enterStyle={{}} is set by default
|
|
518
|
-
setStateShallow({
|
|
519
|
-
mounted: true,
|
|
520
|
-
})
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
internal.current!.isMounted = true
|
|
524
|
-
return () => {
|
|
525
|
-
mouseUps.delete(unPress)
|
|
526
|
-
internal.current!.isMounted = false
|
|
527
|
-
internal.current!.unmountEffects?.forEach((cb) => cb())
|
|
528
|
-
}
|
|
529
|
-
}, [hasEnterStyle, props.animation])
|
|
530
|
-
|
|
531
630
|
let styles: any[]
|
|
532
631
|
|
|
533
632
|
const animationStyles = state.animation ? state.animation.style : null
|
|
@@ -546,11 +645,13 @@ export function createComponent<
|
|
|
546
645
|
]
|
|
547
646
|
if (!animationStyles && initialSplitStyles) {
|
|
548
647
|
const initPseudos = initialSplitStyles.pseudos
|
|
549
|
-
const force = shouldForcePseudo
|
|
550
648
|
!state.mounted && addPseudoToStyles(styles, initPseudos, pseudos, 'enterStyle')
|
|
551
|
-
state.hover &&
|
|
552
|
-
|
|
553
|
-
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)
|
|
554
655
|
}
|
|
555
656
|
// ugly but for now...
|
|
556
657
|
if (shouldForcePseudo) {
|
|
@@ -648,7 +749,6 @@ export function createComponent<
|
|
|
648
749
|
'onMouseLeave' in props)))
|
|
649
750
|
|
|
650
751
|
const unPress = useCallback(() => {
|
|
651
|
-
if (!internal.current!.isMounted) return
|
|
652
752
|
setStateShallow({
|
|
653
753
|
press: false,
|
|
654
754
|
pressIn: false,
|
|
@@ -739,8 +839,9 @@ export function createComponent<
|
|
|
739
839
|
: null
|
|
740
840
|
|
|
741
841
|
let space = spaceProp
|
|
842
|
+
|
|
742
843
|
// find space by media query
|
|
743
|
-
if (
|
|
844
|
+
if (mediaKeys.length) {
|
|
744
845
|
for (const key in mediaState) {
|
|
745
846
|
if (!mediaState[key]) continue
|
|
746
847
|
if (props[key] && props[key].space !== undefined) {
|
|
@@ -854,7 +955,9 @@ export function createComponent<
|
|
|
854
955
|
// only necessary when animating because some AnimatedView which wraps RNW View doesn't forward dataSet className
|
|
855
956
|
const isAnimatedRNWView = isAnimated && typeof elementType !== 'string' // assuming for now as reanimated is only driver
|
|
856
957
|
const shouldWrapWithComponentTheme =
|
|
857
|
-
|
|
958
|
+
!!theme.className &&
|
|
959
|
+
isAnimatedRNWView &&
|
|
960
|
+
getReturnVariablesAs(props, splitStyleState) === 'non-color-value'
|
|
858
961
|
const shouldWrapWithHover = Boolean(events || isRSC) && attachHover
|
|
859
962
|
|
|
860
963
|
if (shouldWrapWithHover || shouldWrapWithComponentTheme) {
|
|
@@ -901,14 +1004,7 @@ export function createComponent<
|
|
|
901
1004
|
}
|
|
902
1005
|
}
|
|
903
1006
|
|
|
904
|
-
return
|
|
905
|
-
<>
|
|
906
|
-
{features.elements}
|
|
907
|
-
{content}
|
|
908
|
-
</>
|
|
909
|
-
) : (
|
|
910
|
-
content
|
|
911
|
-
)
|
|
1007
|
+
return content
|
|
912
1008
|
})
|
|
913
1009
|
|
|
914
1010
|
if (staticConfig.componentName) {
|
|
@@ -1335,3 +1431,69 @@ function mergeConfigDefaultProps(
|
|
|
1335
1431
|
}
|
|
1336
1432
|
return props
|
|
1337
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/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
|
}
|