react-native-unistyles 3.5.1 → 3.5.3
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/android/src/main/java/com/unistyles/NativePlatform+android.kt +44 -7
- package/android/src/main/java/com/unistyles/NativePlatform+insets.kt +1 -1
- package/cxx/core/UnistylesRegistry.cpp +5 -5
- package/cxx/core/UnistylesRegistry.h +3 -3
- package/cxx/hybridObjects/HybridShadowRegistry.cpp +48 -14
- package/cxx/hybridObjects/HybridShadowRegistry.h +3 -2
- package/cxx/hybridObjects/HybridStyleSheet.cpp +3 -3
- package/cxx/parser/Parser.cpp +18 -2
- package/cxx/shadowTree/ShadowTreeManager.cpp +5 -5
- package/cxx/shadowTree/ShadowTreeManager.h +1 -1
- package/ios/NativePlatform+ios.swift +6 -4
- 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.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/useProxifiedUnistyles/useProxifiedUnistyles.js +20 -5
- package/lib/commonjs/core/useProxifiedUnistyles/useProxifiedUnistyles.js.map +1 -1
- package/lib/commonjs/core/withUnistyles/withUnistyles.native.js +28 -17
- package/lib/commonjs/core/withUnistyles/withUnistyles.native.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 +76 -74
- package/lib/commonjs/specs/ShadowRegistry/index.js.map +1 -1
- package/lib/commonjs/web/css/core.js +30 -5
- package/lib/commonjs/web/css/core.js.map +1 -1
- package/lib/commonjs/web/css/state.js +9 -3
- package/lib/commonjs/web/css/state.js.map +1 -1
- package/lib/commonjs/web/registry.js +1 -1
- package/lib/commonjs/web/registry.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.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/useProxifiedUnistyles/useProxifiedUnistyles.js +22 -7
- package/lib/module/core/useProxifiedUnistyles/useProxifiedUnistyles.js.map +1 -1
- package/lib/module/core/withUnistyles/withUnistyles.native.js +27 -17
- package/lib/module/core/withUnistyles/withUnistyles.native.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 +76 -74
- package/lib/module/specs/ShadowRegistry/index.js.map +1 -1
- package/lib/module/web/css/core.js +28 -4
- package/lib/module/web/css/core.js.map +1 -1
- package/lib/module/web/css/state.js +10 -4
- package/lib/module/web/css/state.js.map +1 -1
- package/lib/module/web/registry.js +1 -1
- package/lib/module/web/registry.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__/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-child-selector.spec.d.ts +2 -0
- package/lib/typescript/src/__tests__/web-child-selector.spec.d.ts.map +1 -0
- package/lib/typescript/src/__tests__/web-pointer-events.spec.d.ts +2 -0
- package/lib/typescript/src/__tests__/web-pointer-events.spec.d.ts.map +1 -0
- package/lib/typescript/src/__tests__/withUnistyles.spec.d.ts +2 -0
- package/lib/typescript/src/__tests__/withUnistyles.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.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/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 +6 -0
- 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 +4 -3
- package/lib/typescript/src/specs/ShadowRegistry/index.d.ts.map +1 -1
- package/lib/typescript/src/web/css/core.d.ts +1 -0
- package/lib/typescript/src/web/css/core.d.ts.map +1 -1
- package/lib/typescript/src/web/css/state.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/createUnistylesImageBackground.tsx +6 -3
- package/src/core/createUnistylesTouchableHighlight.tsx +7 -11
- package/src/core/useProxifiedUnistyles/useProxifiedUnistyles.ts +22 -10
- package/src/core/withUnistyles/withUnistyles.native.tsx +46 -30
- package/src/reanimated/useAnimatedTheme.native.ts +9 -9
- package/src/reanimated/useAnimatedTheme.ts +9 -9
- package/src/specs/ShadowRegistry/index.ts +93 -91
- package/src/web/css/core.ts +29 -4
- package/src/web/css/state.ts +16 -4
- package/src/web/registry.ts +1 -1
- package/src/web/shadowRegistry.ts +3 -1
|
@@ -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
|
|
@@ -18,7 +19,7 @@ interface ShadowRegistry extends UnistylesShadowRegistrySpec {
|
|
|
18
19
|
setScopedTheme(themeName?: string): void
|
|
19
20
|
getScopedTheme(): string | undefined
|
|
20
21
|
verify(): VerifyReport
|
|
21
|
-
|
|
22
|
+
takeCommittedInstanceHandles(): Array<any>
|
|
22
23
|
refreshReactNodes(nodes: Array<ShadowNode>): void
|
|
23
24
|
}
|
|
24
25
|
|
|
@@ -72,137 +73,122 @@ const findShadowNodeForHandle = (handle: ViewHandle) => {
|
|
|
72
73
|
return node
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
const getNativeTag = (handle: ViewHandle): number | undefined =>
|
|
76
|
-
findFiberForHandle(handle)?.stateNode?.canonical?.nativeTag
|
|
77
|
-
|
|
78
|
-
// by native tag, weak: views unmounted while frozen never unlink, their dead refs are dropped when the map doubles
|
|
79
|
-
const linkedHandles = new Map<number, WeakRef<ViewHandle>>()
|
|
80
|
-
const MIN_SWEEP_SIZE = 256
|
|
81
|
-
let sweepSize = MIN_SWEEP_SIZE
|
|
82
|
-
|
|
83
|
-
const sweepUnmountedHandles = () => {
|
|
84
|
-
linkedHandles.forEach((ref, tag) => {
|
|
85
|
-
if (!ref.deref()) {
|
|
86
|
-
linkedHandles.delete(tag)
|
|
87
|
-
}
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
sweepSize = Math.max(MIN_SWEEP_SIZE, linkedHandles.size * 2)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const trackHandle = (handle: ViewHandle) => {
|
|
94
|
-
const tag = getNativeTag(handle)
|
|
95
|
-
|
|
96
|
-
// views re-link on every render
|
|
97
|
-
if (tag === undefined || linkedHandles.get(tag)?.deref() === handle) {
|
|
98
|
-
return
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
linkedHandles.set(tag, new WeakRef(handle))
|
|
102
|
-
|
|
103
|
-
if (linkedHandles.size >= sweepSize) {
|
|
104
|
-
sweepUnmountedHandles()
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const untrackHandle = (handle: ViewHandle) => {
|
|
109
|
-
const tag = getNativeTag(handle)
|
|
110
|
-
|
|
111
|
-
if (tag !== undefined && linkedHandles.get(tag)?.deref() === handle) {
|
|
112
|
-
linkedHandles.delete(tag)
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
76
|
// React re-attaches an untouched subtree through its root's node and only follows clones made on the JS thread.
|
|
117
77
|
// Once a node was cloned elsewhere (state updates, Reanimated), React would commit a subtree from before a Unistyles
|
|
118
78
|
// update, so after a Unistyles commit the committed nodes and their host ancestors must point at the committed tree
|
|
119
79
|
const refreshReactNodes = () => {
|
|
120
|
-
const
|
|
80
|
+
const fibers = HybridShadowRegistry.takeCommittedInstanceHandles()
|
|
121
81
|
|
|
122
|
-
if (
|
|
82
|
+
if (fibers.length === 0) {
|
|
123
83
|
return
|
|
124
84
|
}
|
|
125
85
|
|
|
126
|
-
const nodes
|
|
127
|
-
const
|
|
86
|
+
const nodes: Array<ShadowNode> = []
|
|
87
|
+
const refreshedTags = new Set<number>()
|
|
88
|
+
const hostFibers: Array<any> = []
|
|
128
89
|
|
|
129
|
-
for (const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (!handle) {
|
|
90
|
+
for (const fiber of fibers) {
|
|
91
|
+
// collected, unmounted since
|
|
92
|
+
if (!fiber) {
|
|
133
93
|
continue
|
|
134
94
|
}
|
|
135
95
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
// hidden by Suspense or a frozen screen
|
|
139
|
-
if (!fiber || isInsideSuspendedBoundary(fiber)) {
|
|
140
|
-
continue
|
|
141
|
-
}
|
|
96
|
+
let isHidden = false
|
|
142
97
|
|
|
143
|
-
|
|
144
|
-
visited.add(current)
|
|
98
|
+
hostFibers.length = 0
|
|
145
99
|
|
|
146
|
-
|
|
147
|
-
|
|
100
|
+
for (let current: any = fiber; current; current = current.return) {
|
|
101
|
+
// hidden by Suspense or a frozen screen
|
|
102
|
+
if ((current.tag === SUSPENSE_TAG || current.tag === OFFSCREEN_TAG) && current.memoizedState !== null) {
|
|
103
|
+
isHidden = true
|
|
148
104
|
}
|
|
149
105
|
|
|
150
106
|
if (current.tag !== HOST_COMPONENT_TAG) {
|
|
151
107
|
continue
|
|
152
108
|
}
|
|
153
109
|
|
|
154
|
-
|
|
155
|
-
|
|
110
|
+
// its ancestors are visible and already collected
|
|
111
|
+
if (refreshedTags.has(current.stateNode?.canonical?.nativeTag)) {
|
|
112
|
+
break
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
hostFibers.push(current)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (isHidden) {
|
|
119
|
+
continue
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
for (const hostFiber of hostFibers) {
|
|
123
|
+
const node = hostFiber.stateNode?.node
|
|
124
|
+
const alternateNode = hostFiber.alternate?.stateNode?.node
|
|
125
|
+
const hostTag = hostFiber.stateNode?.canonical?.nativeTag
|
|
126
|
+
|
|
127
|
+
if (hostTag !== undefined) {
|
|
128
|
+
refreshedTags.add(hostTag)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (node) {
|
|
132
|
+
nodes.push(node)
|
|
133
|
+
}
|
|
156
134
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
135
|
+
if (alternateNode && alternateNode !== node) {
|
|
136
|
+
nodes.push(alternateNode)
|
|
160
137
|
}
|
|
161
138
|
}
|
|
162
139
|
}
|
|
163
140
|
|
|
164
|
-
if (nodes.
|
|
165
|
-
HybridShadowRegistry.refreshReactNodes(
|
|
141
|
+
if (nodes.length > 0) {
|
|
142
|
+
HybridShadowRegistry.refreshReactNodes(nodes)
|
|
166
143
|
}
|
|
167
144
|
}
|
|
168
145
|
|
|
169
146
|
StyleSheet.addChangeListener(refreshReactNodes)
|
|
170
147
|
|
|
171
|
-
//
|
|
172
|
-
|
|
173
|
-
|
|
148
|
+
// skips empty styles and splits a style merged from many unistyles (eg. flattened by Animated) into one per unistyle
|
|
149
|
+
// runs for every style on every link, so it reads the keys once and allocates only for the rare merged style
|
|
150
|
+
const collectStyle = (style: any, collected: Array<any>) => {
|
|
151
|
+
if (!style) {
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const keys = Object.keys(style)
|
|
156
|
+
let unistylesCount = 0
|
|
174
157
|
|
|
175
|
-
for (const key
|
|
176
|
-
if (
|
|
177
|
-
|
|
158
|
+
for (const key of keys) {
|
|
159
|
+
if (key.startsWith('unistyles_')) {
|
|
160
|
+
unistylesCount++
|
|
178
161
|
}
|
|
162
|
+
}
|
|
179
163
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
.map((unistyleKey) => ({ [unistyleKey]: style[unistyleKey] }))
|
|
164
|
+
if (unistylesCount < 2) {
|
|
165
|
+
if (keys.length > 0) {
|
|
166
|
+
collected.push(style)
|
|
184
167
|
}
|
|
185
168
|
|
|
186
|
-
|
|
169
|
+
return
|
|
187
170
|
}
|
|
188
171
|
|
|
189
|
-
|
|
172
|
+
for (const key of keys) {
|
|
173
|
+
if (key.startsWith('unistyles_')) {
|
|
174
|
+
collected.push({ [key]: style[key] })
|
|
175
|
+
}
|
|
176
|
+
}
|
|
190
177
|
}
|
|
191
178
|
|
|
192
|
-
HybridShadowRegistry.add = (handle, styles) => {
|
|
179
|
+
HybridShadowRegistry.add = (handle, styles, scope) => {
|
|
193
180
|
// virtualized nodes can be null
|
|
194
181
|
if (!handle || !styles) {
|
|
195
182
|
return
|
|
196
183
|
}
|
|
197
184
|
|
|
198
|
-
const
|
|
185
|
+
const filteredStyles: Array<any> = []
|
|
199
186
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
.flatMap(splitMergedUnistyles)
|
|
187
|
+
if (Array.isArray(styles)) {
|
|
188
|
+
styles.flat(Infinity).forEach((style) => collectStyle(style, filteredStyles))
|
|
189
|
+
} else {
|
|
190
|
+
collectStyle(styles, filteredStyles)
|
|
191
|
+
}
|
|
206
192
|
|
|
207
193
|
if (filteredStyles.length > 0) {
|
|
208
194
|
const node = findShadowNodeForHandle(handle)
|
|
@@ -213,8 +199,18 @@ HybridShadowRegistry.add = (handle, styles) => {
|
|
|
213
199
|
)
|
|
214
200
|
}
|
|
215
201
|
|
|
202
|
+
// the view can link after its ScopedTheme rendered, when the registry is already restored
|
|
203
|
+
const previousScopedTheme = scope ? HybridShadowRegistry.getScopedTheme() : undefined
|
|
204
|
+
|
|
205
|
+
if (scope) {
|
|
206
|
+
HybridShadowRegistry.setScopedTheme(scope.name)
|
|
207
|
+
}
|
|
208
|
+
|
|
216
209
|
HybridShadowRegistry.link(node, filteredStyles)
|
|
217
|
-
|
|
210
|
+
|
|
211
|
+
if (scope) {
|
|
212
|
+
HybridShadowRegistry.setScopedTheme(previousScopedTheme)
|
|
213
|
+
}
|
|
218
214
|
}
|
|
219
215
|
}
|
|
220
216
|
|
|
@@ -232,11 +228,17 @@ HybridShadowRegistry.remove = (handle) => {
|
|
|
232
228
|
HybridShadowRegistry.suspend(maybeNode)
|
|
233
229
|
} else {
|
|
234
230
|
HybridShadowRegistry.unlink(maybeNode)
|
|
235
|
-
untrackHandle(handle)
|
|
236
231
|
}
|
|
237
232
|
}
|
|
238
233
|
}
|
|
239
234
|
|
|
240
|
-
type PrivateMethods =
|
|
235
|
+
type PrivateMethods =
|
|
236
|
+
| 'add'
|
|
237
|
+
| 'remove'
|
|
238
|
+
| 'link'
|
|
239
|
+
| 'unlink'
|
|
240
|
+
| 'suspend'
|
|
241
|
+
| 'takeCommittedInstanceHandles'
|
|
242
|
+
| 'refreshReactNodes'
|
|
241
243
|
|
|
242
244
|
export const UnistylesShadowRegistry = HybridShadowRegistry as Omit<ShadowRegistry, PrivateMethods>
|
package/src/web/css/core.ts
CHANGED
|
@@ -3,6 +3,31 @@ import type { CSSState } from './state'
|
|
|
3
3
|
import { isPseudoClass } from '../convert/pseudo'
|
|
4
4
|
import { getMediaQuery } from '../utils'
|
|
5
5
|
|
|
6
|
+
type SetProps = Parameters<CSSState['set']>[0]
|
|
7
|
+
|
|
8
|
+
// box-none and box-only aren't CSS values, polyfill them like react-native-web: [element, children]
|
|
9
|
+
const POINTER_EVENTS: Record<string, [string, string]> = {
|
|
10
|
+
'box-none': ['none', 'auto'],
|
|
11
|
+
'box-only': ['auto', 'none'],
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const getChildrenClassName = (className: string) => `:where(.${className})>*`
|
|
15
|
+
|
|
16
|
+
const setStyle = (state: CSSState, props: SetProps) => {
|
|
17
|
+
if (props.propertyKey !== 'pointerEvents') {
|
|
18
|
+
state.set(props)
|
|
19
|
+
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const [value, childrenValue] = POINTER_EVENTS[props.value] ?? [props.value]
|
|
24
|
+
|
|
25
|
+
state.set({ ...props, value })
|
|
26
|
+
// :where() has no specificity, so a child's own pointerEvents always wins
|
|
27
|
+
// set it for every value, so re-applying the style can't leave a stale children rule
|
|
28
|
+
state.set({ ...props, className: getChildrenClassName(props.className), value: childrenValue })
|
|
29
|
+
}
|
|
30
|
+
|
|
6
31
|
export const convertToCSS = (hash: string, value: Record<string, any>, state: CSSState) => {
|
|
7
32
|
Object.entries(value).forEach(([styleKey, styleValue]) => {
|
|
8
33
|
if (styleKey[0] === '_') {
|
|
@@ -15,7 +40,7 @@ export const convertToCSS = (hash: string, value: Record<string, any>, state: CS
|
|
|
15
40
|
Object.entries(pseudoStyleValue).forEach(([breakpointStyleKey, breakpointStyleValue]) => {
|
|
16
41
|
const mediaQuery = getMediaQuery(pseudoStyleKey, allBreakpoints)
|
|
17
42
|
|
|
18
|
-
state
|
|
43
|
+
setStyle(state, {
|
|
19
44
|
mediaQuery,
|
|
20
45
|
className: pseudoClassName,
|
|
21
46
|
propertyKey: breakpointStyleKey,
|
|
@@ -26,7 +51,7 @@ export const convertToCSS = (hash: string, value: Record<string, any>, state: CS
|
|
|
26
51
|
return
|
|
27
52
|
}
|
|
28
53
|
|
|
29
|
-
state
|
|
54
|
+
setStyle(state, {
|
|
30
55
|
className: pseudoClassName,
|
|
31
56
|
propertyKey: pseudoStyleKey,
|
|
32
57
|
value: pseudoStyleValue,
|
|
@@ -49,7 +74,7 @@ export const convertToCSS = (hash: string, value: Record<string, any>, state: CS
|
|
|
49
74
|
.map(([key]) => key)
|
|
50
75
|
const mediaQuery = getMediaQuery(styleKey, allBreakpoints)
|
|
51
76
|
|
|
52
|
-
state
|
|
77
|
+
setStyle(state, {
|
|
53
78
|
mediaQuery,
|
|
54
79
|
className: hash,
|
|
55
80
|
propertyKey: breakpointStyleKey,
|
|
@@ -60,7 +85,7 @@ export const convertToCSS = (hash: string, value: Record<string, any>, state: CS
|
|
|
60
85
|
return
|
|
61
86
|
}
|
|
62
87
|
|
|
63
|
-
state
|
|
88
|
+
setStyle(state, {
|
|
64
89
|
className: hash,
|
|
65
90
|
propertyKey: styleKey,
|
|
66
91
|
value: styleValue,
|
package/src/web/css/state.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { UnistylesServices } from '../types'
|
|
|
3
3
|
|
|
4
4
|
import { convertUnistyles } from '../convert'
|
|
5
5
|
import { hyphenate, isServer } from '../utils'
|
|
6
|
-
import { convertToCSS } from './core'
|
|
6
|
+
import { convertToCSS, getChildrenClassName } from './core'
|
|
7
7
|
|
|
8
8
|
type MapType = Map<string, Map<string, Map<string, any>>>
|
|
9
9
|
type SetProps = {
|
|
@@ -89,19 +89,31 @@ 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) => {
|
|
108
|
+
const childrenClassName = getChildrenClassName(hash)
|
|
109
|
+
|
|
100
110
|
this.mainMap.forEach((styles) => {
|
|
101
111
|
styles.delete(hash)
|
|
112
|
+
styles.delete(childrenClassName)
|
|
102
113
|
})
|
|
103
114
|
this.mqMap.forEach((styles) => {
|
|
104
115
|
styles.delete(hash)
|
|
116
|
+
styles.delete(childrenClassName)
|
|
105
117
|
})
|
|
106
118
|
this.recreate()
|
|
107
119
|
}
|
|
@@ -117,7 +129,7 @@ export class CSSState {
|
|
|
117
129
|
}
|
|
118
130
|
|
|
119
131
|
for (const [className, thirdLevelMap] of secondLevelMap) {
|
|
120
|
-
styles += `.${className}{`
|
|
132
|
+
styles += className[0] === ':' ? `${className}{` : `.${className}{`
|
|
121
133
|
|
|
122
134
|
for (const [propertyKey, value] of thirdLevelMap) {
|
|
123
135
|
if (value === undefined) {
|
package/src/web/registry.ts
CHANGED
|
@@ -112,7 +112,7 @@ export class UnistylesRegistry {
|
|
|
112
112
|
|
|
113
113
|
add = (value: UnistylesValues, forChild?: boolean) => {
|
|
114
114
|
const generatedHash = generateHash(value)
|
|
115
|
-
const hash = forChild ? `${generatedHash} > *` : generatedHash
|
|
115
|
+
const hash = forChild ? `${generatedHash}_child > *` : generatedHash
|
|
116
116
|
|
|
117
117
|
if (!this.stylesCache.has(hash)) {
|
|
118
118
|
this.applyStyles(hash, value)
|
|
@@ -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
|