@tamagui/native-registry 0.0.0-bootstrap.0 → 3.0.0-beta.643.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/README.md +58 -0
- package/TamaguiRegistry.podspec +32 -0
- package/android/CMakeLists.txt +25 -0
- package/android/build.gradle +83 -0
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/cpp/cpp-adapter.cpp +11 -0
- package/android/src/main/java/com/tamagui/registry/TamaguiRegistryPackage.kt +25 -0
- package/cpp/HybridTamaguiRegistry.cpp +369 -0
- package/cpp/HybridTamaguiRegistry.hpp +117 -0
- package/dist/cjs/index.cjs +73 -0
- package/dist/cjs/index.native.cjs +144 -0
- package/dist/cjs/index.native.js +146 -0
- package/dist/cjs/index.native.js.map +1 -0
- package/dist/cjs/mirror.cjs +44 -0
- package/dist/cjs/mirror.native.cjs +48 -0
- package/dist/cjs/mirror.native.js +50 -0
- package/dist/cjs/mirror.native.js.map +1 -0
- package/dist/cjs/processStyleColors.cjs +56 -0
- package/dist/cjs/processStyleColors.native.cjs +58 -0
- package/dist/cjs/processStyleColors.native.js +60 -0
- package/dist/cjs/processStyleColors.native.js.map +1 -0
- package/dist/cjs/specs/TamaguiRegistry.nitro.cjs +17 -0
- package/dist/cjs/specs/TamaguiRegistry.nitro.native.cjs +19 -0
- package/dist/cjs/specs/TamaguiRegistry.nitro.native.js +21 -0
- package/dist/cjs/specs/TamaguiRegistry.nitro.native.js.map +1 -0
- package/dist/cjs/types.cjs +17 -0
- package/dist/cjs/types.native.cjs +19 -0
- package/dist/cjs/types.native.js +21 -0
- package/dist/cjs/types.native.js.map +1 -0
- package/dist/esm/index.js +39 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/index.mjs +39 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/index.native.js +107 -0
- package/dist/esm/index.native.js.map +1 -0
- package/dist/esm/mirror.mjs +17 -0
- package/dist/esm/mirror.mjs.map +1 -0
- package/dist/esm/mirror.native.js +19 -0
- package/dist/esm/mirror.native.js.map +1 -0
- package/dist/esm/processStyleColors.mjs +36 -0
- package/dist/esm/processStyleColors.mjs.map +1 -0
- package/dist/esm/processStyleColors.native.js +36 -0
- package/dist/esm/processStyleColors.native.js.map +1 -0
- package/dist/esm/specs/TamaguiRegistry.nitro.mjs +0 -0
- package/dist/esm/specs/TamaguiRegistry.nitro.native.js +0 -0
- package/dist/esm/types.mjs +0 -0
- package/dist/esm/types.native.js +0 -0
- package/nitro.json +18 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/tamagui/registry/tamaguiregistryOnLoad.kt +35 -0
- package/nitrogen/generated/android/tamaguiregistry+autolinking.cmake +81 -0
- package/nitrogen/generated/android/tamaguiregistry+autolinking.gradle +27 -0
- package/nitrogen/generated/android/tamaguiregistryOnLoad.cpp +49 -0
- package/nitrogen/generated/android/tamaguiregistryOnLoad.hpp +34 -0
- package/nitrogen/generated/ios/TamaguiRegistry+autolinking.rb +62 -0
- package/nitrogen/generated/ios/TamaguiRegistry-Swift-Cxx-Bridge.cpp +17 -0
- package/nitrogen/generated/ios/TamaguiRegistry-Swift-Cxx-Bridge.hpp +27 -0
- package/nitrogen/generated/ios/TamaguiRegistry-Swift-Cxx-Umbrella.hpp +38 -0
- package/nitrogen/generated/ios/TamaguiRegistryAutolinking.mm +35 -0
- package/nitrogen/generated/ios/TamaguiRegistryAutolinking.swift +16 -0
- package/nitrogen/generated/shared/c++/HybridTamaguiRegistrySpec.cpp +27 -0
- package/nitrogen/generated/shared/c++/HybridTamaguiRegistrySpec.hpp +68 -0
- package/package.json +69 -6
- package/src/index.native.ts +174 -0
- package/src/index.ts +79 -0
- package/src/mirror.ts +31 -0
- package/src/processStyleColors.ts +42 -0
- package/src/specs/TamaguiRegistry.nitro.ts +51 -0
- package/src/types.ts +65 -0
- package/types/index.d.ts +20 -0
- package/types/index.d.ts.map +11 -0
- package/types/index.native.d.ts +37 -0
- package/types/index.native.d.ts.map +11 -0
- package/types/mirror.d.ts +7 -0
- package/types/mirror.d.ts.map +11 -0
- package/types/processStyleColors.d.ts +3 -0
- package/types/processStyleColors.d.ts.map +11 -0
- package/types/specs/TamaguiRegistry.nitro.d.ts +49 -0
- package/types/specs/TamaguiRegistry.nitro.d.ts.map +11 -0
- package/types/types.d.ts +61 -0
- package/types/types.d.ts.map +11 -0
package/package.json
CHANGED
|
@@ -1,15 +1,78 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tamagui/native-registry",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.0.0-beta.643.1",
|
|
4
|
+
"description": "Generic native style registry: zero-re-render style updates via Fabric ShadowTree commits",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"types": "./types/index.d.ts",
|
|
8
|
+
"main": "dist/cjs",
|
|
9
|
+
"module": "dist/esm",
|
|
10
|
+
"react-native": "src/index.native.ts",
|
|
11
|
+
"files": [
|
|
12
|
+
"src",
|
|
13
|
+
"!src/__tests__",
|
|
14
|
+
"types",
|
|
15
|
+
"dist",
|
|
16
|
+
"nitrogen",
|
|
17
|
+
"android",
|
|
18
|
+
"cpp",
|
|
19
|
+
"nitro.json",
|
|
20
|
+
"TamaguiRegistry.podspec"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tamagui-build",
|
|
24
|
+
"watch": "tamagui-build --watch",
|
|
25
|
+
"clean": "tamagui-build clean",
|
|
26
|
+
"clean:build": "tamagui-build clean:build",
|
|
27
|
+
"codegen": "nitrogen",
|
|
28
|
+
"test": "vitest run"
|
|
29
|
+
},
|
|
30
|
+
"exports": {
|
|
31
|
+
"./package.json": "./package.json",
|
|
32
|
+
".": {
|
|
33
|
+
"react-native": {
|
|
34
|
+
"types": "./types/index.d.ts",
|
|
35
|
+
"module": "./dist/esm/index.native.js",
|
|
36
|
+
"import": "./dist/esm/index.native.js",
|
|
37
|
+
"require": "./dist/cjs/index.native.js"
|
|
38
|
+
},
|
|
39
|
+
"types": "./types/index.d.ts",
|
|
40
|
+
"browser": "./dist/esm/index.mjs",
|
|
41
|
+
"module": "./dist/esm/index.mjs",
|
|
42
|
+
"import": "./dist/esm/index.mjs",
|
|
43
|
+
"require": "./dist/cjs/index.cjs",
|
|
44
|
+
"default": "./dist/esm/index.mjs"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@tamagui/build": "3.0.0-beta.643.1",
|
|
49
|
+
"react": ">=19",
|
|
50
|
+
"react-native": "0.86.2",
|
|
51
|
+
"react-native-nitro-modules": "^0.36.5",
|
|
52
|
+
"typescript": "~6.0.3",
|
|
53
|
+
"vitest": "4.0.4",
|
|
54
|
+
"nitrogen": "^0.36.5"
|
|
55
|
+
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"react": "*",
|
|
58
|
+
"react-native": ">=0.81.0",
|
|
59
|
+
"react-native-nitro-modules": ">=0.36.0",
|
|
60
|
+
"react-native-web": "*"
|
|
61
|
+
},
|
|
62
|
+
"peerDependenciesMeta": {
|
|
63
|
+
"react-native-nitro-modules": {
|
|
64
|
+
"optional": true
|
|
65
|
+
},
|
|
66
|
+
"react-native-web": {
|
|
67
|
+
"optional": true
|
|
68
|
+
}
|
|
69
|
+
},
|
|
5
70
|
"repository": {
|
|
6
71
|
"type": "git",
|
|
7
|
-
"url": "git+https://github.com/tamagui/tamagui.git"
|
|
72
|
+
"url": "git+https://github.com/tamagui/tamagui.git",
|
|
73
|
+
"directory": "code/core/native-registry"
|
|
8
74
|
},
|
|
9
75
|
"license": "MIT",
|
|
10
|
-
"files": [
|
|
11
|
-
"README.md"
|
|
12
|
-
],
|
|
13
76
|
"publishConfig": {
|
|
14
77
|
"access": "public"
|
|
15
78
|
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native implementation backed by the TamaguiRegistry Nitro HybridObject.
|
|
3
|
+
* The C++ engine commits style updates directly to Fabric's ShadowTree via
|
|
4
|
+
* UIManager::updateShadowTree (RN >= 0.81), with zero React re-renders.
|
|
5
|
+
*/
|
|
6
|
+
import { NitroModules } from 'react-native-nitro-modules'
|
|
7
|
+
import type { TamaguiRegistry } from './specs/TamaguiRegistry.nitro'
|
|
8
|
+
import type {
|
|
9
|
+
LinkHandle,
|
|
10
|
+
RegistryStats,
|
|
11
|
+
Unlink,
|
|
12
|
+
ViewSlots,
|
|
13
|
+
ViewStateSnapshot,
|
|
14
|
+
ViewStateTableUpdate,
|
|
15
|
+
ViewStateUpdate,
|
|
16
|
+
} from './types'
|
|
17
|
+
import {
|
|
18
|
+
ROOT_SCOPE,
|
|
19
|
+
getMirroredStateName,
|
|
20
|
+
removeMirroredScope,
|
|
21
|
+
setMirroredStateName,
|
|
22
|
+
} from './mirror'
|
|
23
|
+
import { processStyleColors } from './processStyleColors'
|
|
24
|
+
|
|
25
|
+
export type {
|
|
26
|
+
LinkHandle,
|
|
27
|
+
RegistryStats,
|
|
28
|
+
Unlink,
|
|
29
|
+
ViewSlots,
|
|
30
|
+
ViewStateSnapshot,
|
|
31
|
+
ViewStateTableUpdate,
|
|
32
|
+
ViewStateUpdate,
|
|
33
|
+
} from './types'
|
|
34
|
+
export { ROOT_SCOPE, getMirroredStateName } from './mirror'
|
|
35
|
+
export { processStyleColors } from './processStyleColors'
|
|
36
|
+
|
|
37
|
+
/** Full engine surface: typed Nitro methods plus the raw-JSI methods. */
|
|
38
|
+
interface Engine extends TamaguiRegistry {
|
|
39
|
+
link(shadowNode: unknown, slots: object, scopeId: string): number
|
|
40
|
+
applyViewStates(entries: ViewStateUpdate[]): void
|
|
41
|
+
updateViewStateTables(entries: ViewStateTableUpdate[]): void
|
|
42
|
+
getViewState(id: number): ViewStateSnapshot | null
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let engine: Engine | null = null
|
|
46
|
+
let initError: unknown = null
|
|
47
|
+
try {
|
|
48
|
+
engine = NitroModules.createHybridObject<TamaguiRegistry>('TamaguiRegistry') as Engine
|
|
49
|
+
} catch (error) {
|
|
50
|
+
initError = error
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function isAvailable(): boolean {
|
|
54
|
+
return engine !== null
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getEngine(): Engine {
|
|
58
|
+
if (engine) return engine
|
|
59
|
+
const detail = initError instanceof Error ? ` ${initError.message}` : ''
|
|
60
|
+
throw new Error(
|
|
61
|
+
`[@tamagui/native-registry] TamaguiRegistry failed to initialize; is react-native-nitro-modules installed and the app rebuilt?${detail}`
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Extract the opaque ShadowNode JSI wrapper from a Fabric host component ref.
|
|
67
|
+
* Same internals access as Unistyles; verified against RN 0.86.
|
|
68
|
+
*/
|
|
69
|
+
function getShadowNode(ref: unknown): unknown | null {
|
|
70
|
+
const handle = (ref as Record<string, unknown>)?.__internalInstanceHandle as
|
|
71
|
+
| { stateNode?: { node?: unknown } }
|
|
72
|
+
| undefined
|
|
73
|
+
return handle?.stateNode?.node ?? null
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Link a mounted view to the engine. Captures the ShadowNode once, returns
|
|
78
|
+
* a handle keyed by the engine-issued id: unlink never re-derives anything
|
|
79
|
+
* from the ref, so a torn-down ref cannot leave a stale entry behind.
|
|
80
|
+
*/
|
|
81
|
+
export function link(
|
|
82
|
+
ref: unknown,
|
|
83
|
+
slots: ViewSlots,
|
|
84
|
+
scopeId: string = ROOT_SCOPE
|
|
85
|
+
): LinkHandle | null {
|
|
86
|
+
const node = getShadowNode(ref)
|
|
87
|
+
if (!node) return null
|
|
88
|
+
|
|
89
|
+
const e = getEngine()
|
|
90
|
+
const prepared: Record<string, unknown> = {}
|
|
91
|
+
if (slots.base) prepared.base = processStyleColors(slots.base)
|
|
92
|
+
if (slots.state) {
|
|
93
|
+
const state: Record<string, unknown> = {}
|
|
94
|
+
for (const name in slots.state) {
|
|
95
|
+
state[name] = processStyleColors(slots.state[name])
|
|
96
|
+
}
|
|
97
|
+
prepared.state = state
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const id = e.link(node, prepared, scopeId)
|
|
101
|
+
let unlinked = false
|
|
102
|
+
return {
|
|
103
|
+
id,
|
|
104
|
+
unlink: () => {
|
|
105
|
+
if (unlinked) return
|
|
106
|
+
unlinked = true
|
|
107
|
+
e.unlink(id)
|
|
108
|
+
},
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Batched per-view state selection: cold entries carry `props` (computed by
|
|
114
|
+
* the caller, colors already processed via processStyleColors), warm entries
|
|
115
|
+
* just name the state. One native commit for the whole batch.
|
|
116
|
+
*/
|
|
117
|
+
export function applyViewStates(entries: ViewStateUpdate[]): void {
|
|
118
|
+
if (entries.length === 0) return
|
|
119
|
+
getEngine().applyViewStates(entries)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Fill lazily resolved state-table entries without switching a view to the
|
|
124
|
+
* per-view runtime controller. The native engine commits an entry immediately
|
|
125
|
+
* only when that state is already active for the view's scope.
|
|
126
|
+
*/
|
|
127
|
+
export function updateViewStateTables(entries: ViewStateTableUpdate[]): void {
|
|
128
|
+
if (entries.length === 0) return
|
|
129
|
+
getEngine().updateViewStateTables(
|
|
130
|
+
entries.map((entry) => ({ ...entry, props: processStyleColors(entry.props) }))
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Set the active state name (e.g. theme name) for a scope and commit the
|
|
136
|
+
* update natively. The JS mirror updates first so any concurrent React
|
|
137
|
+
* render paints the same styles the engine commits.
|
|
138
|
+
*/
|
|
139
|
+
export function setStateName(stateName: string, scopeId: string = ROOT_SCOPE): void {
|
|
140
|
+
setMirroredStateName(scopeId, stateName)
|
|
141
|
+
getEngine().setStateName(scopeId, stateName)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function removeScope(scopeId: string): void {
|
|
145
|
+
removeMirroredScope(scopeId)
|
|
146
|
+
getEngine().removeScope(scopeId)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Resolve the props a view should render right now, mirror-consistent. */
|
|
150
|
+
export function resolveSlots(
|
|
151
|
+
slots: ViewSlots,
|
|
152
|
+
scopeId: string = ROOT_SCOPE
|
|
153
|
+
): Record<string, unknown> {
|
|
154
|
+
const name = getMirroredStateName(scopeId)
|
|
155
|
+
return {
|
|
156
|
+
...slots.base,
|
|
157
|
+
...(name ? slots.state?.[name] : undefined),
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Debug/test introspection of a linked view's engine tables. Not a hot path. */
|
|
162
|
+
export function getViewState(id: number): ViewStateSnapshot | null {
|
|
163
|
+
if (!engine) return null
|
|
164
|
+
return engine.getViewState(id)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function getStats(): RegistryStats {
|
|
168
|
+
if (!engine) return { viewCount: 0, commitCount: 0, missCount: 0 }
|
|
169
|
+
return {
|
|
170
|
+
viewCount: engine.getViewCount(),
|
|
171
|
+
commitCount: engine.getCommitCount(),
|
|
172
|
+
missCount: engine.getMissCount(),
|
|
173
|
+
}
|
|
174
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web/no-native fallback. The registry is a native-only optimization; on web
|
|
3
|
+
* (or when the native module is absent) the mirror still tracks scope state
|
|
4
|
+
* so shared code can resolve slots, but nothing links and nothing commits.
|
|
5
|
+
*/
|
|
6
|
+
import type {
|
|
7
|
+
LinkHandle,
|
|
8
|
+
RegistryStats,
|
|
9
|
+
ViewSlots,
|
|
10
|
+
ViewStateSnapshot,
|
|
11
|
+
ViewStateTableUpdate,
|
|
12
|
+
ViewStateUpdate,
|
|
13
|
+
} from './types'
|
|
14
|
+
import {
|
|
15
|
+
ROOT_SCOPE,
|
|
16
|
+
getMirroredStateName,
|
|
17
|
+
removeMirroredScope,
|
|
18
|
+
setMirroredStateName,
|
|
19
|
+
} from './mirror'
|
|
20
|
+
|
|
21
|
+
export type {
|
|
22
|
+
LinkHandle,
|
|
23
|
+
RegistryStats,
|
|
24
|
+
Unlink,
|
|
25
|
+
ViewSlots,
|
|
26
|
+
ViewStateSnapshot,
|
|
27
|
+
ViewStateTableUpdate,
|
|
28
|
+
ViewStateUpdate,
|
|
29
|
+
} from './types'
|
|
30
|
+
export { ROOT_SCOPE, getMirroredStateName } from './mirror'
|
|
31
|
+
|
|
32
|
+
export function isAvailable(): boolean {
|
|
33
|
+
return false
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function link(
|
|
37
|
+
_ref: unknown,
|
|
38
|
+
_slots: ViewSlots,
|
|
39
|
+
_scopeId?: string
|
|
40
|
+
): LinkHandle | null {
|
|
41
|
+
return null
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function applyViewStates(_entries: ViewStateUpdate[]): void {}
|
|
45
|
+
|
|
46
|
+
export function updateViewStateTables(_entries: ViewStateTableUpdate[]): void {}
|
|
47
|
+
|
|
48
|
+
export function getViewState(_id: number): ViewStateSnapshot | null {
|
|
49
|
+
return null
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function setStateName(stateName: string, scopeId: string = ROOT_SCOPE): void {
|
|
53
|
+
setMirroredStateName(scopeId, stateName)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function removeScope(scopeId: string): void {
|
|
57
|
+
removeMirroredScope(scopeId)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function resolveSlots(
|
|
61
|
+
slots: ViewSlots,
|
|
62
|
+
scopeId: string = ROOT_SCOPE
|
|
63
|
+
): Record<string, unknown> {
|
|
64
|
+
const name = getMirroredStateName(scopeId)
|
|
65
|
+
return {
|
|
66
|
+
...slots.base,
|
|
67
|
+
...(name ? slots.state?.[name] : undefined),
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function getStats(): RegistryStats {
|
|
72
|
+
return { viewCount: 0, commitCount: 0, missCount: 0 }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function processStyleColors(
|
|
76
|
+
props: Record<string, unknown>
|
|
77
|
+
): Record<string, unknown> {
|
|
78
|
+
return props
|
|
79
|
+
}
|
package/src/mirror.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JS mirror of the engine's scope state.
|
|
3
|
+
*
|
|
4
|
+
* React re-renders of a linked component must never revert a native commit,
|
|
5
|
+
* so components read their current state name from this mirror at render
|
|
6
|
+
* time (without subscribing) and always paint styles that match what the
|
|
7
|
+
* engine last committed. The mirror is updated synchronously before the
|
|
8
|
+
* native call in setStateName, so render and engine can never disagree.
|
|
9
|
+
*/
|
|
10
|
+
const scopeStates = new Map<string, string>()
|
|
11
|
+
|
|
12
|
+
export const ROOT_SCOPE = ''
|
|
13
|
+
|
|
14
|
+
export function getMirroredStateName(scopeId: string = ROOT_SCOPE): string | undefined {
|
|
15
|
+
return (
|
|
16
|
+
scopeStates.get(scopeId) ??
|
|
17
|
+
(scopeId === ROOT_SCOPE ? undefined : scopeStates.get(ROOT_SCOPE))
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function setMirroredStateName(scopeId: string, stateName: string): void {
|
|
22
|
+
scopeStates.set(scopeId, stateName)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function removeMirroredScope(scopeId: string): void {
|
|
26
|
+
scopeStates.delete(scopeId)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function resetMirror(): void {
|
|
30
|
+
scopeStates.clear()
|
|
31
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fabric's C++ prop parser takes colors as ARGB ints, not CSS strings, so
|
|
3
|
+
* every color prop must be converted before props reach the engine. The
|
|
4
|
+
* compiler mappings and runtime-mode pushes both use this exact runtime
|
|
5
|
+
* processor before props cross into the engine.
|
|
6
|
+
*/
|
|
7
|
+
import { processColor } from 'react-native'
|
|
8
|
+
|
|
9
|
+
const COLOR_PROPS = new Set([
|
|
10
|
+
'color',
|
|
11
|
+
'backgroundColor',
|
|
12
|
+
'borderColor',
|
|
13
|
+
'borderTopColor',
|
|
14
|
+
'borderBottomColor',
|
|
15
|
+
'borderLeftColor',
|
|
16
|
+
'borderRightColor',
|
|
17
|
+
'borderStartColor',
|
|
18
|
+
'borderEndColor',
|
|
19
|
+
'borderBlockColor',
|
|
20
|
+
'borderBlockStartColor',
|
|
21
|
+
'borderBlockEndColor',
|
|
22
|
+
'shadowColor',
|
|
23
|
+
'textShadowColor',
|
|
24
|
+
'textDecorationColor',
|
|
25
|
+
'tintColor',
|
|
26
|
+
'overlayColor',
|
|
27
|
+
])
|
|
28
|
+
|
|
29
|
+
export function processStyleColors(
|
|
30
|
+
props: Record<string, unknown>
|
|
31
|
+
): Record<string, unknown> {
|
|
32
|
+
let out: Record<string, unknown> | null = null
|
|
33
|
+
for (const key in props) {
|
|
34
|
+
const value = props[key]
|
|
35
|
+
if (COLOR_PROPS.has(key) && typeof value === 'string') {
|
|
36
|
+
out ??= { ...props }
|
|
37
|
+
const processed = processColor(value)
|
|
38
|
+
if (processed != null) out[key] = processed
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return out ?? props
|
|
42
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { HybridObject } from 'react-native-nitro-modules'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Typed surface of the native registry.
|
|
5
|
+
*
|
|
6
|
+
* The engine is deliberately generic: it knows nothing about Tamagui themes
|
|
7
|
+
* beyond "a named state per scope selects which slot props apply". Tamagui
|
|
8
|
+
* semantics (theme names, scope wiring, compiler output) live in JS.
|
|
9
|
+
*
|
|
10
|
+
* Two methods are NOT in this spec because they take values Nitro cannot
|
|
11
|
+
* type: `link(shadowNode, slots, scopeId) -> number` and internal raw-JSI
|
|
12
|
+
* registration. They are registered as raw hybrid methods in C++ and typed
|
|
13
|
+
* on the JS side in index.native.ts.
|
|
14
|
+
*
|
|
15
|
+
* Threading: every method must be called from the JS thread. The engine is
|
|
16
|
+
* single-threaded by contract and holds no locks.
|
|
17
|
+
*/
|
|
18
|
+
export interface TamaguiRegistry extends HybridObject<{ ios: 'c++'; android: 'c++' }> {
|
|
19
|
+
/**
|
|
20
|
+
* Set the active state name for a scope ('' = root scope) and commit the
|
|
21
|
+
* matching slot props for every affected linked view in one ShadowTree
|
|
22
|
+
* transaction.
|
|
23
|
+
*/
|
|
24
|
+
setStateName(scopeId: string, stateName: string): void
|
|
25
|
+
|
|
26
|
+
/** Read the active state name for a scope ('' = root). */
|
|
27
|
+
getStateName(scopeId: string): string
|
|
28
|
+
|
|
29
|
+
/** Drop a scope entry (cleanup when a scope provider unmounts). */
|
|
30
|
+
removeScope(scopeId: string): void
|
|
31
|
+
|
|
32
|
+
/** Unlink by the id returned from link(). Safe to call twice. */
|
|
33
|
+
unlink(id: number): void
|
|
34
|
+
|
|
35
|
+
/** Number of currently linked views. */
|
|
36
|
+
getViewCount(): number
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Number of ShadowTree commits performed. Benchmark honesty counter: a
|
|
40
|
+
* measurement where this does not increase never exercised the fast path.
|
|
41
|
+
*/
|
|
42
|
+
getCommitCount(): number
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Number of linked views skipped during commits because their slots had no
|
|
46
|
+
* entry for the active state name. Always 0 when the compiler emitted
|
|
47
|
+
* exhaustive keys; anything else is an upstream bug, not a runtime
|
|
48
|
+
* condition to recover from.
|
|
49
|
+
*/
|
|
50
|
+
getMissCount(): number
|
|
51
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slot props for one linked view.
|
|
3
|
+
*
|
|
4
|
+
* v1 implements two slot kinds: `base` (state-independent props, applied
|
|
5
|
+
* under every state) and `state` (props keyed by state name, e.g. theme
|
|
6
|
+
* name; the scope's active name selects which entry applies). Future kinds
|
|
7
|
+
* (media, press, group, container) extend this shape; the engine merge
|
|
8
|
+
* order is fixed: base, then state, then future kinds.
|
|
9
|
+
*
|
|
10
|
+
* Keys must be exhaustive for every state name the scope can take. The
|
|
11
|
+
* engine does exact lookups only: no fallback chains, no name parsing. A
|
|
12
|
+
* miss increments the engine's miss counter and is a bug in the emitter.
|
|
13
|
+
*/
|
|
14
|
+
export interface ViewSlots {
|
|
15
|
+
base?: Record<string, unknown>
|
|
16
|
+
state?: Record<string, Record<string, unknown>>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface RegistryStats {
|
|
20
|
+
viewCount: number
|
|
21
|
+
commitCount: number
|
|
22
|
+
missCount: number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Returned by link(); call to unlink. Safe to call more than once. */
|
|
26
|
+
export type Unlink = () => void
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Handle for a linked view. `id` addresses the view in batched per-view
|
|
30
|
+
* operations (applyViewStates); `unlink` removes it. null when the ref had
|
|
31
|
+
* no shadow node (never mounted) or the engine is unavailable (web).
|
|
32
|
+
*/
|
|
33
|
+
export interface LinkHandle {
|
|
34
|
+
id: number
|
|
35
|
+
unlink: Unlink
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* One entry of a batched per-view state update. When `props` is present it
|
|
40
|
+
* is merged into the view's state table under `state` first (lazy warm-up
|
|
41
|
+
* for runtime integrations); the view's active state then becomes `state`
|
|
42
|
+
* and all entries commit natively in one transaction.
|
|
43
|
+
*/
|
|
44
|
+
export interface ViewStateUpdate {
|
|
45
|
+
id: number
|
|
46
|
+
state: string
|
|
47
|
+
props?: Record<string, unknown>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** add or replace one resolved state-table entry without changing its view's controller */
|
|
51
|
+
export interface ViewStateTableUpdate {
|
|
52
|
+
id: number
|
|
53
|
+
state: string
|
|
54
|
+
props: Record<string, unknown>
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Debug/test snapshot of a linked view's engine tables (getViewState). */
|
|
58
|
+
export interface ViewStateSnapshot {
|
|
59
|
+
scopeId: string
|
|
60
|
+
activeState: string
|
|
61
|
+
base: Record<string, unknown> | null
|
|
62
|
+
states: Record<string, Record<string, unknown>> | null
|
|
63
|
+
/** the family's sticky nativeProps_DEPRECATED merge, null when unset */
|
|
64
|
+
nativeProps: Record<string, unknown> | null
|
|
65
|
+
}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web/no-native fallback. The registry is a native-only optimization; on web
|
|
3
|
+
* (or when the native module is absent) the mirror still tracks scope state
|
|
4
|
+
* so shared code can resolve slots, but nothing links and nothing commits.
|
|
5
|
+
*/
|
|
6
|
+
import type { LinkHandle, RegistryStats, ViewSlots, ViewStateSnapshot, ViewStateTableUpdate, ViewStateUpdate } from "./types";
|
|
7
|
+
export type { LinkHandle, RegistryStats, Unlink, ViewSlots, ViewStateSnapshot, ViewStateTableUpdate, ViewStateUpdate } from "./types";
|
|
8
|
+
export { ROOT_SCOPE, getMirroredStateName } from "./mirror";
|
|
9
|
+
export declare function isAvailable(): boolean;
|
|
10
|
+
export declare function link(_ref: unknown, _slots: ViewSlots, _scopeId?: string): LinkHandle | null;
|
|
11
|
+
export declare function applyViewStates(_entries: ViewStateUpdate[]): void;
|
|
12
|
+
export declare function updateViewStateTables(_entries: ViewStateTableUpdate[]): void;
|
|
13
|
+
export declare function getViewState(_id: number): ViewStateSnapshot | null;
|
|
14
|
+
export declare function setStateName(stateName: string, scopeId?: string): void;
|
|
15
|
+
export declare function removeScope(scopeId: string): void;
|
|
16
|
+
export declare function resolveSlots(slots: ViewSlots, scopeId?: string): Record<string, unknown>;
|
|
17
|
+
export declare function getStats(): RegistryStats;
|
|
18
|
+
export declare function processStyleColors(props: Record<string, unknown>): Record<string, unknown>;
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mappings": ";;;;;AAKA,cACE,YACA,eACA,WACA,mBACA,sBACA,uBACK;AAQP,cACE,YACA,eACA,QACA,WACA,mBACA,sBACA,uBACK;AACP,SAAS,YAAY,4BAA4B;AAEjD,OAAO,iBAAS;AAIhB,OAAO,iBAAS,KACd,eACA,QAAQ,WACR,oBACC;AAIH,OAAO,iBAAS,gBAAgB,UAAU;AAE1C,OAAO,iBAAS,sBAAsB,UAAU;AAEhD,OAAO,iBAAS,aAAa,cAAc;AAI3C,OAAO,iBAAS,aAAa,mBAAmB;AAIhD,OAAO,iBAAS,YAAY;AAI5B,OAAO,iBAAS,aACd,OAAO,WACP,mBACC;AAQH,OAAO,iBAAS,YAAY;AAI5B,OAAO,iBAAS,mBACd,OAAO,0BACN",
|
|
3
|
+
"names": [],
|
|
4
|
+
"sources": [
|
|
5
|
+
"src/index.ts"
|
|
6
|
+
],
|
|
7
|
+
"version": 3,
|
|
8
|
+
"sourcesContent": [
|
|
9
|
+
"/**\n * Web/no-native fallback. The registry is a native-only optimization; on web\n * (or when the native module is absent) the mirror still tracks scope state\n * so shared code can resolve slots, but nothing links and nothing commits.\n */\nimport type {\n LinkHandle,\n RegistryStats,\n ViewSlots,\n ViewStateSnapshot,\n ViewStateTableUpdate,\n ViewStateUpdate,\n} from './types'\nimport {\n ROOT_SCOPE,\n getMirroredStateName,\n removeMirroredScope,\n setMirroredStateName,\n} from './mirror'\n\nexport type {\n LinkHandle,\n RegistryStats,\n Unlink,\n ViewSlots,\n ViewStateSnapshot,\n ViewStateTableUpdate,\n ViewStateUpdate,\n} from './types'\nexport { ROOT_SCOPE, getMirroredStateName } from './mirror'\n\nexport function isAvailable(): boolean {\n return false\n}\n\nexport function link(\n _ref: unknown,\n _slots: ViewSlots,\n _scopeId?: string\n): LinkHandle | null {\n return null\n}\n\nexport function applyViewStates(_entries: ViewStateUpdate[]): void {}\n\nexport function updateViewStateTables(_entries: ViewStateTableUpdate[]): void {}\n\nexport function getViewState(_id: number): ViewStateSnapshot | null {\n return null\n}\n\nexport function setStateName(stateName: string, scopeId: string = ROOT_SCOPE): void {\n setMirroredStateName(scopeId, stateName)\n}\n\nexport function removeScope(scopeId: string): void {\n removeMirroredScope(scopeId)\n}\n\nexport function resolveSlots(\n slots: ViewSlots,\n scopeId: string = ROOT_SCOPE\n): Record<string, unknown> {\n const name = getMirroredStateName(scopeId)\n return {\n ...slots.base,\n ...(name ? slots.state?.[name] : undefined),\n }\n}\n\nexport function getStats(): RegistryStats {\n return { viewCount: 0, commitCount: 0, missCount: 0 }\n}\n\nexport function processStyleColors(\n props: Record<string, unknown>\n): Record<string, unknown> {\n return props\n}\n"
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { LinkHandle, RegistryStats, ViewSlots, ViewStateSnapshot, ViewStateTableUpdate, ViewStateUpdate } from "./types";
|
|
2
|
+
export type { LinkHandle, RegistryStats, Unlink, ViewSlots, ViewStateSnapshot, ViewStateTableUpdate, ViewStateUpdate } from "./types";
|
|
3
|
+
export { ROOT_SCOPE, getMirroredStateName } from "./mirror";
|
|
4
|
+
export { processStyleColors } from "./processStyleColors";
|
|
5
|
+
export declare function isAvailable(): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Link a mounted view to the engine. Captures the ShadowNode once, returns
|
|
8
|
+
* a handle keyed by the engine-issued id: unlink never re-derives anything
|
|
9
|
+
* from the ref, so a torn-down ref cannot leave a stale entry behind.
|
|
10
|
+
*/
|
|
11
|
+
export declare function link(ref: unknown, slots: ViewSlots, scopeId?: string): LinkHandle | null;
|
|
12
|
+
/**
|
|
13
|
+
* Batched per-view state selection: cold entries carry `props` (computed by
|
|
14
|
+
* the caller, colors already processed via processStyleColors), warm entries
|
|
15
|
+
* just name the state. One native commit for the whole batch.
|
|
16
|
+
*/
|
|
17
|
+
export declare function applyViewStates(entries: ViewStateUpdate[]): void;
|
|
18
|
+
/**
|
|
19
|
+
* Fill lazily resolved state-table entries without switching a view to the
|
|
20
|
+
* per-view runtime controller. The native engine commits an entry immediately
|
|
21
|
+
* only when that state is already active for the view's scope.
|
|
22
|
+
*/
|
|
23
|
+
export declare function updateViewStateTables(entries: ViewStateTableUpdate[]): void;
|
|
24
|
+
/**
|
|
25
|
+
* Set the active state name (e.g. theme name) for a scope and commit the
|
|
26
|
+
* update natively. The JS mirror updates first so any concurrent React
|
|
27
|
+
* render paints the same styles the engine commits.
|
|
28
|
+
*/
|
|
29
|
+
export declare function setStateName(stateName: string, scopeId?: string): void;
|
|
30
|
+
export declare function removeScope(scopeId: string): void;
|
|
31
|
+
/** Resolve the props a view should render right now, mirror-consistent. */
|
|
32
|
+
export declare function resolveSlots(slots: ViewSlots, scopeId?: string): Record<string, unknown>;
|
|
33
|
+
/** Debug/test introspection of a linked view's engine tables. Not a hot path. */
|
|
34
|
+
export declare function getViewState(id: number): ViewStateSnapshot | null;
|
|
35
|
+
export declare function getStats(): RegistryStats;
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=index.native.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mappings": "AAOA,cACE,YACA,eAEA,WACA,mBACA,sBACA,uBACK;AASP,cACE,YACA,eACA,QACA,WACA,mBACA,sBACA,uBACK;AACP,SAAS,YAAY,4BAA4B;AACjD,SAAS,0BAA0B;AAkBnC,OAAO,iBAAS;;;;;;AA4BhB,OAAO,iBAAS,KACd,cACA,OAAO,WACP,mBACC;;;;;;AAgCH,OAAO,iBAAS,gBAAgB,SAAS;;;;;;AAUzC,OAAO,iBAAS,sBAAsB,SAAS;;;;;;AAY/C,OAAO,iBAAS,aAAa,mBAAmB;AAKhD,OAAO,iBAAS,YAAY;;AAM5B,OAAO,iBAAS,aACd,OAAO,WACP,mBACC;;AASH,OAAO,iBAAS,aAAa,aAAa;AAK1C,OAAO,iBAAS,YAAY",
|
|
3
|
+
"names": [],
|
|
4
|
+
"sources": [
|
|
5
|
+
"src/index.native.ts"
|
|
6
|
+
],
|
|
7
|
+
"version": 3,
|
|
8
|
+
"sourcesContent": [
|
|
9
|
+
"/**\n * Native implementation backed by the TamaguiRegistry Nitro HybridObject.\n * The C++ engine commits style updates directly to Fabric's ShadowTree via\n * UIManager::updateShadowTree (RN >= 0.81), with zero React re-renders.\n */\nimport { NitroModules } from 'react-native-nitro-modules'\nimport type { TamaguiRegistry } from './specs/TamaguiRegistry.nitro'\nimport type {\n LinkHandle,\n RegistryStats,\n Unlink,\n ViewSlots,\n ViewStateSnapshot,\n ViewStateTableUpdate,\n ViewStateUpdate,\n} from './types'\nimport {\n ROOT_SCOPE,\n getMirroredStateName,\n removeMirroredScope,\n setMirroredStateName,\n} from './mirror'\nimport { processStyleColors } from './processStyleColors'\n\nexport type {\n LinkHandle,\n RegistryStats,\n Unlink,\n ViewSlots,\n ViewStateSnapshot,\n ViewStateTableUpdate,\n ViewStateUpdate,\n} from './types'\nexport { ROOT_SCOPE, getMirroredStateName } from './mirror'\nexport { processStyleColors } from './processStyleColors'\n\n/** Full engine surface: typed Nitro methods plus the raw-JSI methods. */\ninterface Engine extends TamaguiRegistry {\n link(shadowNode: unknown, slots: object, scopeId: string): number\n applyViewStates(entries: ViewStateUpdate[]): void\n updateViewStateTables(entries: ViewStateTableUpdate[]): void\n getViewState(id: number): ViewStateSnapshot | null\n}\n\nlet engine: Engine | null = null\nlet initError: unknown = null\ntry {\n engine = NitroModules.createHybridObject<TamaguiRegistry>('TamaguiRegistry') as Engine\n} catch (error) {\n initError = error\n}\n\nexport function isAvailable(): boolean {\n return engine !== null\n}\n\nfunction getEngine(): Engine {\n if (engine) return engine\n const detail = initError instanceof Error ? ` ${initError.message}` : ''\n throw new Error(\n `[@tamagui/native-registry] TamaguiRegistry failed to initialize; is react-native-nitro-modules installed and the app rebuilt?${detail}`\n )\n}\n\n/**\n * Extract the opaque ShadowNode JSI wrapper from a Fabric host component ref.\n * Same internals access as Unistyles; verified against RN 0.86.\n */\nfunction getShadowNode(ref: unknown): unknown | null {\n const handle = (ref as Record<string, unknown>)?.__internalInstanceHandle as\n | { stateNode?: { node?: unknown } }\n | undefined\n return handle?.stateNode?.node ?? null\n}\n\n/**\n * Link a mounted view to the engine. Captures the ShadowNode once, returns\n * a handle keyed by the engine-issued id: unlink never re-derives anything\n * from the ref, so a torn-down ref cannot leave a stale entry behind.\n */\nexport function link(\n ref: unknown,\n slots: ViewSlots,\n scopeId: string = ROOT_SCOPE\n): LinkHandle | null {\n const node = getShadowNode(ref)\n if (!node) return null\n\n const e = getEngine()\n const prepared: Record<string, unknown> = {}\n if (slots.base) prepared.base = processStyleColors(slots.base)\n if (slots.state) {\n const state: Record<string, unknown> = {}\n for (const name in slots.state) {\n state[name] = processStyleColors(slots.state[name])\n }\n prepared.state = state\n }\n\n const id = e.link(node, prepared, scopeId)\n let unlinked = false\n return {\n id,\n unlink: () => {\n if (unlinked) return\n unlinked = true\n e.unlink(id)\n },\n }\n}\n\n/**\n * Batched per-view state selection: cold entries carry `props` (computed by\n * the caller, colors already processed via processStyleColors), warm entries\n * just name the state. One native commit for the whole batch.\n */\nexport function applyViewStates(entries: ViewStateUpdate[]): void {\n if (entries.length === 0) return\n getEngine().applyViewStates(entries)\n}\n\n/**\n * Fill lazily resolved state-table entries without switching a view to the\n * per-view runtime controller. The native engine commits an entry immediately\n * only when that state is already active for the view's scope.\n */\nexport function updateViewStateTables(entries: ViewStateTableUpdate[]): void {\n if (entries.length === 0) return\n getEngine().updateViewStateTables(\n entries.map((entry) => ({ ...entry, props: processStyleColors(entry.props) }))\n )\n}\n\n/**\n * Set the active state name (e.g. theme name) for a scope and commit the\n * update natively. The JS mirror updates first so any concurrent React\n * render paints the same styles the engine commits.\n */\nexport function setStateName(stateName: string, scopeId: string = ROOT_SCOPE): void {\n setMirroredStateName(scopeId, stateName)\n getEngine().setStateName(scopeId, stateName)\n}\n\nexport function removeScope(scopeId: string): void {\n removeMirroredScope(scopeId)\n getEngine().removeScope(scopeId)\n}\n\n/** Resolve the props a view should render right now, mirror-consistent. */\nexport function resolveSlots(\n slots: ViewSlots,\n scopeId: string = ROOT_SCOPE\n): Record<string, unknown> {\n const name = getMirroredStateName(scopeId)\n return {\n ...slots.base,\n ...(name ? slots.state?.[name] : undefined),\n }\n}\n\n/** Debug/test introspection of a linked view's engine tables. Not a hot path. */\nexport function getViewState(id: number): ViewStateSnapshot | null {\n if (!engine) return null\n return engine.getViewState(id)\n}\n\nexport function getStats(): RegistryStats {\n if (!engine) return { viewCount: 0, commitCount: 0, missCount: 0 }\n return {\n viewCount: engine.getViewCount(),\n commitCount: engine.getCommitCount(),\n missCount: engine.getMissCount(),\n }\n}\n"
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const ROOT_SCOPE = "";
|
|
2
|
+
export declare function getMirroredStateName(scopeId?: string): string | undefined;
|
|
3
|
+
export declare function setMirroredStateName(scopeId: string, stateName: string): void;
|
|
4
|
+
export declare function removeMirroredScope(scopeId: string): void;
|
|
5
|
+
export declare function resetMirror(): void;
|
|
6
|
+
|
|
7
|
+
//# sourceMappingURL=mirror.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mappings": "AAWA,OAAO,cAAM,aAAa;AAE1B,OAAO,iBAAS,qBAAqB;AAOrC,OAAO,iBAAS,qBAAqB,iBAAiB;AAItD,OAAO,iBAAS,oBAAoB;AAIpC,OAAO,iBAAS",
|
|
3
|
+
"names": [],
|
|
4
|
+
"sources": [
|
|
5
|
+
"src/mirror.ts"
|
|
6
|
+
],
|
|
7
|
+
"version": 3,
|
|
8
|
+
"sourcesContent": [
|
|
9
|
+
"/**\n * JS mirror of the engine's scope state.\n *\n * React re-renders of a linked component must never revert a native commit,\n * so components read their current state name from this mirror at render\n * time (without subscribing) and always paint styles that match what the\n * engine last committed. The mirror is updated synchronously before the\n * native call in setStateName, so render and engine can never disagree.\n */\nconst scopeStates = new Map<string, string>()\n\nexport const ROOT_SCOPE = ''\n\nexport function getMirroredStateName(scopeId: string = ROOT_SCOPE): string | undefined {\n return (\n scopeStates.get(scopeId) ??\n (scopeId === ROOT_SCOPE ? undefined : scopeStates.get(ROOT_SCOPE))\n )\n}\n\nexport function setMirroredStateName(scopeId: string, stateName: string): void {\n scopeStates.set(scopeId, stateName)\n}\n\nexport function removeMirroredScope(scopeId: string): void {\n scopeStates.delete(scopeId)\n}\n\nexport function resetMirror(): void {\n scopeStates.clear()\n}\n"
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mappings": "AA4BA,OAAO,iBAAS,mBACd,OAAO,0BACN",
|
|
3
|
+
"names": [],
|
|
4
|
+
"sources": [
|
|
5
|
+
"src/processStyleColors.ts"
|
|
6
|
+
],
|
|
7
|
+
"version": 3,
|
|
8
|
+
"sourcesContent": [
|
|
9
|
+
"/**\n * Fabric's C++ prop parser takes colors as ARGB ints, not CSS strings, so\n * every color prop must be converted before props reach the engine. The\n * compiler mappings and runtime-mode pushes both use this exact runtime\n * processor before props cross into the engine.\n */\nimport { processColor } from 'react-native'\n\nconst COLOR_PROPS = new Set([\n 'color',\n 'backgroundColor',\n 'borderColor',\n 'borderTopColor',\n 'borderBottomColor',\n 'borderLeftColor',\n 'borderRightColor',\n 'borderStartColor',\n 'borderEndColor',\n 'borderBlockColor',\n 'borderBlockStartColor',\n 'borderBlockEndColor',\n 'shadowColor',\n 'textShadowColor',\n 'textDecorationColor',\n 'tintColor',\n 'overlayColor',\n])\n\nexport function processStyleColors(\n props: Record<string, unknown>\n): Record<string, unknown> {\n let out: Record<string, unknown> | null = null\n for (const key in props) {\n const value = props[key]\n if (COLOR_PROPS.has(key) && typeof value === 'string') {\n out ??= { ...props }\n const processed = processColor(value)\n if (processed != null) out[key] = processed\n }\n }\n return out ?? props\n}\n"
|
|
10
|
+
]
|
|
11
|
+
}
|