@tamagui/web 1.53.2 → 1.54.1
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/CSSColorNames.js +17 -0
- package/dist/cjs/CSSColorNames.js.map +6 -0
- package/dist/cjs/GetRef.js +17 -0
- package/dist/cjs/GetRef.js.map +6 -0
- package/dist/cjs/Role.js +17 -0
- package/dist/cjs/Role.js.map +6 -0
- package/dist/cjs/contexts/ComponentContext.js +47 -0
- package/dist/cjs/contexts/ComponentContext.js.map +6 -0
- package/dist/cjs/createComponent.js +67 -20
- package/dist/cjs/createComponent.js.map +2 -2
- package/dist/cjs/createTamagui.js +1 -0
- package/dist/cjs/createTamagui.js.map +1 -1
- package/dist/cjs/helpers/createMediaStyle.js +13 -5
- package/dist/cjs/helpers/createMediaStyle.js.map +1 -1
- package/dist/cjs/helpers/createShallowSetState.js +39 -0
- package/dist/cjs/helpers/createShallowSetState.js.map +6 -0
- package/dist/cjs/helpers/createStyledContext.js +7 -2
- package/dist/cjs/helpers/createStyledContext.js.map +1 -1
- package/dist/cjs/helpers/getSplitStyles.js +40 -22
- package/dist/cjs/helpers/getSplitStyles.js.map +2 -2
- package/dist/cjs/helpers/getStylesAtomic.js.map +1 -1
- package/dist/cjs/helpers/getVariantExtras.js +3 -3
- package/dist/cjs/helpers/getVariantExtras.js.map +1 -1
- package/dist/cjs/helpers/propMapper.js +3 -3
- package/dist/cjs/helpers/propMapper.js.map +1 -1
- package/dist/cjs/helpers/pseudoDescriptors.js +9 -2
- package/dist/cjs/helpers/pseudoDescriptors.js.map +1 -1
- package/dist/cjs/hooks/useAnimationDriver.js +2 -2
- package/dist/cjs/hooks/useAnimationDriver.js.map +1 -1
- package/dist/cjs/hooks/useMedia.js +6 -3
- package/dist/cjs/hooks/useMedia.js.map +1 -1
- package/dist/cjs/hooks/useStyle.js +3 -7
- package/dist/cjs/hooks/useStyle.js.map +1 -1
- package/dist/cjs/index.js +8 -8
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/interfaces/CSSColorNames.js +17 -0
- package/dist/cjs/interfaces/CSSColorNames.js.map +6 -0
- package/dist/cjs/interfaces/GetRef.js +17 -0
- package/dist/cjs/interfaces/GetRef.js.map +6 -0
- package/dist/cjs/interfaces/Role.js +17 -0
- package/dist/cjs/interfaces/Role.js.map +6 -0
- package/dist/cjs/styled.js.map +1 -1
- package/dist/cjs/types/CSSColorNames.js +17 -0
- package/dist/cjs/types/CSSColorNames.js.map +6 -0
- package/dist/cjs/types/GetRef.js +17 -0
- package/dist/cjs/types/GetRef.js.map +6 -0
- package/dist/cjs/types/Role.js +17 -0
- package/dist/cjs/types/Role.js.map +6 -0
- package/dist/cjs/views/AnimationDriverProvider.js +2 -2
- package/dist/cjs/views/AnimationDriverProvider.js.map +1 -1
- package/dist/cjs/views/FontLanguage.native.js +3 -3
- package/dist/cjs/views/FontLanguage.native.js.map +1 -1
- package/dist/cjs/views/TamaguiProvider.js +3 -5
- package/dist/cjs/views/TamaguiProvider.js.map +1 -1
- package/dist/esm/CSSColorNames.js +1 -0
- package/dist/esm/CSSColorNames.js.map +6 -0
- package/dist/esm/GetRef.js +1 -0
- package/dist/esm/GetRef.js.map +6 -0
- package/dist/esm/Role.js +1 -0
- package/dist/esm/Role.js.map +6 -0
- package/dist/esm/contexts/ComponentContext.js +23 -0
- package/dist/esm/contexts/ComponentContext.js.map +6 -0
- package/dist/esm/createComponent.js +68 -20
- package/dist/esm/createComponent.js.map +2 -2
- package/dist/esm/createTamagui.js +1 -0
- package/dist/esm/createTamagui.js.map +1 -1
- package/dist/esm/helpers/createMediaStyle.js +13 -5
- package/dist/esm/helpers/createMediaStyle.js.map +1 -1
- package/dist/esm/helpers/createShallowSetState.js +15 -0
- package/dist/esm/helpers/createShallowSetState.js.map +6 -0
- package/dist/esm/helpers/createStyledContext.js +7 -2
- package/dist/esm/helpers/createStyledContext.js.map +1 -1
- package/dist/esm/helpers/getSplitStyles.js +41 -23
- package/dist/esm/helpers/getSplitStyles.js.map +2 -2
- package/dist/esm/helpers/getStylesAtomic.js.map +1 -1
- package/dist/esm/helpers/getVariantExtras.js +3 -3
- package/dist/esm/helpers/getVariantExtras.js.map +1 -1
- package/dist/esm/helpers/propMapper.js +3 -3
- package/dist/esm/helpers/propMapper.js.map +1 -1
- package/dist/esm/helpers/pseudoDescriptors.js +7 -1
- package/dist/esm/helpers/pseudoDescriptors.js.map +1 -1
- package/dist/esm/hooks/useAnimationDriver.js +2 -2
- package/dist/esm/hooks/useAnimationDriver.js.map +1 -1
- package/dist/esm/hooks/useMedia.js +6 -3
- package/dist/esm/hooks/useMedia.js.map +1 -1
- package/dist/esm/hooks/useStyle.js +3 -7
- package/dist/esm/hooks/useStyle.js.map +1 -1
- package/dist/esm/index.js +5 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/interfaces/CSSColorNames.js +1 -0
- package/dist/esm/interfaces/CSSColorNames.js.map +6 -0
- package/dist/esm/interfaces/GetRef.js +1 -0
- package/dist/esm/interfaces/GetRef.js.map +6 -0
- package/dist/esm/interfaces/Role.js +1 -0
- package/dist/esm/interfaces/Role.js.map +6 -0
- package/dist/esm/styled.js.map +1 -1
- package/dist/esm/types/CSSColorNames.js +1 -0
- package/dist/esm/types/CSSColorNames.js.map +6 -0
- package/dist/esm/types/GetRef.js +1 -0
- package/dist/esm/types/GetRef.js.map +6 -0
- package/dist/esm/types/Role.js +1 -0
- package/dist/esm/types/Role.js.map +6 -0
- package/dist/esm/views/AnimationDriverProvider.js +2 -2
- package/dist/esm/views/AnimationDriverProvider.js.map +1 -1
- package/dist/esm/views/FontLanguage.native.js +3 -3
- package/dist/esm/views/FontLanguage.native.js.map +1 -1
- package/dist/esm/views/TamaguiProvider.js +3 -5
- package/dist/esm/views/TamaguiProvider.js.map +1 -1
- package/package.json +10 -10
- package/src/contexts/ComponentContext.tsx +22 -0
- package/src/createComponent.tsx +108 -26
- package/src/createTamagui.ts +1 -0
- package/src/helpers/createMediaStyle.ts +14 -5
- package/src/helpers/{useShallowSetState.tsx → createShallowSetState.tsx} +1 -1
- package/src/helpers/createStyledContext.tsx +7 -2
- package/src/helpers/getSplitStyles.tsx +47 -19
- package/src/helpers/getStylesAtomic.ts +1 -1
- package/src/helpers/getVariantExtras.tsx +3 -3
- package/src/helpers/propMapper.ts +5 -5
- package/src/helpers/pseudoDescriptors.ts +7 -0
- package/src/hooks/useAnimationDriver.tsx +2 -2
- package/src/hooks/useMedia.tsx +10 -3
- package/src/hooks/useStyle.tsx +3 -7
- package/src/index.ts +7 -6
- package/src/interfaces/CSSColorNames.tsx +141 -0
- package/src/interfaces/GetRef.tsx +23 -0
- package/src/interfaces/Role.tsx +68 -0
- package/src/styled.tsx +1 -1
- package/src/types.tsx +91 -272
- package/src/views/AnimationDriverProvider.tsx +3 -3
- package/src/views/FontLanguage.native.tsx +3 -3
- package/src/views/TamaguiProvider.tsx +11 -19
- package/types/CSSColorNames.d.ts +2 -0
- package/types/CSSColorNames.d.ts.map +1 -0
- package/types/GetRef.d.ts +23 -0
- package/types/GetRef.d.ts.map +1 -0
- package/types/Role.d.ts +2 -0
- package/types/Role.d.ts.map +1 -0
- package/types/contexts/ComponentContext.d.ts +3 -0
- package/types/contexts/ComponentContext.d.ts.map +1 -0
- package/types/createComponent.d.ts +2 -2
- package/types/createComponent.d.ts.map +1 -1
- package/types/createTamagui.d.ts.map +1 -1
- package/types/helpers/createMediaStyle.d.ts.map +1 -1
- package/types/helpers/createShallowSetState.d.ts +4 -0
- package/types/helpers/createShallowSetState.d.ts.map +1 -0
- package/types/helpers/createStyledContext.d.ts.map +1 -1
- package/types/helpers/getSplitStyles.d.ts +2 -3
- package/types/helpers/getSplitStyles.d.ts.map +1 -1
- package/types/helpers/pseudoDescriptors.d.ts +5 -0
- package/types/helpers/pseudoDescriptors.d.ts.map +1 -1
- package/types/hooks/useAnimationDriver.d.ts +3 -1
- package/types/hooks/useAnimationDriver.d.ts.map +1 -1
- package/types/hooks/useMedia.d.ts +1 -1
- package/types/hooks/useMedia.d.ts.map +1 -1
- package/types/hooks/useStyle.d.ts.map +1 -1
- package/types/index.d.ts +5 -5
- package/types/index.d.ts.map +1 -1
- package/types/interfaces/CSSColorNames.d.ts +2 -0
- package/types/interfaces/CSSColorNames.d.ts.map +1 -0
- package/types/interfaces/GetRef.d.ts +6 -0
- package/types/interfaces/GetRef.d.ts.map +1 -0
- package/types/interfaces/Role.d.ts +2 -0
- package/types/interfaces/Role.d.ts.map +1 -0
- package/types/styled.d.ts +2 -1
- package/types/styled.d.ts.map +1 -1
- package/types/types/CSSColorNames.d.ts +2 -0
- package/types/types/CSSColorNames.d.ts.map +1 -0
- package/types/types/GetRef.d.ts +6 -0
- package/types/types/GetRef.d.ts.map +1 -0
- package/types/types/Role.d.ts +2 -0
- package/types/types/Role.d.ts.map +1 -0
- package/types/types.d.ts +58 -31
- package/types/types.d.ts.map +1 -1
- package/types/views/TamaguiProvider.d.ts.map +1 -1
- package/src/contexts/AnimationDriverContext.tsx +0 -5
- package/src/contexts/ButtonNestingContext.tsx +0 -3
- package/src/contexts/FontLanguageContext.tsx +0 -5
- package/src/contexts/TextAncestorContext.tsx +0 -3
package/src/createComponent.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useComposedRefs } from '@tamagui/compose-refs'
|
|
2
|
-
import { isClient, isServer, isWeb
|
|
2
|
+
import { isClient, isServer, isWeb } from '@tamagui/constants'
|
|
3
3
|
import { validStyles } from '@tamagui/helpers'
|
|
4
4
|
import { useDidFinishSSR } from '@tamagui/use-did-finish-ssr'
|
|
5
5
|
import React, {
|
|
@@ -12,35 +12,38 @@ import React, {
|
|
|
12
12
|
useContext,
|
|
13
13
|
useEffect,
|
|
14
14
|
useId,
|
|
15
|
+
useMemo,
|
|
15
16
|
useRef,
|
|
16
17
|
useState,
|
|
17
18
|
} from 'react'
|
|
18
19
|
|
|
19
20
|
import { getConfig, onConfiguredOnce } from './config'
|
|
20
21
|
import { stackDefaultStyles } from './constants/constants'
|
|
21
|
-
import {
|
|
22
|
-
import { TextAncestorContext } from './contexts/TextAncestorContext'
|
|
22
|
+
import { ComponentContext } from './contexts/ComponentContext'
|
|
23
23
|
import { didGetVariableValue, setDidGetVariableValue } from './createVariable'
|
|
24
|
+
import { createShallowSetState } from './helpers/createShallowSetState'
|
|
24
25
|
import { useSplitStyles } from './helpers/getSplitStyles'
|
|
25
26
|
import { mergeProps } from './helpers/mergeProps'
|
|
26
27
|
import { proxyThemeVariables } from './helpers/proxyThemeVariables'
|
|
27
28
|
import { themeable } from './helpers/themeable'
|
|
28
|
-
import { useShallowSetState } from './helpers/useShallowSetState'
|
|
29
|
-
import { useAnimationDriver } from './hooks/useAnimationDriver'
|
|
30
29
|
import { setMediaShouldUpdate, useMedia } from './hooks/useMedia'
|
|
31
30
|
import { useThemeWithState } from './hooks/useTheme'
|
|
32
31
|
import { hooks } from './setupHooks'
|
|
33
32
|
import {
|
|
34
33
|
DebugProp,
|
|
34
|
+
DisposeFn,
|
|
35
|
+
GroupContextType,
|
|
35
36
|
SpaceDirection,
|
|
36
37
|
SpaceValue,
|
|
37
38
|
SpacerProps,
|
|
39
|
+
StackProps,
|
|
38
40
|
StaticConfig,
|
|
39
41
|
TamaguiComponent,
|
|
40
42
|
TamaguiComponentEvents,
|
|
41
43
|
TamaguiComponentState,
|
|
42
44
|
TamaguiElement,
|
|
43
45
|
TamaguiInternalConfig,
|
|
46
|
+
TextProps,
|
|
44
47
|
UseAnimationHook,
|
|
45
48
|
UseAnimationProps,
|
|
46
49
|
} from './types'
|
|
@@ -97,7 +100,7 @@ let BaseView: any
|
|
|
97
100
|
let hasSetupBaseViews = false
|
|
98
101
|
|
|
99
102
|
export function createComponent<
|
|
100
|
-
ComponentPropTypes extends
|
|
103
|
+
ComponentPropTypes extends StackProps | TextProps = {},
|
|
101
104
|
Ref = TamaguiElement,
|
|
102
105
|
BaseProps = never
|
|
103
106
|
>(staticConfig: StaticConfig) {
|
|
@@ -142,7 +145,7 @@ export function createComponent<
|
|
|
142
145
|
}
|
|
143
146
|
}
|
|
144
147
|
|
|
145
|
-
const component = forwardRef<Ref, ComponentPropTypes>((propsIn
|
|
148
|
+
const component = forwardRef<Ref, ComponentPropTypes>((propsIn, forwardedRef) => {
|
|
146
149
|
if (process.env.TAMAGUI_TARGET === 'native') {
|
|
147
150
|
// todo this could be moved to a cleaner location
|
|
148
151
|
if (!hasSetupBaseViews) {
|
|
@@ -163,6 +166,8 @@ export function createComponent<
|
|
|
163
166
|
}
|
|
164
167
|
}
|
|
165
168
|
|
|
169
|
+
const componentContext = useContext(ComponentContext)
|
|
170
|
+
|
|
166
171
|
// set variants through context
|
|
167
172
|
// order is after default props but before props
|
|
168
173
|
let styledContextProps: Object | undefined
|
|
@@ -204,7 +209,7 @@ export function createComponent<
|
|
|
204
209
|
|
|
205
210
|
// React inserts default props after your props for some reason...
|
|
206
211
|
// order important so we do loops, you can't just spread because JS does weird things
|
|
207
|
-
let props:
|
|
212
|
+
let props: StackProps | TextProps
|
|
208
213
|
if (curDefaultProps) {
|
|
209
214
|
props = mergeProps(curDefaultProps, propsIn)
|
|
210
215
|
} else {
|
|
@@ -244,7 +249,7 @@ export function createComponent<
|
|
|
244
249
|
/**
|
|
245
250
|
* Component state for tracking animations, pseudos
|
|
246
251
|
*/
|
|
247
|
-
const animationsConfig =
|
|
252
|
+
const animationsConfig = componentContext.animationDriver
|
|
248
253
|
const useAnimations = animationsConfig?.useAnimations as UseAnimationHook | undefined
|
|
249
254
|
|
|
250
255
|
// after we get states mount we need to turn off isAnimated for server side
|
|
@@ -283,8 +288,24 @@ export function createComponent<
|
|
|
283
288
|
: states[0]
|
|
284
289
|
const setState = states[1]
|
|
285
290
|
|
|
286
|
-
|
|
287
|
-
|
|
291
|
+
let setStateShallow = createShallowSetState(setState)
|
|
292
|
+
|
|
293
|
+
const groupName = props.group as any as string
|
|
294
|
+
if (groupName) {
|
|
295
|
+
// when we set state we also set our group state and emit an event for children listening:
|
|
296
|
+
const groupContextState = componentContext.groups.state
|
|
297
|
+
const og = setStateShallow
|
|
298
|
+
setStateShallow = (state) => {
|
|
299
|
+
og(state)
|
|
300
|
+
componentContext.groups.emit(groupName, state)
|
|
301
|
+
// and mutate the current since its concurrent safe (children throw it in useState on mount)
|
|
302
|
+
const next = {
|
|
303
|
+
...groupContextState[groupName],
|
|
304
|
+
...state,
|
|
305
|
+
}
|
|
306
|
+
groupContextState[groupName] = next
|
|
307
|
+
}
|
|
308
|
+
}
|
|
288
309
|
|
|
289
310
|
if (process.env.NODE_ENV === 'development' && time) time`use-state`
|
|
290
311
|
|
|
@@ -308,8 +329,8 @@ export function createComponent<
|
|
|
308
329
|
: props.componentName
|
|
309
330
|
? `is_${props.componentName}`
|
|
310
331
|
: defaultComponentClassName
|
|
311
|
-
|
|
312
|
-
const
|
|
332
|
+
|
|
333
|
+
const hasTextAncestor = !!(isWeb && isText ? componentContext.inText : false)
|
|
313
334
|
const isDisabled = props.disabled ?? props.accessibilityState?.disabled
|
|
314
335
|
|
|
315
336
|
if (process.env.NODE_ENV === 'development' && time) time`use-context`
|
|
@@ -372,8 +393,6 @@ export function createComponent<
|
|
|
372
393
|
const themeStateProps = {
|
|
373
394
|
name: props.theme,
|
|
374
395
|
componentName,
|
|
375
|
-
reset: props.reset,
|
|
376
|
-
inverse: props.themeInverse,
|
|
377
396
|
// @ts-ignore this is internal use only
|
|
378
397
|
disable: disableTheme,
|
|
379
398
|
shallow: stateRef.current.themeShallow,
|
|
@@ -464,7 +483,6 @@ export function createComponent<
|
|
|
464
483
|
const styleProps = {
|
|
465
484
|
mediaState,
|
|
466
485
|
noClassNames,
|
|
467
|
-
hasTextAncestor,
|
|
468
486
|
resolveVariablesAs,
|
|
469
487
|
isExiting,
|
|
470
488
|
isAnimated,
|
|
@@ -479,7 +497,7 @@ export function createComponent<
|
|
|
479
497
|
state,
|
|
480
498
|
styleProps,
|
|
481
499
|
null,
|
|
482
|
-
|
|
500
|
+
componentContext,
|
|
483
501
|
elementType,
|
|
484
502
|
debugProp
|
|
485
503
|
)
|
|
@@ -559,7 +577,6 @@ export function createComponent<
|
|
|
559
577
|
styleProps,
|
|
560
578
|
theme: themeState.state.theme!,
|
|
561
579
|
pseudos: pseudos || null,
|
|
562
|
-
onDidAnimate: props.onDidAnimate,
|
|
563
580
|
hostRef,
|
|
564
581
|
staticConfig,
|
|
565
582
|
})
|
|
@@ -601,7 +618,10 @@ export function createComponent<
|
|
|
601
618
|
|
|
602
619
|
if (process.env.NODE_ENV === 'development' && time) time`destructure`
|
|
603
620
|
|
|
604
|
-
const disabled =
|
|
621
|
+
const disabled =
|
|
622
|
+
props.accessibilityState?.disabled ||
|
|
623
|
+
// @ts-expect-error (comes from core)
|
|
624
|
+
props.accessibilityDisabled
|
|
605
625
|
|
|
606
626
|
// these can ultimately be for DOM, react-native-web views, or animated views
|
|
607
627
|
// so the type is pretty loose
|
|
@@ -647,12 +667,12 @@ export function createComponent<
|
|
|
647
667
|
})
|
|
648
668
|
}, [])
|
|
649
669
|
|
|
650
|
-
const shouldSetMounted = needsMount && state.unmounted
|
|
651
|
-
|
|
652
670
|
// combined multiple effects into one for performance so be careful with logic
|
|
653
671
|
// should not be a layout effect because otherwise it wont render the initial state
|
|
654
672
|
// for example css driver needs to render once with the first styles, then again with the next
|
|
655
673
|
// if its a layout effect it will just skip that first render output
|
|
674
|
+
const shouldSetMounted = needsMount && state.unmounted
|
|
675
|
+
const { pseudoGroups } = splitStyles
|
|
656
676
|
useEffect(() => {
|
|
657
677
|
if (shouldSetMounted) {
|
|
658
678
|
const unmounted =
|
|
@@ -664,10 +684,35 @@ export function createComponent<
|
|
|
664
684
|
// no need for mouseUp removal effect if its not even mounted yet
|
|
665
685
|
}
|
|
666
686
|
|
|
687
|
+
// parent group pseudo listening
|
|
688
|
+
let disposeGroupsListener: DisposeFn | undefined
|
|
689
|
+
if (pseudoGroups) {
|
|
690
|
+
const current = {}
|
|
691
|
+
disposeGroupsListener = componentContext.groups.subscribe((name, next) => {
|
|
692
|
+
if (pseudoGroups.has(name)) {
|
|
693
|
+
// merge because we emit a partial of the state each time
|
|
694
|
+
Object.assign(current, next)
|
|
695
|
+
const group = {
|
|
696
|
+
...state.group,
|
|
697
|
+
[name]: current,
|
|
698
|
+
}
|
|
699
|
+
setStateShallow({
|
|
700
|
+
// force it to be referentially different so it always updates
|
|
701
|
+
group,
|
|
702
|
+
})
|
|
703
|
+
}
|
|
704
|
+
})
|
|
705
|
+
}
|
|
706
|
+
|
|
667
707
|
return () => {
|
|
708
|
+
disposeGroupsListener?.()
|
|
668
709
|
mouseUps.delete(unPress)
|
|
669
710
|
}
|
|
670
|
-
}, [
|
|
711
|
+
}, [
|
|
712
|
+
shouldSetMounted,
|
|
713
|
+
state.unmounted,
|
|
714
|
+
pseudoGroups ? Object.keys([...pseudoGroups]).join('') : 0,
|
|
715
|
+
])
|
|
671
716
|
|
|
672
717
|
const avoidAnimationStyle = keepStyleSSR && state.unmounted === true
|
|
673
718
|
|
|
@@ -690,6 +735,7 @@ export function createComponent<
|
|
|
690
735
|
componentName ? componentClassName : '',
|
|
691
736
|
fontFamilyClassName,
|
|
692
737
|
classNames ? Object.values(classNames).join(' ') : '',
|
|
738
|
+
props.group ? `t_group_${props.group}` : '',
|
|
693
739
|
]
|
|
694
740
|
className = classList.join(' ')
|
|
695
741
|
|
|
@@ -724,14 +770,29 @@ export function createComponent<
|
|
|
724
770
|
viewProps.style = style
|
|
725
771
|
}
|
|
726
772
|
|
|
773
|
+
// if its a group its gotta listen for pseudos to emit them to children
|
|
774
|
+
|
|
727
775
|
const runtimePressStyle = !disabled && noClassNames && pseudos?.pressStyle
|
|
728
776
|
const attachPress = Boolean(
|
|
729
|
-
|
|
777
|
+
groupName ||
|
|
778
|
+
runtimePressStyle ||
|
|
779
|
+
onPress ||
|
|
780
|
+
onPressOut ||
|
|
781
|
+
onPressIn ||
|
|
782
|
+
onLongPress ||
|
|
783
|
+
onClick
|
|
730
784
|
)
|
|
731
785
|
const runtimeHoverStyle = !disabled && noClassNames && pseudos?.hoverStyle
|
|
732
786
|
const isHoverable =
|
|
733
787
|
isWeb &&
|
|
734
|
-
!!(
|
|
788
|
+
!!(
|
|
789
|
+
groupName ||
|
|
790
|
+
runtimeHoverStyle ||
|
|
791
|
+
onHoverIn ||
|
|
792
|
+
onHoverOut ||
|
|
793
|
+
onMouseEnter ||
|
|
794
|
+
onMouseLeave
|
|
795
|
+
)
|
|
735
796
|
|
|
736
797
|
const handlesPressEvents = !(isWeb || asChild)
|
|
737
798
|
|
|
@@ -785,7 +846,6 @@ export function createComponent<
|
|
|
785
846
|
setStateShallow({
|
|
786
847
|
press: true,
|
|
787
848
|
pressIn: true,
|
|
788
|
-
hover: false,
|
|
789
849
|
})
|
|
790
850
|
onPressIn?.(e)
|
|
791
851
|
onMouseDown?.(e)
|
|
@@ -872,6 +932,28 @@ export function createComponent<
|
|
|
872
932
|
|
|
873
933
|
content = createElement(elementType, viewProps, content)
|
|
874
934
|
|
|
935
|
+
// must override context so siblings don't clobber initial state
|
|
936
|
+
const subGroupContext = useMemo(() => {
|
|
937
|
+
if (!groupName) return null
|
|
938
|
+
// change reference so context value updates
|
|
939
|
+
return {
|
|
940
|
+
...componentContext.groups,
|
|
941
|
+
// change reference so as we mutate it doesn't affect siblings etc
|
|
942
|
+
state: {
|
|
943
|
+
...componentContext.groups.state,
|
|
944
|
+
[groupName]: initialState,
|
|
945
|
+
},
|
|
946
|
+
}
|
|
947
|
+
}, [groupName])
|
|
948
|
+
|
|
949
|
+
if (groupName && subGroupContext) {
|
|
950
|
+
content = (
|
|
951
|
+
<ComponentContext.Provider groups={subGroupContext}>
|
|
952
|
+
{content}
|
|
953
|
+
</ComponentContext.Provider>
|
|
954
|
+
)
|
|
955
|
+
}
|
|
956
|
+
|
|
875
957
|
// disable theme prop is deterministic so conditional hook ok here
|
|
876
958
|
content = disableThemeProp
|
|
877
959
|
? content
|
|
@@ -1038,7 +1120,7 @@ Unspaced['isUnspaced'] = true
|
|
|
1038
1120
|
|
|
1039
1121
|
// dont used styled() here to avoid circular deps
|
|
1040
1122
|
// keep inline to avoid circular deps
|
|
1041
|
-
|
|
1123
|
+
// @ts-expect-error we override
|
|
1042
1124
|
export const Spacer = createComponent<SpacerProps>({
|
|
1043
1125
|
acceptsClassName: true,
|
|
1044
1126
|
memo: true,
|
package/src/createTamagui.ts
CHANGED
|
@@ -9,6 +9,12 @@ export const MEDIA_SEP = '_'
|
|
|
9
9
|
let prefixes: Record<string, string> | null = null
|
|
10
10
|
let selectors: Record<string, string> | null = null
|
|
11
11
|
|
|
12
|
+
const parentPseudoToSelector = {
|
|
13
|
+
hovered: ':hover',
|
|
14
|
+
focused: ':focus',
|
|
15
|
+
pressed: ':active',
|
|
16
|
+
}
|
|
17
|
+
|
|
12
18
|
export const createMediaStyle = (
|
|
13
19
|
{ property, identifier, rules }: StyleObject,
|
|
14
20
|
mediaKey: string,
|
|
@@ -20,7 +26,8 @@ export const createMediaStyle = (
|
|
|
20
26
|
const enableMediaPropOrder = conf.settings.mediaPropOrder
|
|
21
27
|
const isThemeMedia = mediaKey.startsWith('theme-')
|
|
22
28
|
const isPlatformMedia = !isThemeMedia && mediaKey.startsWith('platform-')
|
|
23
|
-
const
|
|
29
|
+
const isGroupMedia = !isThemeMedia && !isPlatformMedia && mediaKey.startsWith('group-')
|
|
30
|
+
const isNonWindowMedia = isThemeMedia || isPlatformMedia || isGroupMedia
|
|
24
31
|
const negKey = negate ? '0' : ''
|
|
25
32
|
const ogPrefix = identifier.slice(0, identifier.indexOf('-') + 1)
|
|
26
33
|
|
|
@@ -29,19 +36,21 @@ export const createMediaStyle = (
|
|
|
29
36
|
const id = `${ogPrefix}${MEDIA_SEP}${mediaKey.replace('-', '')}${negKey}${MEDIA_SEP}`
|
|
30
37
|
const nextIdentifier = identifier.replace(ogPrefix, id)
|
|
31
38
|
|
|
32
|
-
if (
|
|
39
|
+
if (isNonWindowMedia) {
|
|
33
40
|
const precedencePrefix = new Array(priority).fill(':root').join('')
|
|
34
41
|
const styleInner = rules
|
|
35
42
|
.map((rule) => rule.replace(identifier, nextIdentifier))
|
|
36
43
|
.join(';')
|
|
37
44
|
|
|
38
|
-
if (isThemeMedia) {
|
|
39
|
-
const
|
|
45
|
+
if (isThemeMedia || isGroupMedia) {
|
|
46
|
+
const keyParts = mediaKey.split('-')
|
|
47
|
+
const name = (isGroupMedia ? 'group_' : '') + keyParts[1]
|
|
40
48
|
const selectorStart = styleInner.indexOf(':root')
|
|
41
49
|
const selectorEnd = styleInner.lastIndexOf('{')
|
|
42
50
|
const selector = styleInner.slice(selectorStart, selectorEnd)
|
|
43
51
|
const precedenceSpace = conf.themeClassNameOnRoot ? '' : ' '
|
|
44
|
-
const
|
|
52
|
+
const pseudoSelector = parentPseudoToSelector[keyParts[2]] || ''
|
|
53
|
+
const nextSelector = `:root${precedencePrefix}${precedenceSpace}.t_${name}${pseudoSelector} ${selector.replace(
|
|
45
54
|
':root',
|
|
46
55
|
''
|
|
47
56
|
)}`
|
|
@@ -2,7 +2,7 @@ import React from 'react'
|
|
|
2
2
|
|
|
3
3
|
import { TamaguiComponentState } from '../types'
|
|
4
4
|
|
|
5
|
-
export function
|
|
5
|
+
export function createShallowSetState<State extends TamaguiComponentState>(
|
|
6
6
|
setter: React.Dispatch<React.SetStateAction<State>>
|
|
7
7
|
) {
|
|
8
8
|
return (next: Partial<State>) => setter((prev) => shallow(prev, next))
|
|
@@ -18,7 +18,7 @@ export type StyledContext<Props extends Object = any> = Omit<
|
|
|
18
18
|
export function createStyledContext<VariantProps extends Record<string, any>>(
|
|
19
19
|
props: VariantProps
|
|
20
20
|
): StyledContext<VariantProps> {
|
|
21
|
-
const OGContext = createContext<
|
|
21
|
+
const OGContext = createContext<VariantProps>(props)
|
|
22
22
|
const OGProvider = OGContext.Provider
|
|
23
23
|
const Context = OGContext as any as StyledContext<VariantProps>
|
|
24
24
|
|
|
@@ -26,7 +26,12 @@ export function createStyledContext<VariantProps extends Record<string, any>>(
|
|
|
26
26
|
children,
|
|
27
27
|
...values
|
|
28
28
|
}: VariantProps & { children?: React.ReactNode }) => {
|
|
29
|
-
const value = useMemo(() =>
|
|
29
|
+
const value = useMemo(() => {
|
|
30
|
+
return {
|
|
31
|
+
...props,
|
|
32
|
+
...values,
|
|
33
|
+
}
|
|
34
|
+
}, [objectIdentityKey(values)])
|
|
30
35
|
return <OGProvider value={value}>{children}</OGProvider>
|
|
31
36
|
}
|
|
32
37
|
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
} from '../hooks/useMedia'
|
|
34
34
|
import type {
|
|
35
35
|
ClassNamesObject,
|
|
36
|
+
ComponentContextI,
|
|
36
37
|
DebugProp,
|
|
37
38
|
GetStyleResult,
|
|
38
39
|
GetStyleState,
|
|
@@ -66,7 +67,7 @@ import {
|
|
|
66
67
|
reverseMapClassNameToValue,
|
|
67
68
|
} from './normalizeValueWithProperty'
|
|
68
69
|
import { getPropMappedFontFamily, propMapper } from './propMapper'
|
|
69
|
-
import { pseudoDescriptors } from './pseudoDescriptors'
|
|
70
|
+
import { pseudoDescriptors, pseudoPriorities } from './pseudoDescriptors'
|
|
70
71
|
|
|
71
72
|
const fontFamilyKey = 'fontFamily'
|
|
72
73
|
|
|
@@ -89,7 +90,7 @@ type StyleSplitter = (
|
|
|
89
90
|
componentState: TamaguiComponentState,
|
|
90
91
|
styleProps: SplitStyleProps,
|
|
91
92
|
parentSplitStyles?: GetStyleResult | null,
|
|
92
|
-
|
|
93
|
+
context?: ComponentContextI,
|
|
93
94
|
// web-only
|
|
94
95
|
elementType?: string,
|
|
95
96
|
debug?: DebugProp
|
|
@@ -126,7 +127,7 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
126
127
|
componentState,
|
|
127
128
|
styleProps,
|
|
128
129
|
parentSplitStyles,
|
|
129
|
-
|
|
130
|
+
context,
|
|
130
131
|
elementType,
|
|
131
132
|
debug
|
|
132
133
|
) => {
|
|
@@ -150,6 +151,7 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
150
151
|
let space: SpaceTokens | null = props.space
|
|
151
152
|
let hasMedia: boolean | string[] = false
|
|
152
153
|
let dynamicThemeAccess: boolean | undefined
|
|
154
|
+
let pseudoGroups: Set<string> | undefined
|
|
153
155
|
const shouldDoClasses = acceptsClassName && isWeb && !styleProps.noClassNames
|
|
154
156
|
|
|
155
157
|
let style: ViewStyleWithPseudos = {}
|
|
@@ -166,7 +168,7 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
166
168
|
* Not the biggest fan of creating this object but it is a nice API
|
|
167
169
|
*/
|
|
168
170
|
const styleState: GetStyleState = {
|
|
169
|
-
curProps: {
|
|
171
|
+
curProps: Object.assign({}, props),
|
|
170
172
|
classNames,
|
|
171
173
|
conf,
|
|
172
174
|
props,
|
|
@@ -177,7 +179,7 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
177
179
|
theme,
|
|
178
180
|
usedKeys,
|
|
179
181
|
viewProps,
|
|
180
|
-
|
|
182
|
+
context,
|
|
181
183
|
debug,
|
|
182
184
|
}
|
|
183
185
|
|
|
@@ -594,7 +596,7 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
594
596
|
(typeof valInit === 'string' && valInit[0] !== '$')))
|
|
595
597
|
|
|
596
598
|
const expanded = avoidPropMap
|
|
597
|
-
? [[keyInit, valInit]]
|
|
599
|
+
? ([[keyInit, valInit]] as const)
|
|
598
600
|
: propMapper(keyInit, valInit, styleState)
|
|
599
601
|
|
|
600
602
|
const next = getPropMappedFontFamily(expanded)
|
|
@@ -847,7 +849,7 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
847
849
|
if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
|
|
848
850
|
// prettier-ignore
|
|
849
851
|
// rome-ignore lint/nursery/noConsoleLog: ok
|
|
850
|
-
console.log(` 📺 ${key}`, { key, val, mediaStyle, props, shouldDoClasses });
|
|
852
|
+
console.log(` 📺 ${key}`, { key, val, mediaStyle, props, shouldDoClasses, componentState });
|
|
851
853
|
}
|
|
852
854
|
|
|
853
855
|
// for some reason 'space' in val upsetting next ssr during prod build
|
|
@@ -901,33 +903,56 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
901
903
|
mergeClassName(transforms, classNames, fullKey, out.identifier, true, true)
|
|
902
904
|
}
|
|
903
905
|
} else {
|
|
904
|
-
const isThemeMedia = mediaKeyShort.startsWith('theme-')
|
|
905
|
-
const
|
|
906
|
+
const isThemeMedia = !isPlatformMedia && mediaKeyShort.startsWith('theme-')
|
|
907
|
+
const isGroupMedia =
|
|
908
|
+
!isPlatformMedia && !isThemeMedia && mediaKeyShort.startsWith('group-')
|
|
906
909
|
|
|
907
|
-
if (!isThemeMedia && !isPlatformMedia) {
|
|
910
|
+
if (!isThemeMedia && !isPlatformMedia && !isGroupMedia) {
|
|
908
911
|
if (!mediaState[mediaKeyShort]) {
|
|
909
912
|
continue
|
|
910
913
|
}
|
|
911
914
|
}
|
|
912
915
|
|
|
916
|
+
let importanceBump = 0
|
|
917
|
+
|
|
913
918
|
if (isThemeMedia) {
|
|
914
919
|
// needed to get updates when theme changes
|
|
915
920
|
dynamicThemeAccess = true
|
|
916
|
-
|
|
917
921
|
const mediaThemeName = mediaKeyShort.slice(6)
|
|
918
922
|
if (!(themeName === mediaThemeName || themeName.startsWith(mediaThemeName))) {
|
|
919
923
|
continue
|
|
920
924
|
}
|
|
925
|
+
} else if (isGroupMedia) {
|
|
926
|
+
const [_, groupName, groupPseudoKey] = mediaKeyShort.split('-')
|
|
927
|
+
|
|
928
|
+
// $group-x
|
|
929
|
+
if (!context?.groups.state[groupName]) {
|
|
930
|
+
if (process.env.NODE_ENV === 'development' && debug) {
|
|
931
|
+
console.warn(`No parent with group prop, skipping styles: ${groupName}`)
|
|
932
|
+
}
|
|
933
|
+
continue
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
// $group-x-hovered
|
|
937
|
+
pseudoGroups ||= new Set()
|
|
938
|
+
pseudoGroups.add(groupName)
|
|
939
|
+
if (groupPseudoKey) {
|
|
940
|
+
const groupPseudoKeyShort = groupPseudoKey.replace('ed', '')
|
|
941
|
+
const groupState =
|
|
942
|
+
componentState.group?.[groupName] ||
|
|
943
|
+
// fallback to context initially
|
|
944
|
+
context.groups.state[groupName]
|
|
945
|
+
|
|
946
|
+
const isActive = groupState?.[groupPseudoKeyShort]
|
|
947
|
+
if (!isActive) {
|
|
948
|
+
continue
|
|
949
|
+
}
|
|
950
|
+
const priority = pseudoPriorities[groupPseudoKeyShort]
|
|
951
|
+
importanceBump = priority
|
|
952
|
+
}
|
|
921
953
|
}
|
|
922
954
|
|
|
923
955
|
for (const subKey in mediaStyle) {
|
|
924
|
-
const importance = getMediaImportanceIfMoreImportant(
|
|
925
|
-
mediaKeyShort,
|
|
926
|
-
subKey,
|
|
927
|
-
usedKeys,
|
|
928
|
-
mediaState[mediaKeyShort]
|
|
929
|
-
)
|
|
930
|
-
if (importance === null) continue
|
|
931
956
|
if (subKey === 'space') {
|
|
932
957
|
space = valInit.space
|
|
933
958
|
continue
|
|
@@ -938,7 +963,8 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
938
963
|
subKey,
|
|
939
964
|
mediaStyle[subKey],
|
|
940
965
|
usedKeys,
|
|
941
|
-
mediaState[mediaKeyShort]
|
|
966
|
+
mediaState[mediaKeyShort],
|
|
967
|
+
importanceBump
|
|
942
968
|
)
|
|
943
969
|
if (key === fontFamilyKey) {
|
|
944
970
|
styleState.fontFamily = mediaStyle.fontFamily as string
|
|
@@ -1171,6 +1197,7 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
1171
1197
|
classNames,
|
|
1172
1198
|
rulesToInsert,
|
|
1173
1199
|
dynamicThemeAccess,
|
|
1200
|
+
pseudoGroups,
|
|
1174
1201
|
}
|
|
1175
1202
|
|
|
1176
1203
|
// native: swap out the right family based on weight/style
|
|
@@ -1399,6 +1426,7 @@ const skipProps = {
|
|
|
1399
1426
|
disableOptimization: 1,
|
|
1400
1427
|
tag: 1,
|
|
1401
1428
|
style: 1, // handled after loop so pseudos set usedKeys and override it if necessary
|
|
1429
|
+
group: 1,
|
|
1402
1430
|
}
|
|
1403
1431
|
|
|
1404
1432
|
if (process.env.NODE_ENV === 'test') {
|
|
@@ -4,10 +4,10 @@ import { LanguageContextType } from '../views/FontLanguage.types'
|
|
|
4
4
|
import { createProxy } from './createProxy'
|
|
5
5
|
|
|
6
6
|
export function getVariantExtras(styleState: GetStyleState) {
|
|
7
|
-
const { curProps, conf,
|
|
7
|
+
const { curProps, conf, context, theme } = styleState
|
|
8
8
|
let fonts = conf.fontsParsed
|
|
9
|
-
if (
|
|
10
|
-
fonts = getFontsForLanguage(conf.fontsParsed,
|
|
9
|
+
if (context?.language) {
|
|
10
|
+
fonts = getFontsForLanguage(conf.fontsParsed, context.language)
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
// should be able to just use styleState.fontFamily but no time to test for now
|
|
@@ -341,7 +341,7 @@ const getToken = (
|
|
|
341
341
|
styleProps: SplitStyleProps,
|
|
342
342
|
styleState: GetStyleState
|
|
343
343
|
) => {
|
|
344
|
-
const { theme, conf,
|
|
344
|
+
const { theme, conf, context, fontFamily } = styleState
|
|
345
345
|
|
|
346
346
|
const tokensParsed = conf.tokensParsed
|
|
347
347
|
let valOrVar: any
|
|
@@ -360,8 +360,8 @@ const getToken = (
|
|
|
360
360
|
} else {
|
|
361
361
|
switch (key) {
|
|
362
362
|
case 'fontFamily': {
|
|
363
|
-
const fontsParsed =
|
|
364
|
-
? getFontsForLanguage(conf.fontsParsed,
|
|
363
|
+
const fontsParsed = context?.language
|
|
364
|
+
? getFontsForLanguage(conf.fontsParsed, context.language)
|
|
365
365
|
: conf.fontsParsed
|
|
366
366
|
valOrVar = fontsParsed[value]?.family || value
|
|
367
367
|
hasSet = true
|
|
@@ -373,8 +373,8 @@ const getToken = (
|
|
|
373
373
|
case 'fontWeight': {
|
|
374
374
|
const fam = fontFamily || styleState.conf.defaultFont
|
|
375
375
|
if (fam) {
|
|
376
|
-
const fontsParsed =
|
|
377
|
-
? getFontsForLanguage(conf.fontsParsed,
|
|
376
|
+
const fontsParsed = context?.language
|
|
377
|
+
? getFontsForLanguage(conf.fontsParsed, context.language)
|
|
378
378
|
: conf.fontsParsed
|
|
379
379
|
const font = fontsParsed[fam]
|
|
380
380
|
valOrVar = font?.[fontShorthand[key] || key]?.[value] || value
|
|
@@ -17,6 +17,13 @@ export const pseudoDescriptorsBase = {
|
|
|
17
17
|
},
|
|
18
18
|
} as const
|
|
19
19
|
|
|
20
|
+
// MATCH TO ABOVE but note that press = press not active
|
|
21
|
+
export const pseudoPriorities = {
|
|
22
|
+
hover: 1,
|
|
23
|
+
press: 2,
|
|
24
|
+
focus: 3,
|
|
25
|
+
}
|
|
26
|
+
|
|
20
27
|
export const pseudoDescriptors: Record<
|
|
21
28
|
'hoverStyle' | 'pressStyle' | 'focusStyle' | 'enterStyle' | 'exitStyle',
|
|
22
29
|
PseudoDescriptor
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useContext } from 'react'
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { ComponentContext } from '../contexts/ComponentContext'
|
|
4
4
|
import { getAnimationDriver } from '../helpers/getAnimationDriver'
|
|
5
5
|
|
|
6
6
|
export const useAnimationDriver = () => {
|
|
7
|
-
return useContext(
|
|
7
|
+
return useContext(ComponentContext).animationDriver ?? getAnimationDriver()
|
|
8
8
|
}
|