react-native-unistyles 3.5.0 → 3.5.2
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/Unistyles.podspec +1 -0
- package/cxx/common/UnistylesConstants.h +3 -0
- package/cxx/core/HostUnistyle.cpp +13 -1
- package/cxx/core/HostUnistyle.h +6 -2
- package/cxx/core/RNStyle.h +1 -1
- package/cxx/shadowTree/ShadowTreeDiagnostics.cpp +5 -0
- package/lib/commonjs/components/AdaptiveTheme.js +9 -1
- package/lib/commonjs/components/AdaptiveTheme.js.map +1 -1
- package/lib/commonjs/components/NamedTheme.js +9 -1
- package/lib/commonjs/components/NamedTheme.js.map +1 -1
- package/lib/commonjs/components/ScopedThemeContext.js +9 -0
- package/lib/commonjs/components/ScopedThemeContext.js.map +1 -0
- package/lib/commonjs/components/native/Pressable.native.js +6 -5
- package/lib/commonjs/components/native/Pressable.native.js.map +1 -1
- package/lib/commonjs/components/scopeChildren.js +29 -0
- package/lib/commonjs/components/scopeChildren.js.map +1 -0
- package/lib/commonjs/components/scopeChildren.native.js +9 -0
- package/lib/commonjs/components/scopeChildren.native.js.map +1 -0
- package/lib/commonjs/core/createUnistylesActivityIndicator.js +5 -3
- package/lib/commonjs/core/createUnistylesActivityIndicator.js.map +1 -1
- package/lib/commonjs/core/createUnistylesElement.js +1 -1
- package/lib/commonjs/core/createUnistylesElement.js.map +1 -1
- package/lib/commonjs/core/createUnistylesElement.native.js +3 -1
- package/lib/commonjs/core/createUnistylesElement.native.js.map +1 -1
- package/lib/commonjs/core/createUnistylesImageBackground.js +7 -4
- package/lib/commonjs/core/createUnistylesImageBackground.js.map +1 -1
- package/lib/commonjs/core/createUnistylesTouchableHighlight.js +6 -8
- package/lib/commonjs/core/createUnistylesTouchableHighlight.js.map +1 -1
- package/lib/commonjs/core/passForwardRef.js +15 -3
- package/lib/commonjs/core/passForwardRef.js.map +1 -1
- package/lib/commonjs/core/useProxifiedUnistyles/useProxifiedUnistyles.js +10 -5
- package/lib/commonjs/core/useProxifiedUnistyles/useProxifiedUnistyles.js.map +1 -1
- package/lib/commonjs/core/withUnistyles/withUnistyles.native.js +12 -2
- package/lib/commonjs/core/withUnistyles/withUnistyles.native.js.map +1 -1
- package/lib/commonjs/mocks.js +1 -1
- package/lib/commonjs/mocks.js.map +1 -1
- package/lib/commonjs/reanimated/useAnimatedTheme.js +8 -5
- package/lib/commonjs/reanimated/useAnimatedTheme.js.map +1 -1
- package/lib/commonjs/reanimated/useAnimatedTheme.native.js +8 -5
- package/lib/commonjs/reanimated/useAnimatedTheme.native.js.map +1 -1
- package/lib/commonjs/specs/ShadowRegistry/index.js +12 -3
- package/lib/commonjs/specs/ShadowRegistry/index.js.map +1 -1
- package/lib/commonjs/web/css/state.js +5 -2
- package/lib/commonjs/web/css/state.js.map +1 -1
- package/lib/commonjs/web/runtime.js +6 -0
- package/lib/commonjs/web/runtime.js.map +1 -1
- package/lib/commonjs/web/shadowRegistry.js +3 -1
- package/lib/commonjs/web/shadowRegistry.js.map +1 -1
- package/lib/module/components/AdaptiveTheme.js +10 -2
- package/lib/module/components/AdaptiveTheme.js.map +1 -1
- package/lib/module/components/NamedTheme.js +10 -2
- package/lib/module/components/NamedTheme.js.map +1 -1
- package/lib/module/components/ScopedThemeContext.js +5 -0
- package/lib/module/components/ScopedThemeContext.js.map +1 -0
- package/lib/module/components/native/Pressable.native.js +7 -6
- package/lib/module/components/native/Pressable.native.js.map +1 -1
- package/lib/module/components/scopeChildren.js +23 -0
- package/lib/module/components/scopeChildren.js.map +1 -0
- package/lib/module/components/scopeChildren.native.js +4 -0
- package/lib/module/components/scopeChildren.native.js.map +1 -0
- package/lib/module/core/createUnistylesActivityIndicator.js +4 -2
- package/lib/module/core/createUnistylesActivityIndicator.js.map +1 -1
- package/lib/module/core/createUnistylesElement.js +1 -1
- package/lib/module/core/createUnistylesElement.js.map +1 -1
- package/lib/module/core/createUnistylesElement.native.js +4 -2
- package/lib/module/core/createUnistylesElement.native.js.map +1 -1
- package/lib/module/core/createUnistylesImageBackground.js +6 -3
- package/lib/module/core/createUnistylesImageBackground.js.map +1 -1
- package/lib/module/core/createUnistylesTouchableHighlight.js +7 -9
- package/lib/module/core/createUnistylesTouchableHighlight.js.map +1 -1
- package/lib/module/core/passForwardRef.js +15 -3
- package/lib/module/core/passForwardRef.js.map +1 -1
- package/lib/module/core/useProxifiedUnistyles/useProxifiedUnistyles.js +12 -7
- package/lib/module/core/useProxifiedUnistyles/useProxifiedUnistyles.js.map +1 -1
- package/lib/module/core/withUnistyles/withUnistyles.native.js +13 -3
- package/lib/module/core/withUnistyles/withUnistyles.native.js.map +1 -1
- package/lib/module/mocks.js +1 -1
- package/lib/module/mocks.js.map +1 -1
- package/lib/module/reanimated/useAnimatedTheme.js +10 -7
- package/lib/module/reanimated/useAnimatedTheme.js.map +1 -1
- package/lib/module/reanimated/useAnimatedTheme.native.js +10 -7
- package/lib/module/reanimated/useAnimatedTheme.native.js.map +1 -1
- package/lib/module/specs/ShadowRegistry/index.js +12 -3
- package/lib/module/specs/ShadowRegistry/index.js.map +1 -1
- package/lib/module/web/css/state.js +5 -2
- package/lib/module/web/css/state.js.map +1 -1
- package/lib/module/web/runtime.js +6 -0
- package/lib/module/web/runtime.js.map +1 -1
- package/lib/module/web/shadowRegistry.js +3 -1
- package/lib/module/web/shadowRegistry.js.map +1 -1
- package/lib/typescript/src/__tests__/passForwardRef.spec.d.ts +2 -0
- package/lib/typescript/src/__tests__/passForwardRef.spec.d.ts.map +1 -0
- package/lib/typescript/src/__tests__/scoped-theme.spec.d.ts +2 -0
- package/lib/typescript/src/__tests__/scoped-theme.spec.d.ts.map +1 -0
- package/lib/typescript/src/__tests__/shadow-registry.spec.d.ts +2 -0
- package/lib/typescript/src/__tests__/shadow-registry.spec.d.ts.map +1 -0
- package/lib/typescript/src/__tests__/web-runtime.spec.d.ts +2 -0
- package/lib/typescript/src/__tests__/web-runtime.spec.d.ts.map +1 -0
- package/lib/typescript/src/components/AdaptiveTheme.d.ts.map +1 -1
- package/lib/typescript/src/components/NamedTheme.d.ts.map +1 -1
- package/lib/typescript/src/components/ScopedThemeContext.d.ts +6 -0
- package/lib/typescript/src/components/ScopedThemeContext.d.ts.map +1 -0
- package/lib/typescript/src/components/native/Pressable.native.d.ts.map +1 -1
- package/lib/typescript/src/components/scopeChildren.d.ts +4 -0
- package/lib/typescript/src/components/scopeChildren.d.ts.map +1 -0
- package/lib/typescript/src/components/scopeChildren.native.d.ts +4 -0
- package/lib/typescript/src/components/scopeChildren.native.d.ts.map +1 -0
- package/lib/typescript/src/core/createUnistylesActivityIndicator.d.ts.map +1 -1
- package/lib/typescript/src/core/createUnistylesElement.d.ts.map +1 -1
- package/lib/typescript/src/core/createUnistylesElement.native.d.ts.map +1 -1
- package/lib/typescript/src/core/createUnistylesImageBackground.d.ts.map +1 -1
- package/lib/typescript/src/core/createUnistylesTouchableHighlight.d.ts.map +1 -1
- package/lib/typescript/src/core/passForwardRef.d.ts.map +1 -1
- package/lib/typescript/src/core/useProxifiedUnistyles/useProxifiedUnistyles.d.ts +1 -2
- package/lib/typescript/src/core/useProxifiedUnistyles/useProxifiedUnistyles.d.ts.map +1 -1
- package/lib/typescript/src/core/withUnistyles/withUnistyles.native.d.ts.map +1 -1
- package/lib/typescript/src/reanimated/useAnimatedTheme.d.ts.map +1 -1
- package/lib/typescript/src/reanimated/useAnimatedTheme.native.d.ts.map +1 -1
- package/lib/typescript/src/specs/ShadowRegistry/index.d.ts +2 -1
- package/lib/typescript/src/specs/ShadowRegistry/index.d.ts.map +1 -1
- package/lib/typescript/src/web/css/state.d.ts.map +1 -1
- package/lib/typescript/src/web/runtime.d.ts.map +1 -1
- package/lib/typescript/src/web/shadowRegistry.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/AdaptiveTheme.tsx +8 -2
- package/src/components/NamedTheme.tsx +8 -2
- package/src/components/ScopedThemeContext.ts +9 -0
- package/src/components/native/Pressable.native.tsx +8 -7
- package/src/components/scopeChildren.native.ts +5 -0
- package/src/components/scopeChildren.tsx +19 -0
- package/src/core/createUnistylesActivityIndicator.tsx +5 -2
- package/src/core/createUnistylesElement.native.tsx +4 -2
- package/src/core/createUnistylesElement.tsx +6 -1
- package/src/core/createUnistylesImageBackground.tsx +6 -3
- package/src/core/createUnistylesTouchableHighlight.tsx +7 -11
- package/src/core/passForwardRef.ts +16 -4
- package/src/core/useProxifiedUnistyles/useProxifiedUnistyles.ts +11 -10
- package/src/core/withUnistyles/withUnistyles.native.tsx +24 -5
- package/src/mocks.ts +6 -2
- package/src/reanimated/useAnimatedTheme.native.ts +9 -9
- package/src/reanimated/useAnimatedTheme.ts +9 -9
- package/src/specs/ShadowRegistry/index.ts +16 -4
- package/src/web/css/state.ts +10 -2
- package/src/web/runtime.ts +6 -0
- package/src/web/shadowRegistry.ts +3 -1
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { PropsWithChildren } from 'react'
|
|
2
2
|
|
|
3
|
-
import React, { useLayoutEffect } from 'react'
|
|
3
|
+
import React, { useLayoutEffect, useMemo } from 'react'
|
|
4
4
|
|
|
5
5
|
import type { UnistylesThemes } from '../global'
|
|
6
6
|
|
|
7
7
|
import { useUnistyles } from '../core'
|
|
8
8
|
import { UnistylesShadowRegistry } from '../specs'
|
|
9
9
|
import { ApplyScopedTheme } from './ApplyScopedTheme'
|
|
10
|
+
import { scopeChildren } from './scopeChildren'
|
|
11
|
+
import { ScopedThemeContext } from './ScopedThemeContext'
|
|
10
12
|
|
|
11
13
|
interface AdaptiveThemeProps extends PropsWithChildren {
|
|
12
14
|
previousScopedTheme?: string
|
|
@@ -15,9 +17,13 @@ interface AdaptiveThemeProps extends PropsWithChildren {
|
|
|
15
17
|
export const AdaptiveTheme: React.FunctionComponent<AdaptiveThemeProps> = ({ children, previousScopedTheme }) => {
|
|
16
18
|
const { rt } = useUnistyles()
|
|
17
19
|
const name = (rt.colorScheme === 'dark' ? 'light' : 'dark') as keyof UnistylesThemes
|
|
20
|
+
const scope = useMemo(() => ({ name }), [name])
|
|
21
|
+
|
|
18
22
|
const mappedChildren = [
|
|
19
23
|
<ApplyScopedTheme key={name} name={name} />,
|
|
20
|
-
|
|
24
|
+
<ScopedThemeContext.Provider key="scope" value={scope}>
|
|
25
|
+
{scopeChildren(name, children)}
|
|
26
|
+
</ScopedThemeContext.Provider>,
|
|
21
27
|
<ApplyScopedTheme key="dispose" name={previousScopedTheme as keyof UnistylesThemes | undefined} />,
|
|
22
28
|
]
|
|
23
29
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { PropsWithChildren } from 'react'
|
|
2
2
|
|
|
3
|
-
import React, { useLayoutEffect } from 'react'
|
|
3
|
+
import React, { useLayoutEffect, useMemo } from 'react'
|
|
4
4
|
|
|
5
5
|
import type { UnistylesThemes } from '../global'
|
|
6
6
|
|
|
7
7
|
import { UnistylesShadowRegistry } from '../specs'
|
|
8
8
|
import { ApplyScopedTheme } from './ApplyScopedTheme'
|
|
9
|
+
import { scopeChildren } from './scopeChildren'
|
|
10
|
+
import { ScopedThemeContext } from './ScopedThemeContext'
|
|
9
11
|
|
|
10
12
|
interface NamedThemeProps extends PropsWithChildren {
|
|
11
13
|
name: keyof UnistylesThemes | undefined
|
|
@@ -13,9 +15,13 @@ interface NamedThemeProps extends PropsWithChildren {
|
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
export const NamedTheme: React.FunctionComponent<NamedThemeProps> = ({ name, children, previousScopedTheme }) => {
|
|
18
|
+
const scope = useMemo(() => ({ name }), [name])
|
|
19
|
+
|
|
16
20
|
const mappedChildren = [
|
|
17
21
|
<ApplyScopedTheme key="apply" name={name} />,
|
|
18
|
-
|
|
22
|
+
<ScopedThemeContext.Provider key="scope" value={scope}>
|
|
23
|
+
{scopeChildren(name, children)}
|
|
24
|
+
</ScopedThemeContext.Provider>,
|
|
19
25
|
<ApplyScopedTheme key="dispose" name={previousScopedTheme as keyof UnistylesThemes | undefined} />,
|
|
20
26
|
]
|
|
21
27
|
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { PressableProps as Props, View } from 'react-native'
|
|
2
2
|
|
|
3
|
-
import React, { forwardRef, useLayoutEffect, useRef } from 'react'
|
|
3
|
+
import React, { forwardRef, useContext, useLayoutEffect, useRef } from 'react'
|
|
4
4
|
import { Pressable as NativePressableReactNative } from 'react-native'
|
|
5
5
|
|
|
6
6
|
import type { Nullable } from '../../types'
|
|
7
7
|
|
|
8
8
|
import { passForwardedRef } from '../../core'
|
|
9
9
|
import { UnistylesShadowRegistry } from '../../specs'
|
|
10
|
+
import { ScopedThemeContext } from '../ScopedThemeContext'
|
|
10
11
|
|
|
11
12
|
// instance type of View for both legacy and Strict TypeScript API (RN 0.87+)
|
|
12
13
|
type ViewRef = React.ComponentRef<typeof View>
|
|
@@ -34,7 +35,7 @@ export const Pressable: React.ForwardRefExoticComponent<PressableProps & React.R
|
|
|
34
35
|
PressableProps
|
|
35
36
|
>(({ variants, style, ...props }, forwardedRef) => {
|
|
36
37
|
const storedRef = useRef<Nullable<ViewRef>>(null)
|
|
37
|
-
const
|
|
38
|
+
const scope = useContext(ScopedThemeContext)
|
|
38
39
|
|
|
39
40
|
useLayoutEffect(() => {
|
|
40
41
|
return () => {
|
|
@@ -63,7 +64,7 @@ export const Pressable: React.ForwardRefExoticComponent<PressableProps & React.R
|
|
|
63
64
|
forwardedRef,
|
|
64
65
|
() => {
|
|
65
66
|
// @ts-expect-error - this is hidden from TS
|
|
66
|
-
UnistylesShadowRegistry.add(ref, unistyles)
|
|
67
|
+
UnistylesShadowRegistry.add(ref, unistyles, scope)
|
|
67
68
|
},
|
|
68
69
|
() => {
|
|
69
70
|
// @ts-expect-error - this is hidden from TS
|
|
@@ -75,12 +76,14 @@ export const Pressable: React.ForwardRefExoticComponent<PressableProps & React.R
|
|
|
75
76
|
const isPropStyleAFunction = typeof style === 'function'
|
|
76
77
|
const previousScopedTheme = UnistylesShadowRegistry.getScopedTheme()
|
|
77
78
|
|
|
78
|
-
UnistylesShadowRegistry.setScopedTheme(
|
|
79
|
+
UnistylesShadowRegistry.setScopedTheme(scope?.name)
|
|
79
80
|
|
|
80
81
|
const unistyles = isPropStyleAFunction
|
|
81
82
|
? style.call(style, state)
|
|
82
83
|
: getStyles(style as unknown as Record<string, any>)
|
|
83
84
|
|
|
85
|
+
UnistylesShadowRegistry.setScopedTheme(previousScopedTheme)
|
|
86
|
+
|
|
84
87
|
if (!storedRef.current) {
|
|
85
88
|
return unistyles
|
|
86
89
|
}
|
|
@@ -89,9 +92,7 @@ export const Pressable: React.ForwardRefExoticComponent<PressableProps & React.R
|
|
|
89
92
|
UnistylesShadowRegistry.remove(storedRef.current)
|
|
90
93
|
|
|
91
94
|
// @ts-expect-error - this is hidden from TS
|
|
92
|
-
UnistylesShadowRegistry.add(storedRef.current, unistyles)
|
|
93
|
-
|
|
94
|
-
UnistylesShadowRegistry.setScopedTheme(previousScopedTheme)
|
|
95
|
+
UnistylesShadowRegistry.add(storedRef.current, unistyles, scope)
|
|
95
96
|
|
|
96
97
|
return unistyles
|
|
97
98
|
}}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import type { UnistylesThemes } from '../global'
|
|
4
|
+
|
|
5
|
+
import { services } from '../web/services'
|
|
6
|
+
|
|
7
|
+
export const scopeChildren = (name: keyof UnistylesThemes | undefined, children: React.ReactNode) => {
|
|
8
|
+
if (!services.state.CSSVars) {
|
|
9
|
+
return children
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const scopeProps = name ? { 'data-unistyles-theme': name } : { 'data-unistyles-reset': '' }
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div style={{ display: 'contents' }} {...scopeProps}>
|
|
16
|
+
{children}
|
|
17
|
+
</div>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { ActivityIndicator } from 'react-native'
|
|
2
2
|
|
|
3
|
-
import React from 'react'
|
|
3
|
+
import React, { useContext } from 'react'
|
|
4
4
|
|
|
5
5
|
import { isAndroid } from '../common'
|
|
6
|
+
import { ScopedThemeContext } from '../components/ScopedThemeContext'
|
|
6
7
|
import { UnistylesShadowRegistry } from '../specs'
|
|
7
8
|
import { copyComponentProperties } from '../utils'
|
|
8
9
|
import { passForwardedRef } from './passForwardRef'
|
|
@@ -18,6 +19,8 @@ const getWrapperHandle = (ref: any) => {
|
|
|
18
19
|
|
|
19
20
|
export const createUnistylesActivityIndicator = (Component: typeof ActivityIndicator) => {
|
|
20
21
|
const UnistylesActivityIndicator = (props: any) => {
|
|
22
|
+
const scope = useContext(ScopedThemeContext)
|
|
23
|
+
|
|
21
24
|
return (
|
|
22
25
|
<Component
|
|
23
26
|
{...props}
|
|
@@ -31,7 +34,7 @@ export const createUnistylesActivityIndicator = (Component: typeof ActivityIndic
|
|
|
31
34
|
props.ref,
|
|
32
35
|
() => {
|
|
33
36
|
// @ts-ignore this is hidden from TS
|
|
34
|
-
UnistylesShadowRegistry.add(wrapperHandle, props.style)
|
|
37
|
+
UnistylesShadowRegistry.add(wrapperHandle, props.style, scope)
|
|
35
38
|
},
|
|
36
39
|
() => {
|
|
37
40
|
// @ts-ignore this is hidden from TS
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { ScrollView } from 'react-native'
|
|
2
2
|
|
|
3
|
-
import React, { useRef } from 'react'
|
|
3
|
+
import React, { useContext, useRef } from 'react'
|
|
4
4
|
|
|
5
|
+
import { ScopedThemeContext } from '../components/ScopedThemeContext'
|
|
5
6
|
import { UnistylesShadowRegistry } from '../specs'
|
|
6
7
|
import { copyComponentProperties } from '../utils'
|
|
7
8
|
import { passForwardedRef } from './passForwardRef'
|
|
@@ -10,6 +11,7 @@ import { maybeWarnAboutMultipleUnistyles } from './warn'
|
|
|
10
11
|
export const createUnistylesElement = (Component: any) => {
|
|
11
12
|
const UnistylesComponent = (props: any) => {
|
|
12
13
|
const scrollViewRef = useRef<ScrollView>(null)
|
|
14
|
+
const scope = useContext(ScopedThemeContext)
|
|
13
15
|
|
|
14
16
|
return (
|
|
15
17
|
<Component
|
|
@@ -38,7 +40,7 @@ export const createUnistylesElement = (Component: any) => {
|
|
|
38
40
|
props.ref,
|
|
39
41
|
() => {
|
|
40
42
|
// @ts-ignore this is hidden from TS
|
|
41
|
-
UnistylesShadowRegistry.add(ref, props.style)
|
|
43
|
+
UnistylesShadowRegistry.add(ref, props.style, scope)
|
|
42
44
|
},
|
|
43
45
|
() => {
|
|
44
46
|
// @ts-ignore this is hidden from TS
|
|
@@ -10,7 +10,12 @@ import { isServer } from '../web/utils'
|
|
|
10
10
|
import { getClassName } from './getClassname'
|
|
11
11
|
import { maybeWarnAboutMultipleUnistyles } from './warn'
|
|
12
12
|
|
|
13
|
-
const STYLE_PROPS = [
|
|
13
|
+
const STYLE_PROPS = [
|
|
14
|
+
'contentContainerStyle',
|
|
15
|
+
'columnWrapperStyle',
|
|
16
|
+
'ListHeaderComponentStyle',
|
|
17
|
+
'ListFooterComponentStyle',
|
|
18
|
+
] as const
|
|
14
19
|
|
|
15
20
|
type StyleProp = (typeof STYLE_PROPS)[number] | 'style'
|
|
16
21
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { ImageBackground, ImageBackgroundProps } from 'react-native'
|
|
2
2
|
|
|
3
|
-
import React from 'react'
|
|
3
|
+
import React, { useContext } from 'react'
|
|
4
4
|
|
|
5
|
+
import { ScopedThemeContext } from '../components/ScopedThemeContext'
|
|
5
6
|
import { UnistylesShadowRegistry } from '../specs'
|
|
6
7
|
import { copyComponentProperties } from '../utils'
|
|
7
8
|
import { passForwardedRef } from './passForwardRef'
|
|
@@ -9,6 +10,8 @@ import { maybeWarnAboutMultipleUnistyles } from './warn'
|
|
|
9
10
|
|
|
10
11
|
export const createUnistylesImageBackground = (Component: typeof ImageBackground) => {
|
|
11
12
|
const UnistylesImageBackground = React.forwardRef<ImageBackground, ImageBackgroundProps>((props, forwardedRef) => {
|
|
13
|
+
const scope = useContext(ScopedThemeContext)
|
|
14
|
+
|
|
12
15
|
// @ts-expect-error we don't know the type of the component
|
|
13
16
|
maybeWarnAboutMultipleUnistyles(props.style, 'ImageBackground')
|
|
14
17
|
// @ts-ignore we don't know the type of the component
|
|
@@ -23,7 +26,7 @@ export const createUnistylesImageBackground = (Component: typeof ImageBackground
|
|
|
23
26
|
forwardedRef,
|
|
24
27
|
() => {
|
|
25
28
|
// @ts-expect-error - this is hidden from TS
|
|
26
|
-
UnistylesShadowRegistry.add(ref, props.style)
|
|
29
|
+
UnistylesShadowRegistry.add(ref, props.style, scope)
|
|
27
30
|
},
|
|
28
31
|
() => {
|
|
29
32
|
// @ts-expect-error - this is hidden from TS
|
|
@@ -33,7 +36,7 @@ export const createUnistylesImageBackground = (Component: typeof ImageBackground
|
|
|
33
36
|
}}
|
|
34
37
|
imageRef={(ref) => {
|
|
35
38
|
// @ts-expect-error web types are not compatible with RN styles
|
|
36
|
-
UnistylesShadowRegistry.add(ref, props.imageStyle)
|
|
39
|
+
UnistylesShadowRegistry.add(ref, props.imageStyle, scope)
|
|
37
40
|
|
|
38
41
|
return () => {
|
|
39
42
|
// @ts-ignore this is hidden from TS
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { TouchableHighlight } from 'react-native'
|
|
2
2
|
|
|
3
|
-
import React, { useCallback, useLayoutEffect, useRef, useState } from 'react'
|
|
3
|
+
import React, { useCallback, useContext, useLayoutEffect, useRef, useState } from 'react'
|
|
4
4
|
|
|
5
|
+
import { ScopedThemeContext } from '../components/ScopedThemeContext'
|
|
5
6
|
import { UnistylesShadowRegistry } from '../specs'
|
|
6
7
|
import { copyComponentProperties } from '../utils'
|
|
7
8
|
import { passForwardedRef } from './passForwardRef'
|
|
@@ -9,6 +10,7 @@ import { maybeWarnAboutMultipleUnistyles } from './warn'
|
|
|
9
10
|
|
|
10
11
|
export const createUnistylesTouchableHighlight = (Component: typeof TouchableHighlight) => {
|
|
11
12
|
const UnistylesTouchableHighlight = (props: any) => {
|
|
13
|
+
const scope = useContext(ScopedThemeContext)
|
|
12
14
|
const relinkRef = useRef<() => void>(undefined)
|
|
13
15
|
const [hiddenUnderlays, setHiddenUnderlays] = useState(0)
|
|
14
16
|
|
|
@@ -18,22 +20,16 @@ export const createUnistylesTouchableHighlight = (Component: typeof TouchableHig
|
|
|
18
20
|
}
|
|
19
21
|
}, [hiddenUnderlays])
|
|
20
22
|
|
|
21
|
-
// new props come with a parent render, re-renders for the underlay keep the ref
|
|
23
|
+
// new props come with a parent render, re-renders for the underlay keep the ref
|
|
22
24
|
const ref = useCallback(
|
|
23
25
|
(ref: unknown) => {
|
|
24
26
|
maybeWarnAboutMultipleUnistyles(props.style, 'TouchableHighlight')
|
|
25
27
|
|
|
26
|
-
const scopedTheme = UnistylesShadowRegistry.getScopedTheme()
|
|
27
|
-
|
|
28
28
|
relinkRef.current = () => {
|
|
29
|
-
const previousScopedTheme = UnistylesShadowRegistry.getScopedTheme()
|
|
30
|
-
|
|
31
|
-
UnistylesShadowRegistry.setScopedTheme(scopedTheme)
|
|
32
29
|
// @ts-ignore this is hidden from TS
|
|
33
30
|
UnistylesShadowRegistry.remove(ref)
|
|
34
31
|
// @ts-ignore this is hidden from TS
|
|
35
|
-
UnistylesShadowRegistry.add(ref, props.style)
|
|
36
|
-
UnistylesShadowRegistry.setScopedTheme(previousScopedTheme)
|
|
32
|
+
UnistylesShadowRegistry.add(ref, props.style, scope)
|
|
37
33
|
}
|
|
38
34
|
|
|
39
35
|
return passForwardedRef(
|
|
@@ -41,7 +37,7 @@ export const createUnistylesTouchableHighlight = (Component: typeof TouchableHig
|
|
|
41
37
|
props.ref,
|
|
42
38
|
() => {
|
|
43
39
|
// @ts-ignore this is hidden from TS
|
|
44
|
-
UnistylesShadowRegistry.add(ref, props.style)
|
|
40
|
+
UnistylesShadowRegistry.add(ref, props.style, scope)
|
|
45
41
|
},
|
|
46
42
|
() => {
|
|
47
43
|
relinkRef.current = undefined
|
|
@@ -50,7 +46,7 @@ export const createUnistylesTouchableHighlight = (Component: typeof TouchableHig
|
|
|
50
46
|
},
|
|
51
47
|
)
|
|
52
48
|
},
|
|
53
|
-
[props],
|
|
49
|
+
[props, scope],
|
|
54
50
|
)
|
|
55
51
|
|
|
56
52
|
return (
|
|
@@ -6,7 +6,7 @@ export const passForwardedRef = <T>(
|
|
|
6
6
|
onMount?: () => void,
|
|
7
7
|
onUnmount?: () => void,
|
|
8
8
|
) => {
|
|
9
|
-
const passForwardedRef = () => {
|
|
9
|
+
const passForwardedRef = (): unknown => {
|
|
10
10
|
if (typeof forwardedRef === 'function') {
|
|
11
11
|
return forwardedRef(ref)
|
|
12
12
|
}
|
|
@@ -15,14 +15,26 @@ export const passForwardedRef = <T>(
|
|
|
15
15
|
forwardedRef.current = ref
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
return
|
|
18
|
+
return undefined
|
|
19
19
|
}
|
|
20
20
|
const forwardedRefReturnFn = passForwardedRef()
|
|
21
21
|
|
|
22
22
|
onMount?.()
|
|
23
23
|
|
|
24
24
|
return () => {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
try {
|
|
26
|
+
// React 19 allows a callback ref to return a cleanup function, but returning
|
|
27
|
+
// any other value is still valid, so it can't be called unconditionally.
|
|
28
|
+
// Without a cleanup function React detaches the ref with null, so do we.
|
|
29
|
+
if (typeof forwardedRefReturnFn === 'function') {
|
|
30
|
+
forwardedRefReturnFn()
|
|
31
|
+
} else if (typeof forwardedRef === 'function') {
|
|
32
|
+
forwardedRef(null)
|
|
33
|
+
} else if (forwardedRef) {
|
|
34
|
+
forwardedRef.current = null
|
|
35
|
+
}
|
|
36
|
+
} finally {
|
|
37
|
+
onUnmount?.()
|
|
38
|
+
}
|
|
27
39
|
}
|
|
28
40
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { useEffect, useLayoutEffect, useReducer, useRef, useState } from 'react'
|
|
1
|
+
import { useContext, useEffect, useLayoutEffect, useReducer, useRef, useState } from 'react'
|
|
2
2
|
|
|
3
3
|
import type { UnistylesTheme } from '../../types'
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { ScopedThemeContext } from '../../components/ScopedThemeContext'
|
|
6
|
+
import { type UnistylesMiniRuntime, UnistylesRuntime } from '../../specs'
|
|
6
7
|
// It's imported that way because of circular dependency
|
|
7
8
|
import { UnistyleDependency } from '../../specs/NativePlatform'
|
|
8
9
|
import { listener } from './listener'
|
|
@@ -29,10 +30,9 @@ const RTDependencyMap = {
|
|
|
29
30
|
rtl: UnistyleDependency.Rtl,
|
|
30
31
|
} satisfies Partial<Record<keyof UnistylesMiniRuntime, UnistyleDependency>>
|
|
31
32
|
|
|
32
|
-
export const useProxifiedUnistyles = (
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
)
|
|
33
|
+
export const useProxifiedUnistyles = () => {
|
|
34
|
+
const scope = useContext(ScopedThemeContext)
|
|
35
|
+
const [scopedTheme, setScopedTheme] = useState(scope?.name as UnistylesTheme)
|
|
36
36
|
const [dependencies] = useState(() => new Set<number>())
|
|
37
37
|
const [theme, setTheme] = useState(UnistylesRuntime.getTheme(scopedTheme))
|
|
38
38
|
const [_, runtimeChanged] = useReducer(() => ({}), {})
|
|
@@ -68,10 +68,11 @@ export const useProxifiedUnistyles = (forcedTheme?: UnistylesTheme) => {
|
|
|
68
68
|
}
|
|
69
69
|
}, [disposeRef])
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
-
setScopedTheme(
|
|
71
|
+
// Follow the closest ScopedTheme, `reset` included. Every ScopedTheme provides the context, so the registry isn't read:
|
|
72
|
+
// a suspended ScopedTheme can leave its theme there
|
|
73
|
+
if (scope && scopedTheme !== scope.name) {
|
|
74
|
+
setScopedTheme(scope.name as UnistylesTheme)
|
|
75
|
+
setTheme(UnistylesRuntime.getTheme(scope.name as UnistylesTheme))
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
const proxifiedTheme = new Proxy(theme, {
|
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import React, {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useContext,
|
|
4
|
+
useEffect,
|
|
5
|
+
type ComponentProps,
|
|
6
|
+
type ComponentRef,
|
|
7
|
+
type ComponentType,
|
|
8
|
+
} from 'react'
|
|
9
|
+
|
|
10
|
+
import type { UnistylesValues } from '../../types'
|
|
4
11
|
import type { Mappings } from './types'
|
|
5
12
|
|
|
13
|
+
import { ScopedThemeContext } from '../../components/ScopedThemeContext'
|
|
6
14
|
import { type UnistyleDependency, UnistylesShadowRegistry } from '../../specs'
|
|
7
15
|
import { deepMergeObjects } from '../../utils'
|
|
8
16
|
import { useProxifiedUnistyles } from '../useProxifiedUnistyles'
|
|
@@ -72,8 +80,8 @@ export const withUnistyles = <TComponent, TMappings extends GenericComponentProp
|
|
|
72
80
|
// prettier-ignore
|
|
73
81
|
maybeWarnAboutMultipleUnistyles(narrowedProps.contentContainerStyle, `withUnistyles(${Component.displayName ?? Component.name ?? 'Unknown'})`)
|
|
74
82
|
|
|
75
|
-
const
|
|
76
|
-
const { proxifiedRuntime, proxifiedTheme, addDependencies } = useProxifiedUnistyles(
|
|
83
|
+
const scope = useContext(ScopedThemeContext)
|
|
84
|
+
const { proxifiedRuntime, proxifiedTheme, addDependencies } = useProxifiedUnistyles()
|
|
77
85
|
|
|
78
86
|
// Always track Theme dependency — accessing any property on proxifiedTheme
|
|
79
87
|
// triggers the Proxy get trap which adds Theme to the dependency Set
|
|
@@ -93,9 +101,20 @@ export const withUnistyles = <TComponent, TMappings extends GenericComponentProp
|
|
|
93
101
|
? narrowedProps.uniProps(proxifiedTheme, proxifiedRuntime)
|
|
94
102
|
: {}
|
|
95
103
|
|
|
104
|
+
// styles resolve in the registry's scoped theme, which is already restored when this re-renders or mounts later
|
|
105
|
+
const previousScopedTheme = scope ? UnistylesShadowRegistry.getScopedTheme() : undefined
|
|
106
|
+
|
|
107
|
+
if (scope) {
|
|
108
|
+
UnistylesShadowRegistry.setScopedTheme(scope.name)
|
|
109
|
+
}
|
|
110
|
+
|
|
96
111
|
const styleSecrets = getSecrets(narrowedProps.style)
|
|
97
112
|
const contentContainerStyleSecrets = getSecrets(narrowedProps.contentContainerStyle)
|
|
98
113
|
|
|
114
|
+
if (scope) {
|
|
115
|
+
UnistylesShadowRegistry.setScopedTheme(previousScopedTheme)
|
|
116
|
+
}
|
|
117
|
+
|
|
99
118
|
const finalProps = {
|
|
100
119
|
...deepMergeObjects(mappingsProps, unistyleProps, props),
|
|
101
120
|
...(narrowedProps.style
|
package/src/mocks.ts
CHANGED
|
@@ -11,6 +11,10 @@ type Registry = {
|
|
|
11
11
|
breakpoints: UnistylesBreakpoints
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
type GlobalWithRegistry = typeof globalThis & {
|
|
15
|
+
__UNISTYLES_MOCK_REGISTRY__?: Registry
|
|
16
|
+
}
|
|
17
|
+
|
|
14
18
|
jest.mock('react-native-nitro-modules', () => ({
|
|
15
19
|
NitroModules: {
|
|
16
20
|
createHybridObject: () => ({
|
|
@@ -26,10 +30,10 @@ jest.mock('react-native-nitro-modules', () => ({
|
|
|
26
30
|
|
|
27
31
|
jest.mock('react-native-unistyles', () => {
|
|
28
32
|
const React = require('react')
|
|
29
|
-
const _REGISTRY
|
|
33
|
+
const _REGISTRY = ((globalThis as GlobalWithRegistry).__UNISTYLES_MOCK_REGISTRY__ ??= {
|
|
30
34
|
themes: {},
|
|
31
35
|
breakpoints: {},
|
|
32
|
-
}
|
|
36
|
+
})
|
|
33
37
|
const miniRuntime = {
|
|
34
38
|
themeName: undefined,
|
|
35
39
|
breakpoint: undefined,
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react'
|
|
1
|
+
import { useContext, useEffect, useState } from 'react'
|
|
2
2
|
import { type SharedValue, useSharedValue } from 'react-native-reanimated'
|
|
3
3
|
|
|
4
4
|
import type { UnistylesTheme } from '../types'
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { ScopedThemeContext } from '../components/ScopedThemeContext'
|
|
7
|
+
import { StyleSheet, UnistyleDependency, UnistylesRuntime } from '../specs'
|
|
7
8
|
|
|
8
9
|
export const useAnimatedTheme = () => {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
)
|
|
10
|
+
const scope = useContext(ScopedThemeContext)
|
|
11
|
+
const [scopedTheme, setScopedTheme] = useState(scope?.name as UnistylesTheme | undefined)
|
|
12
12
|
const theme = useSharedValue(UnistylesRuntime.getTheme(scopedTheme))
|
|
13
|
-
const maybeNewScopedTheme = UnistylesShadowRegistry.getScopedTheme() as UnistylesTheme | undefined
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
// Follow the closest ScopedTheme, see useProxifiedUnistyles
|
|
15
|
+
if (scope && scopedTheme !== scope.name) {
|
|
16
|
+
setScopedTheme(scope.name as UnistylesTheme | undefined)
|
|
17
|
+
theme.set(UnistylesRuntime.getTheme(scope.name as UnistylesTheme | undefined))
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
useEffect(() => {
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react'
|
|
1
|
+
import { useContext, useEffect, useState } from 'react'
|
|
2
2
|
import { type SharedValue, useSharedValue } from 'react-native-reanimated'
|
|
3
3
|
|
|
4
4
|
import type { UnistylesTheme } from '../types'
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { ScopedThemeContext } from '../components/ScopedThemeContext'
|
|
7
|
+
import { UnistyleDependency, UnistylesRuntime } from '../specs'
|
|
7
8
|
import { services } from '../web/services'
|
|
8
9
|
|
|
9
10
|
export const useAnimatedTheme = () => {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
)
|
|
11
|
+
const scope = useContext(ScopedThemeContext)
|
|
12
|
+
const [scopedTheme, setScopedTheme] = useState(scope?.name as UnistylesTheme | undefined)
|
|
13
13
|
const theme = useSharedValue(UnistylesRuntime.getTheme(scopedTheme))
|
|
14
|
-
const maybeNewScopedTheme = UnistylesShadowRegistry.getScopedTheme() as UnistylesTheme | undefined
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
// Follow the closest ScopedTheme, see useProxifiedUnistyles
|
|
16
|
+
if (scope && scopedTheme !== scope.name) {
|
|
17
|
+
setScopedTheme(scope.name as UnistylesTheme | undefined)
|
|
18
|
+
theme.set(UnistylesRuntime.getTheme(scope.name as UnistylesTheme | undefined))
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
useEffect(() => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NitroModules } from 'react-native-nitro-modules'
|
|
2
2
|
|
|
3
|
+
import type { Scope } from '../../components/ScopedThemeContext'
|
|
3
4
|
import type { VerifyReport } from '../../diagnostics/types'
|
|
4
5
|
import type { UnistylesShadowRegistry as UnistylesShadowRegistrySpec } from './ShadowRegistry.nitro'
|
|
5
6
|
import type { ShadowNode, Unistyle, ViewHandle } from './types'
|
|
@@ -8,7 +9,7 @@ import { StyleSheet } from '../StyleSheet'
|
|
|
8
9
|
|
|
9
10
|
interface ShadowRegistry extends UnistylesShadowRegistrySpec {
|
|
10
11
|
// Babel API
|
|
11
|
-
add(handle?: ViewHandle, styles?: Array<Unistyle
|
|
12
|
+
add(handle?: ViewHandle, styles?: Array<Unistyle>, scope?: Scope | null): void
|
|
12
13
|
remove(handle?: ViewHandle): void
|
|
13
14
|
// JSI
|
|
14
15
|
link(node: ShadowNode, styles?: Array<Unistyle>): void
|
|
@@ -189,18 +190,17 @@ const splitMergedUnistyles = (style: any) => {
|
|
|
189
190
|
return style
|
|
190
191
|
}
|
|
191
192
|
|
|
192
|
-
HybridShadowRegistry.add = (handle, styles) => {
|
|
193
|
+
HybridShadowRegistry.add = (handle, styles, scope) => {
|
|
193
194
|
// virtualized nodes can be null
|
|
194
195
|
if (!handle || !styles) {
|
|
195
196
|
return
|
|
196
197
|
}
|
|
197
198
|
|
|
198
|
-
const stylesArray = Array.isArray(styles) ? styles.flat() : [styles]
|
|
199
|
+
const stylesArray = Array.isArray(styles) ? styles.flat(Infinity) : [styles]
|
|
199
200
|
|
|
200
201
|
// filter styles that are undefined or with no keys
|
|
201
202
|
const filteredStyles = stylesArray
|
|
202
203
|
.filter((style) => style && Object.keys(style).length > 0)
|
|
203
|
-
.flat()
|
|
204
204
|
.filter(Boolean)
|
|
205
205
|
.flatMap(splitMergedUnistyles)
|
|
206
206
|
|
|
@@ -213,7 +213,19 @@ HybridShadowRegistry.add = (handle, styles) => {
|
|
|
213
213
|
)
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
// the view can link after its ScopedTheme rendered, when the registry is already restored
|
|
217
|
+
const previousScopedTheme = scope ? HybridShadowRegistry.getScopedTheme() : undefined
|
|
218
|
+
|
|
219
|
+
if (scope) {
|
|
220
|
+
HybridShadowRegistry.setScopedTheme(scope.name)
|
|
221
|
+
}
|
|
222
|
+
|
|
216
223
|
HybridShadowRegistry.link(node, filteredStyles)
|
|
224
|
+
|
|
225
|
+
if (scope) {
|
|
226
|
+
HybridShadowRegistry.setScopedTheme(previousScopedTheme)
|
|
227
|
+
}
|
|
228
|
+
|
|
217
229
|
trackHandle(handle)
|
|
218
230
|
}
|
|
219
231
|
}
|
package/src/web/css/state.ts
CHANGED
|
@@ -89,11 +89,19 @@ export class CSSState {
|
|
|
89
89
|
|
|
90
90
|
Object.entries(values).forEach(([key, value]) => convertToCSS(key, value))
|
|
91
91
|
|
|
92
|
+
// ScopedTheme renders an element with data-unistyles-theme (or data-unistyles-reset for `reset`),
|
|
93
|
+
// so the variables follow the closest scope and styles don't need to know it while they render
|
|
92
94
|
if (theme === 'light' || theme === 'dark') {
|
|
93
|
-
this.themesCSS.set(
|
|
95
|
+
this.themesCSS.set(
|
|
96
|
+
`media ${theme}`,
|
|
97
|
+
`@media (prefers-color-scheme: ${theme}){:root,[data-unistyles-reset]{${themeVars}}}`,
|
|
98
|
+
)
|
|
94
99
|
}
|
|
95
100
|
|
|
96
|
-
this.themesCSS.set(
|
|
101
|
+
this.themesCSS.set(
|
|
102
|
+
theme,
|
|
103
|
+
`:root.${theme},:root.${theme} [data-unistyles-reset],[data-unistyles-theme="${theme}"]{${themeVars}}`,
|
|
104
|
+
)
|
|
97
105
|
}
|
|
98
106
|
|
|
99
107
|
remove = (hash: string) => {
|
package/src/web/runtime.ts
CHANGED
|
@@ -80,6 +80,12 @@ export class UnistylesRuntime {
|
|
|
80
80
|
return Orientation.Portrait
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
// `screen.orientation` is undefined in browsers without the Screen
|
|
84
|
+
// Orientation API (e.g. iOS Safari <= 16.3), fall back to the viewport
|
|
85
|
+
if (!screen.orientation) {
|
|
86
|
+
return window.matchMedia('(orientation: portrait)').matches ? Orientation.Portrait : Orientation.Landscape
|
|
87
|
+
}
|
|
88
|
+
|
|
83
89
|
return screen.orientation.type.includes('portrait') ? Orientation.Portrait : Orientation.Landscape
|
|
84
90
|
}
|
|
85
91
|
|
|
@@ -101,7 +101,9 @@ export class UnistylesShadowRegistry {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
setScopedTheme = (theme?: UnistylesTheme) => {
|
|
104
|
-
|
|
104
|
+
// With CSS variables, the closest ScopedTheme element picks the theme, so styles are the same in every scope.
|
|
105
|
+
// Keeping no scope here also means a suspended ScopedTheme can't leave it behind
|
|
106
|
+
this.scopedTheme = this.services.state.CSSVars ? undefined : theme
|
|
105
107
|
}
|
|
106
108
|
|
|
107
109
|
getScopedTheme = () => this.scopedTheme
|