@tamagui/core 1.0.1-beta.148 → 1.0.1-beta.151

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/cjs/constants/platform.js.map +2 -2
  2. package/dist/cjs/createComponent.js +161 -52
  3. package/dist/cjs/createComponent.js.map +2 -2
  4. package/dist/cjs/createFont.js +2 -1
  5. package/dist/cjs/createFont.js.map +2 -2
  6. package/dist/cjs/helpers/getSplitStyles.js +60 -50
  7. package/dist/cjs/helpers/getSplitStyles.js.map +2 -2
  8. package/dist/cjs/helpers/mergeTransform.js.map +2 -2
  9. package/dist/cjs/hooks/useFeatures.js +0 -120
  10. package/dist/cjs/hooks/useFeatures.js.map +2 -2
  11. package/dist/cjs/insertFont.js +1 -1
  12. package/dist/cjs/insertFont.js.map +2 -2
  13. package/dist/cjs/types.js.map +1 -1
  14. package/dist/esm/constants/platform.js.map +2 -2
  15. package/dist/esm/createComponent.js +169 -55
  16. package/dist/esm/createComponent.js.map +2 -2
  17. package/dist/esm/createFont.js +2 -1
  18. package/dist/esm/createFont.js.map +2 -2
  19. package/dist/esm/helpers/getSplitStyles.js +60 -50
  20. package/dist/esm/helpers/getSplitStyles.js.map +2 -2
  21. package/dist/esm/helpers/mergeTransform.js.map +2 -2
  22. package/dist/esm/hooks/useFeatures.js +0 -120
  23. package/dist/esm/hooks/useFeatures.js.map +2 -2
  24. package/dist/esm/insertFont.js +1 -1
  25. package/dist/esm/insertFont.js.map +2 -2
  26. package/package.json +10 -9
  27. package/src/constants/platform.ts +1 -0
  28. package/src/createComponent.tsx +246 -57
  29. package/src/createFont.ts +4 -1
  30. package/src/helpers/getSplitStyles.tsx +73 -65
  31. package/src/helpers/mergeTransform.ts +2 -0
  32. package/src/insertFont.ts +1 -1
  33. package/src/types.tsx +7 -5
  34. package/types/helpers/getSplitStyles.d.ts +1 -0
  35. package/types/hooks/useFeatures.d.ts +0 -1
  36. package/types/types.d.ts +11 -3
  37. package/src/hooks/useFeatures.tsx +0 -289
@@ -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 { SplitStyleResult, insertSplitStyles, useSplitStyles } from './helpers/getSplitStyles'
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 { useFeatures } from './hooks/useFeatures'
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
- const features = useFeatures(props, {
210
- forceUpdate,
211
- setStateShallow,
212
- useAnimations,
213
- state,
214
- style: animationFeatureStylesIn,
215
- pseudos,
216
- staticConfig,
217
- theme,
218
- hostRef,
219
- onDidAnimate: props.onDidAnimate,
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
- const setRef = useMergeRefs(hostRef, platformMethodsRef, forwardedRef as any)
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
- // isMounted
507
- const internal = useServerRef<{ isMounted: boolean; unmountEffects?: Function[] }>()
508
- if (!internal.current) {
509
- internal.current = {
510
- isMounted: true,
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 && addPseudoToStyles(styles, initPseudos, pseudos, 'hoverStyle', force)
552
- state.focus && addPseudoToStyles(styles, initPseudos, pseudos, 'focusStyle', force)
553
- state.press && addPseudoToStyles(styles, initPseudos, pseudos, 'pressStyle', force)
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) {
@@ -606,7 +707,34 @@ export function createComponent<
606
707
  }
607
708
 
608
709
  viewProps.style = style
609
- } else {
710
+ }
711
+
712
+ if (process.env.TAMAGUI_TARGET === 'native') {
713
+ // swap out the right family based on weight/style
714
+ if (splitStyles.fontFamily) {
715
+ const faceInfo = config.fontsParsed[splitStyles.fontFamily]?.face
716
+ if (faceInfo) {
717
+ const [weight, style] = (() => {
718
+ let weight: string | undefined
719
+ let style: string | undefined
720
+ for (let i = styles.length; i >= 0; i--) {
721
+ weight ??= styles[i]?.fontWeight
722
+ style ??= styles[i]?.fontStyle
723
+ }
724
+ return [weight || '400', style || 'normal'] as const
725
+ })()
726
+ const overrideFace = faceInfo[weight]?.[style]?.val
727
+ if (overrideFace) {
728
+ for (const style of styles) {
729
+ if (style?.fontFamily) {
730
+ style.fontFamily = overrideFace
731
+ }
732
+ }
733
+ }
734
+ }
735
+ }
736
+
737
+ // assign styles
610
738
  viewProps.style = styles
611
739
  }
612
740
 
@@ -648,7 +776,6 @@ export function createComponent<
648
776
  'onMouseLeave' in props)))
