react-native-css 3.1.0-rc.0 → 3.1.0-rc.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.
Files changed (137) hide show
  1. package/README.md +24 -0
  2. package/dist/commonjs/babel/helpers.js +7 -0
  3. package/dist/commonjs/babel/helpers.js.map +1 -1
  4. package/dist/commonjs/babel/import-plugin.js +12 -6
  5. package/dist/commonjs/babel/import-plugin.js.map +1 -1
  6. package/dist/commonjs/babel/react-native-web.js +2 -2
  7. package/dist/commonjs/babel/react-native-web.js.map +1 -1
  8. package/dist/commonjs/babel/react-native.js +2 -2
  9. package/dist/commonjs/babel/react-native.js.map +1 -1
  10. package/dist/commonjs/compiler/compiler.js +15 -1
  11. package/dist/commonjs/compiler/compiler.js.map +1 -1
  12. package/dist/commonjs/compiler/declarations.js +1 -1
  13. package/dist/commonjs/compiler/declarations.js.map +1 -1
  14. package/dist/commonjs/compiler/selector-builder.js +2 -1
  15. package/dist/commonjs/compiler/selector-builder.js.map +1 -1
  16. package/dist/commonjs/compiler/stylesheet.js +11 -3
  17. package/dist/commonjs/compiler/stylesheet.js.map +1 -1
  18. package/dist/commonjs/metro/index.js.map +1 -1
  19. package/dist/commonjs/metro/metro-transformer.js +16 -3
  20. package/dist/commonjs/metro/metro-transformer.js.map +1 -1
  21. package/dist/commonjs/metro/warnings.js +135 -0
  22. package/dist/commonjs/metro/warnings.js.map +1 -0
  23. package/dist/commonjs/native/api.js +1 -1
  24. package/dist/commonjs/native/api.js.map +1 -1
  25. package/dist/commonjs/native/react/useNativeCss.js +15 -2
  26. package/dist/commonjs/native/react/useNativeCss.js.map +1 -1
  27. package/dist/commonjs/native/reactivity.js +30 -3
  28. package/dist/commonjs/native/reactivity.js.map +1 -1
  29. package/dist/commonjs/native-internal/root.js +18 -7
  30. package/dist/commonjs/native-internal/root.js.map +1 -1
  31. package/dist/commonjs/native-internal/variables.js +1 -1
  32. package/dist/commonjs/native-internal/variables.js.map +1 -1
  33. package/dist/module/babel/helpers.js +6 -0
  34. package/dist/module/babel/helpers.js.map +1 -1
  35. package/dist/module/babel/import-plugin.js +12 -6
  36. package/dist/module/babel/import-plugin.js.map +1 -1
  37. package/dist/module/babel/react-native-web.js +2 -2
  38. package/dist/module/babel/react-native-web.js.map +1 -1
  39. package/dist/module/babel/react-native.js +2 -2
  40. package/dist/module/babel/react-native.js.map +1 -1
  41. package/dist/module/compiler/compiler.js +15 -1
  42. package/dist/module/compiler/compiler.js.map +1 -1
  43. package/dist/module/compiler/compiler.types.js +2 -0
  44. package/dist/module/compiler/compiler.types.js.map +1 -1
  45. package/dist/module/compiler/declarations.js +1 -1
  46. package/dist/module/compiler/declarations.js.map +1 -1
  47. package/dist/module/compiler/selector-builder.js +2 -1
  48. package/dist/module/compiler/selector-builder.js.map +1 -1
  49. package/dist/module/compiler/stylesheet.js +11 -3
  50. package/dist/module/compiler/stylesheet.js.map +1 -1
  51. package/dist/module/metro/index.js.map +1 -1
  52. package/dist/module/metro/metro-transformer.js +16 -3
  53. package/dist/module/metro/metro-transformer.js.map +1 -1
  54. package/dist/module/metro/warnings.js +131 -0
  55. package/dist/module/metro/warnings.js.map +1 -0
  56. package/dist/module/native/api.js +2 -2
  57. package/dist/module/native/api.js.map +1 -1
  58. package/dist/module/native/react/useNativeCss.js +17 -4
  59. package/dist/module/native/react/useNativeCss.js.map +1 -1
  60. package/dist/module/native/reactivity.js +24 -1
  61. package/dist/module/native/reactivity.js.map +1 -1
  62. package/dist/module/native-internal/root.js +18 -7
  63. package/dist/module/native-internal/root.js.map +1 -1
  64. package/dist/module/native-internal/variables.js +2 -2
  65. package/dist/module/native-internal/variables.js.map +1 -1
  66. package/dist/typescript/commonjs/src/babel/helpers.d.ts +2 -1
  67. package/dist/typescript/commonjs/src/babel/helpers.d.ts.map +1 -1
  68. package/dist/typescript/commonjs/src/babel/import-plugin.d.ts.map +1 -1
  69. package/dist/typescript/commonjs/src/babel/react-native-web.d.ts.map +1 -1
  70. package/dist/typescript/commonjs/src/babel/react-native.d.ts.map +1 -1
  71. package/dist/typescript/commonjs/src/compiler/compiler.d.ts +1 -5
  72. package/dist/typescript/commonjs/src/compiler/compiler.d.ts.map +1 -1
  73. package/dist/typescript/commonjs/src/compiler/compiler.types.d.ts +6 -0
  74. package/dist/typescript/commonjs/src/compiler/compiler.types.d.ts.map +1 -1
  75. package/dist/typescript/commonjs/src/compiler/selector-builder.d.ts.map +1 -1
  76. package/dist/typescript/commonjs/src/compiler/stylesheet.d.ts +6 -8
  77. package/dist/typescript/commonjs/src/compiler/stylesheet.d.ts.map +1 -1
  78. package/dist/typescript/commonjs/src/jest/index.d.ts +2 -10
  79. package/dist/typescript/commonjs/src/jest/index.d.ts.map +1 -1
  80. package/dist/typescript/commonjs/src/metro/index.d.ts +4 -0
  81. package/dist/typescript/commonjs/src/metro/index.d.ts.map +1 -1
  82. package/dist/typescript/commonjs/src/metro/metro-transformer.d.ts +4 -1
  83. package/dist/typescript/commonjs/src/metro/metro-transformer.d.ts.map +1 -1
  84. package/dist/typescript/commonjs/src/metro/warnings.d.ts +13 -0
  85. package/dist/typescript/commonjs/src/metro/warnings.d.ts.map +1 -0
  86. package/dist/typescript/commonjs/src/native/api.d.ts.map +1 -1
  87. package/dist/typescript/commonjs/src/native/react/useNativeCss.d.ts.map +1 -1
  88. package/dist/typescript/commonjs/src/native/reactivity.d.ts +7 -0
  89. package/dist/typescript/commonjs/src/native/reactivity.d.ts.map +1 -1
  90. package/dist/typescript/commonjs/src/native-internal/root.d.ts +12 -0
  91. package/dist/typescript/commonjs/src/native-internal/root.d.ts.map +1 -1
  92. package/dist/typescript/commonjs/src/native-internal/variables.d.ts.map +1 -1
  93. package/dist/typescript/module/src/babel/helpers.d.ts +2 -1
  94. package/dist/typescript/module/src/babel/helpers.d.ts.map +1 -1
  95. package/dist/typescript/module/src/babel/import-plugin.d.ts.map +1 -1
  96. package/dist/typescript/module/src/babel/react-native-web.d.ts.map +1 -1
  97. package/dist/typescript/module/src/babel/react-native.d.ts.map +1 -1
  98. package/dist/typescript/module/src/compiler/compiler.d.ts +1 -5
  99. package/dist/typescript/module/src/compiler/compiler.d.ts.map +1 -1
  100. package/dist/typescript/module/src/compiler/compiler.types.d.ts +6 -0
  101. package/dist/typescript/module/src/compiler/compiler.types.d.ts.map +1 -1
  102. package/dist/typescript/module/src/compiler/selector-builder.d.ts.map +1 -1
  103. package/dist/typescript/module/src/compiler/stylesheet.d.ts +6 -8
  104. package/dist/typescript/module/src/compiler/stylesheet.d.ts.map +1 -1
  105. package/dist/typescript/module/src/jest/index.d.ts +2 -10
  106. package/dist/typescript/module/src/jest/index.d.ts.map +1 -1
  107. package/dist/typescript/module/src/metro/index.d.ts +4 -0
  108. package/dist/typescript/module/src/metro/index.d.ts.map +1 -1
  109. package/dist/typescript/module/src/metro/metro-transformer.d.ts +4 -1
  110. package/dist/typescript/module/src/metro/metro-transformer.d.ts.map +1 -1
  111. package/dist/typescript/module/src/metro/warnings.d.ts +13 -0
  112. package/dist/typescript/module/src/metro/warnings.d.ts.map +1 -0
  113. package/dist/typescript/module/src/native/api.d.ts.map +1 -1
  114. package/dist/typescript/module/src/native/react/useNativeCss.d.ts.map +1 -1
  115. package/dist/typescript/module/src/native/reactivity.d.ts +7 -0
  116. package/dist/typescript/module/src/native/reactivity.d.ts.map +1 -1
  117. package/dist/typescript/module/src/native-internal/root.d.ts +12 -0
  118. package/dist/typescript/module/src/native-internal/root.d.ts.map +1 -1
  119. package/dist/typescript/module/src/native-internal/variables.d.ts.map +1 -1
  120. package/package.json +3 -2
  121. package/src/babel/helpers.ts +8 -1
  122. package/src/babel/import-plugin.ts +16 -12
  123. package/src/babel/react-native-web.ts +2 -3
  124. package/src/babel/react-native.ts +2 -3
  125. package/src/compiler/compiler.ts +19 -1
  126. package/src/compiler/compiler.types.ts +9 -0
  127. package/src/compiler/declarations.ts +1 -1
  128. package/src/compiler/selector-builder.ts +2 -1
  129. package/src/compiler/stylesheet.ts +17 -10
  130. package/src/metro/index.ts +5 -0
  131. package/src/metro/metro-transformer.ts +19 -4
  132. package/src/metro/warnings.ts +187 -0
  133. package/src/native/api.tsx +2 -3
  134. package/src/native/react/useNativeCss.ts +17 -2
  135. package/src/native/reactivity.ts +35 -1
  136. package/src/native-internal/root.ts +40 -13
  137. package/src/native-internal/variables.tsx +6 -4
@@ -0,0 +1,187 @@
1
+ import { relative } from "path";
2
+
3
+ import type { CompilerWarnings } from "../compiler/compiler.types";
4
+
5
+ /** "summary" prints one capped block per CSS file, "verbose" lists every entry, "none" prints nothing */
6
+ export type WarningLevel = "none" | "summary" | "verbose";
7
+
8
+ const SUMMARY_ENTRY_LIMIT = 10;
9
+ const SUMMARY_VALUE_LIMIT = 5;
10
+ const SUMMARY_VALUE_LENGTH_LIMIT = 60;
11
+
12
+ const PREFIX = "react-native-css";
13
+
14
+ // Metro re-transforms a CSS file on every rebuild, so a file's block prints again only when its warnings change
15
+ const lastReportedByFile = new Map<string, string>();
16
+
17
+ // Metro forwards each transform worker's stderr to the bundler's terminal, and a warning never fails the build
18
+ export function reportCompilerWarnings(
19
+ warnings: CompilerWarnings,
20
+ options: {
21
+ filename: string;
22
+ projectRoot: string;
23
+ level?: WarningLevel | undefined;
24
+ },
25
+ ): void {
26
+ const { filename, projectRoot, level = "summary" } = options;
27
+
28
+ if (level === "none") {
29
+ return;
30
+ }
31
+
32
+ const message = formatCompilerWarnings(warnings, {
33
+ displayPath: toDisplayPath(filename, projectRoot),
34
+ verbose: level === "verbose",
35
+ });
36
+
37
+ if (message === undefined) {
38
+ lastReportedByFile.delete(filename);
39
+ return;
40
+ }
41
+
42
+ if (lastReportedByFile.get(filename) === message) {
43
+ return;
44
+ }
45
+
46
+ lastReportedByFile.set(filename, message);
47
+
48
+ console.warn(message);
49
+ }
50
+
51
+ // Plain text: Metro's transform workers write to a pipe, where colour would never render
52
+ export function formatCompilerWarnings(
53
+ warnings: CompilerWarnings,
54
+ options: { displayPath: string; verbose?: boolean | undefined },
55
+ ): string | undefined {
56
+ const { displayPath, verbose = false } = options;
57
+
58
+ const droppedCount =
59
+ (warnings.properties?.length ?? 0) +
60
+ (warnings.functions?.length ?? 0) +
61
+ Object.values(warnings.values ?? {}).reduce(
62
+ (total, entries) => total + entries.length,
63
+ 0,
64
+ );
65
+
66
+ // A syntax warning sends the reader to their stylesheet rather than to what React Native lacks, so it is counted apart
67
+ const syntaxCount = warnings.syntax?.length ?? 0;
68
+
69
+ if (droppedCount === 0 && syntaxCount === 0) {
70
+ return undefined;
71
+ }
72
+
73
+ const properties = limit(unique(warnings.properties), verbose);
74
+ const functions = limit(unique(warnings.functions), verbose);
75
+ const rendered = renderValues(warnings.values, verbose);
76
+ const values = limit(rendered.entries, verbose);
77
+ const syntax = limit(unique(warnings.syntax), verbose);
78
+
79
+ const claims: string[] = [];
80
+ if (droppedCount > 0) {
81
+ claims.push(
82
+ `${droppedCount} ${pluralize(droppedCount, "declaration")} dropped, no React Native equivalent`,
83
+ );
84
+ }
85
+ if (syntaxCount > 0) {
86
+ claims.push(`${syntaxCount} syntax ${pluralize(syntaxCount, "warning")}`);
87
+ }
88
+
89
+ const lines = [`${PREFIX}: ${displayPath} - ${claims.join("; ")}`];
90
+
91
+ if (syntax.shown.length > 0) {
92
+ lines.push(` syntax: ${syntax.shown.join("; ")}${suffix(syntax.hidden)}`);
93
+ }
94
+
95
+ if (properties.shown.length > 0) {
96
+ lines.push(
97
+ ` properties: ${properties.shown.join(", ")}${suffix(properties.hidden)}`,
98
+ );
99
+ }
100
+
101
+ if (values.shown.length > 0) {
102
+ lines.push(` values: ${values.shown.join("; ")}${suffix(values.hidden)}`);
103
+ }
104
+
105
+ if (functions.shown.length > 0) {
106
+ lines.push(
107
+ ` functions: ${functions.shown.join(", ")}${suffix(functions.hidden)}`,
108
+ );
109
+ }
110
+
111
+ if (
112
+ properties.hidden +
113
+ values.hidden +
114
+ functions.hidden +
115
+ rendered.hidden +
116
+ syntax.hidden >
117
+ 0
118
+ ) {
119
+ lines.push(
120
+ ` Set reactNativeCSS.warnings to "verbose" for the full list, or "none" to silence this.`,
121
+ );
122
+ }
123
+
124
+ return lines.join("\n");
125
+ }
126
+
127
+ function toDisplayPath(filename: string, projectRoot: string): string {
128
+ const relativePath = relative(projectRoot, filename);
129
+
130
+ return relativePath === "" || relativePath.startsWith("..")
131
+ ? filename
132
+ : relativePath;
133
+ }
134
+
135
+ function renderValues(
136
+ values: Record<string, string[]> | undefined,
137
+ verbose: boolean,
138
+ ): { entries: string[]; hidden: number } {
139
+ let hidden = 0;
140
+ const entries: string[] = [];
141
+ const recordedByProperty = values ?? {};
142
+
143
+ for (const property of Object.keys(recordedByProperty).sort()) {
144
+ const distinct = unique(recordedByProperty[property]);
145
+ const shown = verbose ? distinct : distinct.slice(0, SUMMARY_VALUE_LIMIT);
146
+ hidden += distinct.length - shown.length;
147
+
148
+ const rendered = shown.map((value) => truncate(value, verbose));
149
+
150
+ entries.push(
151
+ `${property}: ${rendered.join(", ")}${suffix(distinct.length - shown.length)}`,
152
+ );
153
+ }
154
+
155
+ return { entries, hidden };
156
+ }
157
+
158
+ function limit<T>(entries: T[], verbose: boolean) {
159
+ if (verbose || entries.length <= SUMMARY_ENTRY_LIMIT) {
160
+ return { shown: entries, hidden: 0 };
161
+ }
162
+
163
+ return {
164
+ shown: entries.slice(0, SUMMARY_ENTRY_LIMIT),
165
+ hidden: entries.length - SUMMARY_ENTRY_LIMIT,
166
+ };
167
+ }
168
+
169
+ function suffix(hidden: number): string {
170
+ return hidden > 0 ? ` (+${hidden} more)` : "";
171
+ }
172
+
173
+ // Code-unit order rather than localeCompare, whose collation varies with the ICU build
174
+ function unique(entries: string[] | undefined): string[] {
175
+ return entries ? [...new Set(entries)].sort() : [];
176
+ }
177
+
178
+ // An unresolved calc() is recorded as its whole lightningcss node, hundreds of characters long
179
+ function truncate(value: string, verbose: boolean): string {
180
+ return verbose || value.length <= SUMMARY_VALUE_LENGTH_LIMIT
181
+ ? value
182
+ : `${value.slice(0, SUMMARY_VALUE_LENGTH_LIMIT)}...`;
183
+ }
184
+
185
+ function pluralize(count: number, noun: string): string {
186
+ return count === 1 ? noun : `${noun}s`;
187
+ }
@@ -18,6 +18,7 @@ import { usePassthrough } from "./react/usePassthrough";
18
18
  import {
19
19
  cleanupEffect,
20
20
  colorScheme as colorSchemeObs,
21
+ toVariableRecord,
21
22
  VAR_SYMBOL,
22
23
  type Effect,
23
24
  type Getter,
@@ -123,8 +124,6 @@ export function useNativeVariable(name: string) {
123
124
  export function vars(variables: Record<string, StyleDescriptor>): ViewStyle {
124
125
  return Object.assign(
125
126
  { [VAR_SYMBOL]: "inline" },
126
- Object.fromEntries(
127
- Object.entries(variables).map(([k, v]) => [k.replace(/^--/, ""), v]),
128
- ),
127
+ toVariableRecord(variables),
129
128
  ) as ViewStyle;
130
129
  }
@@ -4,6 +4,7 @@ import {
4
4
  Fragment,
5
5
  useContext,
6
6
  useEffect,
7
+ useRef,
7
8
  useState,
8
9
  type ComponentType,
9
10
  } from "react";
@@ -16,6 +17,7 @@ import { testGuards, type RenderGuard } from "../conditions/guards";
16
17
  import {
17
18
  cleanupEffect,
18
19
  ContainerContext,
20
+ hasChangedDependencies,
19
21
  type ContainerContextValue,
20
22
  type Effect,
21
23
  type Getter,
@@ -113,12 +115,25 @@ export function useNativeCss(
113
115
  return initialState;
114
116
  });
115
117
 
118
+ // Distinguishes a fresh mount from an effect replay (Activity, StrictMode)
119
+ const hasCommittedRef = useRef(false);
120
+
116
121
  useEffect(() => {
117
122
  // Reconnect subscriptions after React replays an effect setup.
118
123
  if (state.ruleEffect.observers.size === 0) {
119
- state.ruleEffect.run();
120
- state.styleEffect.run();
124
+ if (hasCommittedRef.current || hasChangedDependencies(state.ruleEffect)) {
125
+ // Replay, or conditions changed since the initializer: recalculate.
126
+ state.ruleEffect.run();
127
+ state.styleEffect.run();
128
+ } else {
129
+ // Fresh mount: resubscribe to the initializer's dependencies.
130
+ // styleEffect resubscribes itself during render.
131
+ for (const observable of state.ruleEffect.dependencies ?? []) {
132
+ observable.get(state.ruleEffect);
133
+ }
134
+ }
121
135
  }
136
+ hasCommittedRef.current = true;
122
137
  return () => {
123
138
  cleanupEffect(state.ruleEffect);
124
139
  cleanupEffect(state.styleEffect);
@@ -12,6 +12,10 @@ import type { StyleDescriptor } from "react-native-css/compiler";
12
12
  export type Effect = {
13
13
  observers: Set<Observable<any, any>>;
14
14
  run(): void;
15
+ /** Dependencies recorded by the last cleanupEffect() */
16
+ dependencies?: Observable<any, any>[];
17
+ /** Dependency values recorded by the last cleanupEffect() */
18
+ snapshots?: [Observable<any, any>, unknown][];
15
19
  };
16
20
 
17
21
  export type Observable<Value, Arg = Value> = {
@@ -130,13 +134,28 @@ export function observable<Value, Arg = Value>(
130
134
 
131
135
  export function cleanupEffect(effect: Effect) {
132
136
  if (!effect) return;
133
- const dependencies = Array.from(effect.observers);
137
+ const dependencies = (effect.dependencies = Array.from(effect.observers));
138
+ // Snapshot before detaching so computed observables return cached values
139
+ effect.snapshots = dependencies.map(
140
+ (observable) =>
141
+ [observable, observable.get()] as [Observable<any, any>, unknown],
142
+ );
134
143
  effect.observers.clear();
135
144
  for (const dep of dependencies) {
136
145
  dep.unsubscribe(effect);
137
146
  }
138
147
  }
139
148
 
149
+ /** Whether any of the effect's dependencies changed since cleanupEffect() */
150
+ export function hasChangedDependencies(effect: Effect): boolean {
151
+ const snapshots = effect.snapshots;
152
+ if (!snapshots) return false;
153
+ for (const [observable, value] of snapshots) {
154
+ if (!Object.is(observable.get(), value)) return true;
155
+ }
156
+ return false;
157
+ }
158
+
140
159
  /** Family Helpers ************************************************************/
141
160
 
142
161
  export function family<Key, Result = Key, Args extends any = void>(
@@ -198,6 +217,21 @@ export type VariableContextValue = Record<string, StyleDescriptor> & {
198
217
  [VAR_SYMBOL]: true;
199
218
  };
200
219
 
220
+ // Variable lookup is presence-keyed, so an entry with no value produces no key rather than one that stops the cascade
221
+ export function toVariableRecord(
222
+ variables: Record<string, StyleDescriptor>,
223
+ ): Record<string, StyleDescriptor> {
224
+ const record: Record<string, StyleDescriptor> = {};
225
+
226
+ for (const [name, value] of Object.entries(variables)) {
227
+ if (value !== undefined) {
228
+ record[name.replace(/^--/, "")] = value;
229
+ }
230
+ }
231
+
232
+ return record;
233
+ }
234
+
201
235
  /** Pseudo Classes ************************************************************/
202
236
 
203
237
  export const hoverFamily = weakFamily(() => observable(false));
@@ -29,16 +29,43 @@ const rootVariableFamily = () => {
29
29
  });
30
30
  };
31
31
 
32
- export const rootVariables = rootVariableFamily();
33
- export const universalVariables = rootVariableFamily();
34
-
35
- rootVariables("__rn-css-rem").set([[14]]);
36
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
37
- rootVariables("__rn-css-color").set([
38
- [
39
- Platform.OS === "ios"
40
- ? PlatformColor("label", "labelColor")
41
- : PlatformColor("?attr/textColorPrimary", "SystemBaseHighColor"),
42
- ],
43
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
- ] as any);
32
+ interface RootVariableRegistries {
33
+ root: ReturnType<typeof rootVariableFamily>;
34
+ universal: ReturnType<typeof rootVariableFamily>;
35
+ }
36
+
37
+ declare global {
38
+ var __react_native_css_root_variable_registries:
39
+ | RootVariableRegistries
40
+ | undefined;
41
+ }
42
+
43
+ // Seeded with the registries, so a copy that loads after the stylesheet inject keeps the project's rem
44
+ function createRootVariableRegistries(): RootVariableRegistries {
45
+ const registries: RootVariableRegistries = {
46
+ root: rootVariableFamily(),
47
+ universal: rootVariableFamily(),
48
+ };
49
+
50
+ registries.root("__rn-css-rem").set([[14]]);
51
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
52
+ registries.root("__rn-css-color").set([
53
+ [
54
+ Platform.OS === "ios"
55
+ ? PlatformColor("label", "labelColor")
56
+ : PlatformColor("?attr/textColorPrimary", "SystemBaseHighColor"),
57
+ ],
58
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
59
+ ] as any);
60
+
61
+ return registries;
62
+ }
63
+
64
+ // The exports map gives import and require different builds, and Metro resolves each per requesting module
65
+ globalThis.__react_native_css_root_variable_registries ??=
66
+ createRootVariableRegistries();
67
+
68
+ export const rootVariables =
69
+ globalThis.__react_native_css_root_variable_registries.root;
70
+ export const universalVariables =
71
+ globalThis.__react_native_css_root_variable_registries.universal;
@@ -7,7 +7,11 @@ import {
7
7
 
8
8
  import type { StyleDescriptor } from "react-native-css/compiler";
9
9
 
10
- import { VAR_SYMBOL, type VariableContextValue } from "../native/reactivity";
10
+ import {
11
+ toVariableRecord,
12
+ VAR_SYMBOL,
13
+ type VariableContextValue,
14
+ } from "../native/reactivity";
11
15
 
12
16
  globalThis.__react_native_css_variable_context ??=
13
17
  createContext<VariableContextValue>({
@@ -24,9 +28,7 @@ export function VariableContextProvider(
24
28
  const value: VariableContextValue = useMemo(
25
29
  () => ({
26
30
  ...inheritedVariables,
27
- ...Object.fromEntries(
28
- Object.entries(props.value).map(([k, v]) => [k.replace(/^--/, ""), v]),
29
- ),
31
+ ...toVariableRecord(props.value),
30
32
  [VAR_SYMBOL]: true,
31
33
  }),
32
34
  [inheritedVariables, props.value],