649
777
 
650
778
  const unPress = useCallback(() => {
651
- if (!internal.current!.isMounted) return
652
779
  setStateShallow({
653
780
  press: false,
654
781
  pressIn: false,
@@ -739,8 +866,9 @@ export function createComponent<
739
866
  : null
740
867
 
741
868
  let space = spaceProp
869
+
742
870
  // find space by media query
743
- if (features.enabled.mediaQuery) {
871
+ if (mediaKeys.length) {
744
872
  for (const key in mediaState) {
745
873
  if (!mediaState[key]) continue
746
874
  if (props[key] && props[key].space !== undefined) {
@@ -854,7 +982,9 @@ export function createComponent<
854
982
  // only necessary when animating because some AnimatedView which wraps RNW View doesn't forward dataSet className
855
983
  const isAnimatedRNWView = isAnimated && typeof elementType !== 'string' // assuming for now as reanimated is only driver
856
984
  const shouldWrapWithComponentTheme =
857
- isAnimatedRNWView && getReturnVariablesAs(props, splitStyleState) === 'non-color-value'
985
+ !!theme.className &&
986
+ isAnimatedRNWView &&
987
+ getReturnVariablesAs(props, splitStyleState) === 'non-color-value'
858
988
  const shouldWrapWithHover = Boolean(events || isRSC) && attachHover
859
989
 
860
990
  if (shouldWrapWithHover || shouldWrapWithComponentTheme) {
@@ -901,14 +1031,7 @@ export function createComponent<
901
1031
  }
902
1032
  }
903
1033
 
904
- return !isRSC && features.elements.length ? (
905
- <>
906
- {features.elements}
907
- {content}
908
- </>
909
- ) : (
910
- content
911
- )
1034
+ return content
912
1035
  })
913
1036
 
914
1037
  if (staticConfig.componentName) {
@@ -1335,3 +1458,69 @@ function mergeConfigDefaultProps(
1335
1458
  }
1336
1459
  return props
1337
1460
  }
1461
+
1462
+ const defaults = {
1463
+ left: 0,
1464
+ right: 0,
1465
+ top: 0,
1466
+ bottom: 0,
1467
+ opacity: 1,
1468
+ translateX: 0,
1469
+ translateY: 0,
1470
+ skew: 0,
1471
+ skewX: 0,
1472
+ skewY: 0,
1473
+ scale: 1,
1474
+ rotate: '0deg',
1475
+ rotateY: '0deg',
1476
+ rotateX: '0deg',
1477
+ }
1478
+
1479
+ function ensureBaseHasDefaults(base: ViewStyle, ...pseudos: (ViewStyle | null | undefined)[]) {
1480
+ for (const pseudo of pseudos) {
1481
+ if (!pseudo) continue
1482
+ for (const key in pseudo) {
1483
+ const val = pseudo[key]
1484
+ // can we just use merge() here?
1485
+ if (key === 'transform') {
1486
+ if (typeof val === 'string') {
1487
+ continue
1488
+ }
1489
+ for (const t of val) {
1490
+ const tkey = Object.keys(t)[0]
1491
+ const defaultVal = defaults[tkey]
1492
+ const tDefaultVal = { [tkey]: defaultVal } as any
1493
+ if (!base.transform) {
1494
+ base.transform = [tDefaultVal]
1495
+ } else {
1496
+ if (!base.transform.find((x) => x[tkey])) {
1497
+ base.transform.push(tDefaultVal)
1498
+ }
1499
+ }
1500
+ }
1501
+ } else {
1502
+ if (!(key in base)) {
1503
+ base[key] = defaults[key]
1504
+ }
1505
+ }
1506
+ }
1507
+ }
1508
+ }
1509
+
1510
+ function merge(base: ViewStyle, next: ViewStyle) {
1511
+ if (!next.transform || !base.transform) {
1512
+ Object.assign(base, next)
1513
+ return
1514
+ }
1515
+ const { transform, ...rest } = next
1516
+ Object.assign(base, rest)
1517
+ for (const t of transform) {
1518
+ const key = Object.keys(t)[0]
1519
+ const existing = base.transform.find((x) => key in x)
1520
+ if (existing) {
1521
+ existing[key] = t[key]
1522
+ } else {
1523
+ base.transform.push(t)
1524
+ }
1525
+ }
1526
+ }
package/src/createFont.ts CHANGED
@@ -4,8 +4,11 @@ export const createFont = <A extends GenericFont>(font: A): A => {
4
4
  // fills in any missing values based on size keys being standard
5
5
  const sizeKeys = Object.keys(font.size)
6
6
 
7
+ // fill in intermediate values
7
8
  for (const key in font) {
8
- if (key === 'size' || key === 'family') continue
9
+ if (key === 'size' || key === 'family' || key === 'face') {
10
+ continue
11
+ }
9
12
  const section = font[key] as Object
10
13
  const keys = Object.keys(section)
11
14
 
@@ -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 = (isWeb || process.env.IS_STATIC === 'is_static') && !state.noClassNames
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
- let transforms = null as Record<TransformNamespaceKey, [string, string]> | null
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
- pseudos[key] = getSubStyle(
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
- if (shouldDoClasses) {
365
- const pseudoStyles = getAtomicStyle(pseudos[key], pseudoDescriptors[key])
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,17 @@ export const getSplitStyles: StyleSplitter = (
428
386
  // eslint-disable-next-line no-console
429
387
  console.log('apply media style', mediaKey, mediaState)
430
388
  }
431
- Object.assign(shouldDoClasses ? medias : style, mediaStyle)
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
+ if (key === 'fontFamily') {
396
+ fontFamily = mediaStyle[key]
397
+ }
398
+ }
399
+ }
432
400
  }
433
401
  }
434
402
  continue
@@ -447,13 +415,7 @@ export const getSplitStyles: StyleSplitter = (
447
415
  } else if (key in stylePropsTransform) {
448
416
  mergeTransform(style, key, val, true)
449
417
  } 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
418
  style[key] = normalizeValueWithProperty(val, key)
456
- // }
457
419
  }
458
420
  continue
459
421
  }
@@ -489,7 +451,7 @@ export const getSplitStyles: StyleSplitter = (
489
451
  // should probably have a few more exceptions here!
490
452
  if (key === 'pointerEvents' || !state.dynamicStylesInline) {
491
453
  addStyleToInsertRules(rulesToInsert, atomicStyle)
492
- mergeClassName(key, atomicStyle.identifier)
454
+ mergeClassName(transforms, classNames, key, atomicStyle.identifier)
493
455
  } else {
494
456
  style[key] = atomicStyle.value
495
457
  }
@@ -568,12 +530,58 @@ export const getSplitStyles: StyleSplitter = (
568
530
  viewProps,
569
531
  style,
570
532
  medias,
533
+ mediaKeys,
571
534
  pseudos,
572
535
  classNames,
573
536
  rulesToInsert,
574
537
  }
575
538
  }
576
539
 
540
+ function mergeClassName(
541
+ transforms: Record<string, any[]>,
542
+ classNames: Record<string, string>,
543
+ key: string,
544
+ val: string,
545
+ isMediaOrPseudo = false
546
+ ) {
547
+ if (process.env.TAMAGUI_TARGET === 'web') {
548
+ // empty classnames passed by compiler sometimes
549
+ if (!val) return
550
+ if (val.startsWith('_transform-')) {
551
+ const namespace: TransformNamespaceKey = isMediaOrPseudo ? key : 'transform'
552
+ let transform = insertedTransforms[val]
553
+ if (isClient) {
554
+ if (!transform) {
555
+ // HMR or loaded a new chunk
556
+ updateInserted()
557
+ transform = insertedTransforms[val]
558
+ if (process.env.NODE_ENV === 'development') {
559
+ if (!transform) {
560
+ // eslint-disable-next-line no-console
561
+ console.warn('no transform found', { insertedTransforms, val })
562
+ }
563
+ }
564
+ }
565
+ if (!transform) {
566
+ if (isWeb && val[0] !== '_') {
567
+ // runtime insert
568
+ transform = val
569
+ }
570
+ }
571
+ }
572
+ transforms[namespace] = transforms[namespace] || ['', '']
573
+ const identifier = val.replace('_transform', '')
574
+ transforms[namespace][0] += identifier
575
+ // ssr doesn't need to do anything just make the right classname
576
+ if (transform) {
577
+ transforms[namespace][1] += transform
578
+ }
579
+ } else {
580
+ classNames[key] = val
581
+ }
582
+ }
583
+ }
584
+
577
585
  /**
578
586
  * getSubStyle calls propMapper with props
579
587
  * 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/insertFont.ts CHANGED
@@ -27,7 +27,7 @@ export function parseFont<A extends GenericFont>(definition: A): DeepVariableObj
27
27
  const parsed: any = {}
28
28
  for (const attrKey in definition) {
29
29
  const attr = definition[attrKey]
30
- if (attrKey === 'family') {
30
+ if (attrKey === 'family' || attrKey === 'face') {
31
31
  parsed[attrKey] = attr
32
32
  continue
33
33
  }