react-native-css 3.0.0 → 3.0.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.
Files changed (247) hide show
  1. package/dist/commonjs/compiler/declarations.js +51 -0
  2. package/dist/commonjs/compiler/declarations.js.map +1 -1
  3. package/dist/commonjs/compiler/lightningcss-loader.js +12 -2
  4. package/dist/commonjs/compiler/lightningcss-loader.js.map +1 -1
  5. package/dist/commonjs/compiler/supports.js +3 -1
  6. package/dist/commonjs/compiler/supports.js.map +1 -1
  7. package/dist/commonjs/components/ActivityIndicator.js +4 -4
  8. package/dist/commonjs/components/ActivityIndicator.js.map +1 -1
  9. package/dist/commonjs/components/Button.js +4 -4
  10. package/dist/commonjs/components/Button.js.map +1 -1
  11. package/dist/commonjs/components/FlatList.js +4 -4
  12. package/dist/commonjs/components/FlatList.js.map +1 -1
  13. package/dist/commonjs/components/Image.js +4 -4
  14. package/dist/commonjs/components/Image.js.map +1 -1
  15. package/dist/commonjs/components/ImageBackground.js +4 -4
  16. package/dist/commonjs/components/ImageBackground.js.map +1 -1
  17. package/dist/commonjs/components/KeyboardAvoidingView.js +4 -4
  18. package/dist/commonjs/components/KeyboardAvoidingView.js.map +1 -1
  19. package/dist/commonjs/components/Pressable.js +4 -4
  20. package/dist/commonjs/components/Pressable.js.map +1 -1
  21. package/dist/commonjs/components/ScrollView.js +4 -4
  22. package/dist/commonjs/components/ScrollView.js.map +1 -1
  23. package/dist/commonjs/components/Switch.js +4 -4
  24. package/dist/commonjs/components/Switch.js.map +1 -1
  25. package/dist/commonjs/components/Text.js +4 -4
  26. package/dist/commonjs/components/Text.js.map +1 -1
  27. package/dist/commonjs/components/TextInput.js +4 -4
  28. package/dist/commonjs/components/TextInput.js.map +1 -1
  29. package/dist/commonjs/components/TouchableHighlight.js +4 -4
  30. package/dist/commonjs/components/TouchableHighlight.js.map +1 -1
  31. package/dist/commonjs/components/TouchableOpacity.js +4 -4
  32. package/dist/commonjs/components/TouchableOpacity.js.map +1 -1
  33. package/dist/commonjs/components/TouchableWithoutFeedback.js +4 -4
  34. package/dist/commonjs/components/TouchableWithoutFeedback.js.map +1 -1
  35. package/dist/commonjs/components/View.js +4 -4
  36. package/dist/commonjs/components/View.js.map +1 -1
  37. package/dist/commonjs/components/VirtualizedList.js +4 -4
  38. package/dist/commonjs/components/VirtualizedList.js.map +1 -1
  39. package/dist/commonjs/components/copyComponentProperties.js +19 -0
  40. package/dist/commonjs/components/copyComponentProperties.js.map +1 -0
  41. package/dist/commonjs/components/index.cjs +3 -3
  42. package/dist/commonjs/components/index.cjs.map +1 -1
  43. package/dist/commonjs/metro/resolver.js +5 -3
  44. package/dist/commonjs/metro/resolver.js.map +1 -1
  45. package/dist/commonjs/native/api.js +5 -1
  46. package/dist/commonjs/native/api.js.map +1 -1
  47. package/dist/commonjs/native/react/useNativeCss.js +11 -5
  48. package/dist/commonjs/native/react/useNativeCss.js.map +1 -1
  49. package/dist/commonjs/native/styles/functions/color-mix.js +50 -0
  50. package/dist/commonjs/native/styles/functions/color-mix.js.map +1 -0
  51. package/dist/commonjs/native/styles/functions/index.js +11 -0
  52. package/dist/commonjs/native/styles/functions/index.js.map +1 -1
  53. package/dist/commonjs/native/styles/index.js +249 -19
  54. package/dist/commonjs/native/styles/index.js.map +1 -1
  55. package/dist/commonjs/web/api.js +5 -2
  56. package/dist/commonjs/web/api.js.map +1 -1
  57. package/dist/module/compiler/declarations.js +50 -0
  58. package/dist/module/compiler/declarations.js.map +1 -1
  59. package/dist/module/compiler/lightningcss-loader.js +12 -2
  60. package/dist/module/compiler/lightningcss-loader.js.map +1 -1
  61. package/dist/module/compiler/supports.js +3 -1
  62. package/dist/module/compiler/supports.js.map +1 -1
  63. package/dist/module/components/ActivityIndicator.js +3 -2
  64. package/dist/module/components/ActivityIndicator.js.map +1 -1
  65. package/dist/module/components/Button.js +3 -2
  66. package/dist/module/components/Button.js.map +1 -1
  67. package/dist/module/components/FlatList.js +3 -2
  68. package/dist/module/components/FlatList.js.map +1 -1
  69. package/dist/module/components/Image.js +3 -2
  70. package/dist/module/components/Image.js.map +1 -1
  71. package/dist/module/components/ImageBackground.js +3 -2
  72. package/dist/module/components/ImageBackground.js.map +1 -1
  73. package/dist/module/components/KeyboardAvoidingView.js +3 -2
  74. package/dist/module/components/KeyboardAvoidingView.js.map +1 -1
  75. package/dist/module/components/Pressable.js +3 -2
  76. package/dist/module/components/Pressable.js.map +1 -1
  77. package/dist/module/components/ScrollView.js +3 -2
  78. package/dist/module/components/ScrollView.js.map +1 -1
  79. package/dist/module/components/Switch.js +3 -2
  80. package/dist/module/components/Switch.js.map +1 -1
  81. package/dist/module/components/Text.js +3 -2
  82. package/dist/module/components/Text.js.map +1 -1
  83. package/dist/module/components/TextInput.js +3 -2
  84. package/dist/module/components/TextInput.js.map +1 -1
  85. package/dist/module/components/TouchableHighlight.js +3 -2
  86. package/dist/module/components/TouchableHighlight.js.map +1 -1
  87. package/dist/module/components/TouchableOpacity.js +3 -2
  88. package/dist/module/components/TouchableOpacity.js.map +1 -1
  89. package/dist/module/components/TouchableWithoutFeedback.js +3 -2
  90. package/dist/module/components/TouchableWithoutFeedback.js.map +1 -1
  91. package/dist/module/components/View.js +3 -2
  92. package/dist/module/components/View.js.map +1 -1
  93. package/dist/module/components/VirtualizedList.js +3 -2
  94. package/dist/module/components/VirtualizedList.js.map +1 -1
  95. package/dist/module/components/copyComponentProperties.js +15 -0
  96. package/dist/module/components/copyComponentProperties.js.map +1 -0
  97. package/dist/module/components/index.cjs +3 -3
  98. package/dist/module/components/index.cjs.map +1 -1
  99. package/dist/module/metro/resolver.js +5 -3
  100. package/dist/module/metro/resolver.js.map +1 -1
  101. package/dist/module/native/api.js +4 -1
  102. package/dist/module/native/api.js.map +1 -1
  103. package/dist/module/native/react/useNativeCss.js +11 -5
  104. package/dist/module/native/react/useNativeCss.js.map +1 -1
  105. package/dist/module/native/styles/functions/color-mix.js +45 -0
  106. package/dist/module/native/styles/functions/color-mix.js.map +1 -0
  107. package/dist/module/native/styles/functions/index.js +1 -0
  108. package/dist/module/native/styles/functions/index.js.map +1 -1
  109. package/dist/module/native/styles/index.js +250 -19
  110. package/dist/module/native/styles/index.js.map +1 -1
  111. package/dist/module/web/api.js +5 -2
  112. package/dist/module/web/api.js.map +1 -1
  113. package/dist/typescript/commonjs/.config/eslint.config.d.mts +1 -1
  114. package/dist/typescript/commonjs/example/src/App.d.ts.map +1 -1
  115. package/dist/typescript/commonjs/src/compiler/declarations.d.ts +1 -0
  116. package/dist/typescript/commonjs/src/compiler/declarations.d.ts.map +1 -1
  117. package/dist/typescript/commonjs/src/compiler/lightningcss-loader.d.ts.map +1 -1
  118. package/dist/typescript/commonjs/src/components/ActivityIndicator.d.ts +2 -4
  119. package/dist/typescript/commonjs/src/components/ActivityIndicator.d.ts.map +1 -1
  120. package/dist/typescript/commonjs/src/components/Button.d.ts +2 -4
  121. package/dist/typescript/commonjs/src/components/Button.d.ts.map +1 -1
  122. package/dist/typescript/commonjs/src/components/FlatList.d.ts +2 -2
  123. package/dist/typescript/commonjs/src/components/FlatList.d.ts.map +1 -1
  124. package/dist/typescript/commonjs/src/components/Image.d.ts +2 -4
  125. package/dist/typescript/commonjs/src/components/Image.d.ts.map +1 -1
  126. package/dist/typescript/commonjs/src/components/ImageBackground.d.ts +2 -4
  127. package/dist/typescript/commonjs/src/components/ImageBackground.d.ts.map +1 -1
  128. package/dist/typescript/commonjs/src/components/KeyboardAvoidingView.d.ts +2 -4
  129. package/dist/typescript/commonjs/src/components/KeyboardAvoidingView.d.ts.map +1 -1
  130. package/dist/typescript/commonjs/src/components/Pressable.d.ts +2 -4
  131. package/dist/typescript/commonjs/src/components/Pressable.d.ts.map +1 -1
  132. package/dist/typescript/commonjs/src/components/ScrollView.d.ts +2 -4
  133. package/dist/typescript/commonjs/src/components/ScrollView.d.ts.map +1 -1
  134. package/dist/typescript/commonjs/src/components/Switch.d.ts +2 -6
  135. package/dist/typescript/commonjs/src/components/Switch.d.ts.map +1 -1
  136. package/dist/typescript/commonjs/src/components/Text.d.ts +2 -6
  137. package/dist/typescript/commonjs/src/components/Text.d.ts.map +1 -1
  138. package/dist/typescript/commonjs/src/components/TextInput.d.ts +2 -4
  139. package/dist/typescript/commonjs/src/components/TextInput.d.ts.map +1 -1
  140. package/dist/typescript/commonjs/src/components/TouchableHighlight.d.ts +2 -4
  141. package/dist/typescript/commonjs/src/components/TouchableHighlight.d.ts.map +1 -1
  142. package/dist/typescript/commonjs/src/components/TouchableOpacity.d.ts +2 -4
  143. package/dist/typescript/commonjs/src/components/TouchableOpacity.d.ts.map +1 -1
  144. package/dist/typescript/commonjs/src/components/TouchableWithoutFeedback.d.ts +2 -4
  145. package/dist/typescript/commonjs/src/components/TouchableWithoutFeedback.d.ts.map +1 -1
  146. package/dist/typescript/commonjs/src/components/View.d.ts +2 -6
  147. package/dist/typescript/commonjs/src/components/View.d.ts.map +1 -1
  148. package/dist/typescript/commonjs/src/components/VirtualizedList.d.ts +2 -2
  149. package/dist/typescript/commonjs/src/components/VirtualizedList.d.ts.map +1 -1
  150. package/dist/typescript/commonjs/src/components/copyComponentProperties.d.ts +5 -0
  151. package/dist/typescript/commonjs/src/components/copyComponentProperties.d.ts.map +1 -0
  152. package/dist/typescript/commonjs/src/metro/resolver.d.ts.map +1 -1
  153. package/dist/typescript/commonjs/src/native/api.d.ts +1 -1
  154. package/dist/typescript/commonjs/src/native/api.d.ts.map +1 -1
  155. package/dist/typescript/commonjs/src/native/react/useNativeCss.d.ts.map +1 -1
  156. package/dist/typescript/commonjs/src/native/styles/functions/color-mix.d.ts +3 -0
  157. package/dist/typescript/commonjs/src/native/styles/functions/color-mix.d.ts.map +1 -0
  158. package/dist/typescript/commonjs/src/native/styles/functions/index.d.ts +1 -0
  159. package/dist/typescript/commonjs/src/native/styles/functions/index.d.ts.map +1 -1
  160. package/dist/typescript/commonjs/src/native/styles/index.d.ts.map +1 -1
  161. package/dist/typescript/commonjs/src/utilities/dot-notation.types.d.ts +1 -1
  162. package/dist/typescript/commonjs/src/utilities/dot-notation.types.d.ts.map +1 -1
  163. package/dist/typescript/commonjs/src/web/api.d.ts +2 -2
  164. package/dist/typescript/commonjs/src/web/api.d.ts.map +1 -1
  165. package/dist/typescript/module/.config/eslint.config.d.mts +1 -1
  166. package/dist/typescript/module/example/src/App.d.ts.map +1 -1
  167. package/dist/typescript/module/src/compiler/declarations.d.ts +1 -0
  168. package/dist/typescript/module/src/compiler/declarations.d.ts.map +1 -1
  169. package/dist/typescript/module/src/compiler/lightningcss-loader.d.ts.map +1 -1
  170. package/dist/typescript/module/src/components/ActivityIndicator.d.ts +2 -4
  171. package/dist/typescript/module/src/components/ActivityIndicator.d.ts.map +1 -1
  172. package/dist/typescript/module/src/components/Button.d.ts +2 -4
  173. package/dist/typescript/module/src/components/Button.d.ts.map +1 -1
  174. package/dist/typescript/module/src/components/FlatList.d.ts +2 -2
  175. package/dist/typescript/module/src/components/FlatList.d.ts.map +1 -1
  176. package/dist/typescript/module/src/components/Image.d.ts +2 -4
  177. package/dist/typescript/module/src/components/Image.d.ts.map +1 -1
  178. package/dist/typescript/module/src/components/ImageBackground.d.ts +2 -4
  179. package/dist/typescript/module/src/components/ImageBackground.d.ts.map +1 -1
  180. package/dist/typescript/module/src/components/KeyboardAvoidingView.d.ts +2 -4
  181. package/dist/typescript/module/src/components/KeyboardAvoidingView.d.ts.map +1 -1
  182. package/dist/typescript/module/src/components/Pressable.d.ts +2 -4
  183. package/dist/typescript/module/src/components/Pressable.d.ts.map +1 -1
  184. package/dist/typescript/module/src/components/ScrollView.d.ts +2 -4
  185. package/dist/typescript/module/src/components/ScrollView.d.ts.map +1 -1
  186. package/dist/typescript/module/src/components/Switch.d.ts +2 -6
  187. package/dist/typescript/module/src/components/Switch.d.ts.map +1 -1
  188. package/dist/typescript/module/src/components/Text.d.ts +2 -6
  189. package/dist/typescript/module/src/components/Text.d.ts.map +1 -1
  190. package/dist/typescript/module/src/components/TextInput.d.ts +2 -4
  191. package/dist/typescript/module/src/components/TextInput.d.ts.map +1 -1
  192. package/dist/typescript/module/src/components/TouchableHighlight.d.ts +2 -4
  193. package/dist/typescript/module/src/components/TouchableHighlight.d.ts.map +1 -1
  194. package/dist/typescript/module/src/components/TouchableOpacity.d.ts +2 -4
  195. package/dist/typescript/module/src/components/TouchableOpacity.d.ts.map +1 -1
  196. package/dist/typescript/module/src/components/TouchableWithoutFeedback.d.ts +2 -4
  197. package/dist/typescript/module/src/components/TouchableWithoutFeedback.d.ts.map +1 -1
  198. package/dist/typescript/module/src/components/View.d.ts +2 -6
  199. package/dist/typescript/module/src/components/View.d.ts.map +1 -1
  200. package/dist/typescript/module/src/components/VirtualizedList.d.ts +2 -2
  201. package/dist/typescript/module/src/components/VirtualizedList.d.ts.map +1 -1
  202. package/dist/typescript/module/src/components/copyComponentProperties.d.ts +5 -0
  203. package/dist/typescript/module/src/components/copyComponentProperties.d.ts.map +1 -0
  204. package/dist/typescript/module/src/metro/resolver.d.ts.map +1 -1
  205. package/dist/typescript/module/src/native/api.d.ts +1 -1
  206. package/dist/typescript/module/src/native/api.d.ts.map +1 -1
  207. package/dist/typescript/module/src/native/react/useNativeCss.d.ts.map +1 -1
  208. package/dist/typescript/module/src/native/styles/functions/color-mix.d.ts +3 -0
  209. package/dist/typescript/module/src/native/styles/functions/color-mix.d.ts.map +1 -0
  210. package/dist/typescript/module/src/native/styles/functions/index.d.ts +1 -0
  211. package/dist/typescript/module/src/native/styles/functions/index.d.ts.map +1 -1
  212. package/dist/typescript/module/src/native/styles/index.d.ts.map +1 -1
  213. package/dist/typescript/module/src/utilities/dot-notation.types.d.ts +1 -1
  214. package/dist/typescript/module/src/utilities/dot-notation.types.d.ts.map +1 -1
  215. package/dist/typescript/module/src/web/api.d.ts +2 -2
  216. package/dist/typescript/module/src/web/api.d.ts.map +1 -1
  217. package/package.json +4 -3
  218. package/src/compiler/declarations.ts +96 -0
  219. package/src/compiler/lightningcss-loader.ts +20 -1
  220. package/src/compiler/supports.ts +2 -0
  221. package/src/components/ActivityIndicator.tsx +8 -5
  222. package/src/components/Button.tsx +8 -3
  223. package/src/components/FlatList.tsx +13 -4
  224. package/src/components/Image.tsx +8 -3
  225. package/src/components/ImageBackground.tsx +8 -5
  226. package/src/components/KeyboardAvoidingView.tsx +8 -5
  227. package/src/components/Pressable.tsx +8 -3
  228. package/src/components/ScrollView.tsx +8 -5
  229. package/src/components/Switch.tsx +8 -3
  230. package/src/components/Text.tsx +8 -3
  231. package/src/components/TextInput.tsx +8 -3
  232. package/src/components/TouchableHighlight.tsx +8 -5
  233. package/src/components/TouchableOpacity.tsx +8 -5
  234. package/src/components/TouchableWithoutFeedback.tsx +8 -5
  235. package/src/components/View.tsx +8 -3
  236. package/src/components/VirtualizedList.tsx +17 -5
  237. package/src/components/copyComponentProperties.ts +21 -0
  238. package/src/components/index.cts +3 -3
  239. package/src/metro/resolver.ts +10 -3
  240. package/src/native/api.tsx +6 -2
  241. package/src/native/react/useNativeCss.ts +13 -6
  242. package/src/native/styles/functions/color-mix.ts +68 -0
  243. package/src/native/styles/functions/index.ts +1 -0
  244. package/src/native/styles/index.ts +302 -26
  245. package/src/utilities/dot-notation.types.ts +10 -3
  246. package/src/web/api.tsx +9 -4
  247. package/types.d.ts +3 -0
@@ -17,6 +17,149 @@ import {
17
17
  } from "../reactivity";
18
18
  import { calculateProps } from "./calculate-props";
19
19
 
20
+ /**
21
+ * Checks if the left style object has any properties that are not present in the right style object.
22
+ * This is used to determine if styles need to be preserved in an array or if right can completely override left.
23
+ *
24
+ * Note: This intentionally only checks one direction (left → right). We don't need to check if right has
25
+ * properties that left doesn't have, because right will always be applied/merged. The question we're
26
+ * answering is: "Does left have any properties that would be lost if we just used right?" If yes, we
27
+ * create a style array [left, right] to preserve both. If no, right can safely replace left entirely.
28
+ *
29
+ * @param left - The left style object to check
30
+ * @param right - The right style object to compare against
31
+ * @returns true if left has at least one property key that doesn't exist in right, false otherwise
32
+ *
33
+ * @example
34
+ * hasNonOverlappingProperties({color: 'red', fontSize: 12}, {color: 'blue'}) // true - fontSize is not in right
35
+ * hasNonOverlappingProperties({color: 'red'}, {color: 'blue', fontSize: 12}) // false - all left keys exist in right
36
+ */
37
+ function hasNonOverlappingProperties(
38
+ left: Record<string, any>,
39
+ right: Record<string, any>,
40
+ ): boolean {
41
+ // Null safety check
42
+ if (!left || !right) {
43
+ return false;
44
+ }
45
+
46
+ // Only check own properties to avoid prototype pollution
47
+ for (const key in left) {
48
+ if (Object.prototype.hasOwnProperty.call(left, key)) {
49
+ if (!Object.prototype.hasOwnProperty.call(right, key)) {
50
+ return true;
51
+ }
52
+ }
53
+ }
54
+ return false;
55
+ }
56
+
57
+ /**
58
+ * Flattens a style array into a single object when possible, with rightmost values taking precedence.
59
+ * Returns the original array if it contains any non-plain objects, arrays, or CSS variable objects.
60
+ *
61
+ * Note: This function assumes the input array has already been filtered (e.g., by filterCssVariables),
62
+ * so empty arrays should not reach this function. If they do, they will be treated as non-flattenable.
63
+ *
64
+ * @param styleArray - The style array to potentially flatten
65
+ * @returns A single merged object if all items are plain objects, otherwise the original array
66
+ */
67
+ function flattenStyleArray(styleArray: any[]): any {
68
+ // Check if we can flatten to a single object (all items are plain objects)
69
+ for (const item of styleArray) {
70
+ // Use explicit null check instead of !item to allow falsy values like 0 or false
71
+ if (
72
+ item == null ||
73
+ typeof item !== "object" ||
74
+ Array.isArray(item) ||
75
+ Object.prototype.hasOwnProperty.call(item, VAR_SYMBOL)
76
+ ) {
77
+ return styleArray;
78
+ }
79
+ }
80
+
81
+ // Use reduce to avoid spread operator performance issues with large arrays
82
+ return styleArray.reduce((acc, item) => Object.assign(acc, item), {});
83
+ }
84
+
85
+ /**
86
+ * Recursively filters out CSS variable objects (with VAR_SYMBOL) from style values.
87
+ * This prevents CSS variable runtime objects from leaking into React Native component props.
88
+ *
89
+ * @param value - The value to filter (can be any type: object, array, primitive, etc.)
90
+ * @param depth - Internal recursion depth counter to prevent stack overflow (max 100)
91
+ * @returns The filtered value with CSS variables removed, or `undefined` if the entire value
92
+ * should be filtered out (e.g., empty arrays, objects with only VAR_SYMBOL properties)
93
+ *
94
+ * Filtering behavior:
95
+ * - Objects with VAR_SYMBOL property: returns `undefined` (completely filtered)
96
+ * - Arrays: filters out VAR_SYMBOL objects, returns `undefined` if empty after filtering
97
+ * - Objects: recursively filters properties, returns `undefined` if no properties remain
98
+ * - Primitives (null, undefined, numbers, strings, booleans): returned as-is
99
+ * - Symbol properties: intentionally filtered out for React Native compatibility
100
+ *
101
+ * @example
102
+ * filterCssVariables({fontSize: 16, color: {[VAR_SYMBOL]: true}}) // {fontSize: 16}
103
+ * filterCssVariables([{margin: 10}, {[VAR_SYMBOL]: true}]) // [{margin: 10}]
104
+ * filterCssVariables({color: {[VAR_SYMBOL]: true}}) // undefined (all props filtered)
105
+ */
106
+ function filterCssVariables(value: any, depth = 0): any | undefined {
107
+ // Prevent stack overflow on deeply nested structures
108
+ if (depth > 100) {
109
+ return value;
110
+ }
111
+
112
+ if (value === null || value === undefined) {
113
+ return value;
114
+ }
115
+
116
+ if (Array.isArray(value)) {
117
+ // Single-pass filter with map operation
118
+ const filtered: any[] = [];
119
+
120
+ for (const item of value) {
121
+ const filteredItem = filterCssVariables(item, depth + 1);
122
+ if (
123
+ filteredItem !== undefined &&
124
+ !(
125
+ typeof filteredItem === "object" &&
126
+ filteredItem !== null &&
127
+ Object.prototype.hasOwnProperty.call(filteredItem, VAR_SYMBOL)
128
+ )
129
+ ) {
130
+ filtered.push(filteredItem);
131
+ }
132
+ }
133
+
134
+ return filtered.length > 0 ? filtered : undefined;
135
+ }
136
+
137
+ if (typeof value === "object") {
138
+ // If the object itself has VAR_SYMBOL, filter it out (check own property only)
139
+ if (Object.prototype.hasOwnProperty.call(value, VAR_SYMBOL)) {
140
+ return undefined;
141
+ }
142
+
143
+ // Otherwise, filter VAR_SYMBOL properties from nested objects
144
+ const filtered: Record<string, any> = {};
145
+ let hasProperties = false;
146
+
147
+ // Use Object.keys to only iterate own string properties (not inherited, not Symbols)
148
+ // This intentionally filters out Symbol properties for React Native compatibility
149
+ for (const key of Object.keys(value)) {
150
+ const filteredValue = filterCssVariables(value[key], depth + 1);
151
+ if (filteredValue !== undefined) {
152
+ filtered[key] = filteredValue;
153
+ hasProperties = true;
154
+ }
155
+ }
156
+
157
+ return hasProperties ? filtered : undefined;
158
+ }
159
+
160
+ return value;
161
+ }
162
+
20
163
  export const stylesFamily = family(
21
164
  (
22
165
  hash: string,
@@ -49,10 +192,19 @@ export function getStyledProps(
49
192
  const styledProps = state.stylesObs?.get(state.styleEffect);
50
193
 
51
194
  for (const config of state.configs) {
52
- result = deepMergeConfig(config, styledProps?.normal, inline, true);
195
+ result = deepMergeConfig(
196
+ config,
197
+ nativeStyleMapping(config, styledProps?.normal),
198
+ inline,
199
+ true,
200
+ );
53
201
 
54
202
  if (styledProps?.important) {
55
- result = deepMergeConfig(config, result, styledProps.important);
203
+ result = deepMergeConfig(
204
+ config,
205
+ result,
206
+ nativeStyleMapping(config, styledProps.important),
207
+ );
56
208
  }
57
209
 
58
210
  // Apply the handlers
@@ -122,11 +274,96 @@ function deepMergeConfig(
122
274
  right: Record<string, any> | undefined | null,
123
275
  rightIsInline = false,
124
276
  ) {
125
- if (!config.target || !right) {
277
+ if (!right) {
126
278
  return { ...left };
127
279
  }
128
280
 
129
- let result = Object.assign({}, left, right);
281
+ // Handle style merging to support both className and inline style props
282
+ let result: Record<string, any>;
283
+ if (config.target) {
284
+ if (
285
+ Array.isArray(config.target) &&
286
+ config.target.length === 1 &&
287
+ config.target[0] === "style"
288
+ ) {
289
+ // Special handling for style target when we have inline styles
290
+ result = { ...left, ...right };
291
+
292
+ // Handle null/undefined inline styles
293
+ if (right?.style === null || right?.style === undefined) {
294
+ if (left?.style) {
295
+ result.style = left.style;
296
+ }
297
+ } else if (rightIsInline && right?.style) {
298
+ // Filter inline styles if rightIsInline is true
299
+ const filteredRightStyle = filterCssVariables(right.style);
300
+
301
+ if (left?.style) {
302
+ if (!filteredRightStyle) {
303
+ // All inline styles were CSS variables, only use left
304
+ result.style = left.style;
305
+ } else {
306
+ const leftStyle = left.style;
307
+
308
+ // For arrays or objects, check if we need to create a style array
309
+ const leftIsObject =
310
+ typeof leftStyle === "object" && !Array.isArray(leftStyle);
311
+ const rightIsObject =
312
+ typeof filteredRightStyle === "object" &&
313
+ !Array.isArray(filteredRightStyle);
314
+
315
+ if (leftIsObject && rightIsObject) {
316
+ if (hasNonOverlappingProperties(leftStyle, filteredRightStyle)) {
317
+ result.style = [leftStyle, filteredRightStyle];
318
+ } else {
319
+ // All left properties are in right, right overrides
320
+ result.style = filteredRightStyle;
321
+ }
322
+ } else {
323
+ // One or both are arrays, merge them
324
+ result.style = [leftStyle, filteredRightStyle];
325
+ }
326
+ }
327
+ } else {
328
+ // No left style, just use filtered right
329
+ if (filteredRightStyle) {
330
+ result.style = filteredRightStyle;
331
+ } else {
332
+ // All filtered out, remove style prop
333
+ delete result.style;
334
+ }
335
+ }
336
+ } else if (!rightIsInline && right?.style) {
337
+ // Merging non-inline styles (e.g., important styles)
338
+ if (left?.style) {
339
+ // If left.style is an array, append right.style
340
+ if (Array.isArray(left.style)) {
341
+ const combined = [...left.style, right.style];
342
+ result.style = flattenStyleArray(combined);
343
+ } else if (
344
+ typeof left.style === "object" &&
345
+ typeof right.style === "object"
346
+ ) {
347
+ // Both are objects, check for overlaps
348
+ if (hasNonOverlappingProperties(left.style, right.style)) {
349
+ result.style = flattenStyleArray([left.style, right.style]);
350
+ } else {
351
+ // All left properties are overridden by right
352
+ result.style = right.style;
353
+ }
354
+ } else {
355
+ // One or both are arrays/mixed types
356
+ const combined = [left.style, right.style];
357
+ result.style = flattenStyleArray(combined);
358
+ }
359
+ }
360
+ }
361
+ } else {
362
+ result = Object.assign({}, left, right);
363
+ }
364
+ } else {
365
+ result = { ...left };
366
+ }
130
367
 
131
368
  if (
132
369
  right &&
@@ -140,7 +377,7 @@ function deepMergeConfig(
140
377
  /**
141
378
  * If target is a path, deep merge until we get to the last key
142
379
  */
143
- if (Array.isArray(config.target) && config.target.length > 1) {
380
+ if (Array.isArray(config.target)) {
144
381
  for (let i = 0; i < config.target.length - 1; i++) {
145
382
  const key = config.target[i];
146
383
 
@@ -159,34 +396,17 @@ function deepMergeConfig(
159
396
  return result;
160
397
  }
161
398
 
162
- const target = Array.isArray(config.target)
163
- ? config.target[0]
164
- : config.target;
399
+ const target = config.target;
165
400
 
166
- if (target === undefined) {
401
+ if (target === undefined || target === false) {
167
402
  return result;
168
403
  }
169
404
 
170
405
  let rightValue = right?.[target];
171
406
 
172
407
  // Strip any inline variables from the target
173
- if (rightIsInline && rightValue) {
174
- if (Array.isArray(rightValue)) {
175
- rightValue = rightValue.filter((v) => {
176
- return typeof v !== "object" || !(v && VAR_SYMBOL in v);
177
- });
178
-
179
- if (rightValue.length === 0) {
180
- rightValue = undefined;
181
- }
182
- } else if (
183
- typeof rightValue === "object" &&
184
- rightValue &&
185
- VAR_SYMBOL in rightValue
186
- ) {
187
- rightValue = undefined;
188
- delete result[target][VAR_SYMBOL];
189
- }
408
+ if (rightIsInline && rightValue !== undefined) {
409
+ rightValue = filterCssVariables(rightValue);
190
410
  }
191
411
 
192
412
  if (rightValue !== undefined) {
@@ -196,3 +416,59 @@ function deepMergeConfig(
196
416
 
197
417
  return result;
198
418
  }
419
+
420
+ function nativeStyleMapping(
421
+ config: Config,
422
+ props: Record<string, any> | undefined,
423
+ ) {
424
+ if (!config.nativeStyleMapping || !props) {
425
+ return props;
426
+ }
427
+
428
+ let source: Record<string, any> | undefined;
429
+
430
+ if (typeof config.target === "string") {
431
+ source = props[config.target];
432
+ } else if (config.target === false) {
433
+ source = props["style"];
434
+ } else {
435
+ const tokens = [...config.target];
436
+ const lastToken = tokens.pop()!;
437
+
438
+ source = props;
439
+ for (const token of tokens) {
440
+ source = source[token];
441
+ if (!source) {
442
+ return props;
443
+ }
444
+ }
445
+
446
+ source = source[lastToken];
447
+ }
448
+
449
+ if (!source) {
450
+ return props;
451
+ }
452
+
453
+ for (const [key, path] of Object.entries(config.nativeStyleMapping)) {
454
+ const styleValue = source[key];
455
+
456
+ delete source[key];
457
+
458
+ if (styleValue === undefined) {
459
+ continue;
460
+ }
461
+
462
+ let target = props;
463
+ const tokens = path.split(".");
464
+ const lastToken = tokens.pop();
465
+ for (const token of tokens) {
466
+ target[token] ??= {};
467
+ target = target[token];
468
+ }
469
+
470
+ target[lastToken!] = styleValue;
471
+ }
472
+
473
+ return props;
474
+ }
@@ -29,9 +29,16 @@ export type StyleProp<T> =
29
29
  // ---------- Type Helpers ----------
30
30
 
31
31
  // Unwrap nested arrays (from RecursiveArray)
32
- type UnwrapRecursiveArray<T> = T extends (infer I)[]
33
- ? UnwrapRecursiveArray<I>
34
- : T;
32
+ type UnwrapRecursiveArray<
33
+ T,
34
+ Depth extends unknown[] = [],
35
+ MaxDepth extends number = 10
36
+ > = Depth["length"] extends MaxDepth
37
+ ? T
38
+ : T extends (infer I)[]
39
+ ? UnwrapRecursiveArray<I, [...Depth, unknown], MaxDepth>
40
+ : T;
41
+
35
42
 
36
43
  // Remove null, false, undefined, etc.
37
44
  type RemoveFalsy<T> = Exclude<T, Falsy>;
package/src/web/api.tsx CHANGED
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  createElement,
3
3
  useMemo,
4
- type ComponentProps,
4
+ type ComponentPropsWithRef,
5
+ type ComponentType,
5
6
  type PropsWithChildren,
6
7
  } from "react";
7
8
  import { Appearance } from "react-native";
@@ -17,15 +18,19 @@ import type {
17
18
  import type { ReactComponent } from "../runtime.types";
18
19
  import { assignStyle } from "./assign-style";
19
20
 
21
+ const defaultMapping: StyledConfiguration<ComponentType<{ style: unknown }>> = {
22
+ className: "style",
23
+ };
24
+
20
25
  export const styled = <
21
26
  const C extends ReactComponent,
22
27
  const M extends StyledConfiguration<C>,
23
28
  >(
24
29
  baseComponent: C,
25
- mapping: M,
30
+ mapping: M = defaultMapping as M,
26
31
  _options?: StyledOptions,
27
32
  ) => {
28
- return (props: StyledProps<ComponentProps<C>, M>) => {
33
+ return (props: StyledProps<ComponentPropsWithRef<C>, M>) => {
29
34
  return useCssElement(baseComponent, mapping, props);
30
35
  };
31
36
  };
@@ -93,7 +98,7 @@ export function VariableContextProvider(
93
98
  ) {
94
99
  const style = useMemo(() => {
95
100
  return {
96
- display: "content",
101
+ display: "contents",
97
102
  ...Object.fromEntries(
98
103
  Object.entries(props.value).map(([key, value]) => [
99
104
  key.startsWith("--") ? key : `--${key}`,
package/types.d.ts CHANGED
@@ -16,6 +16,9 @@ declare module "@react-native/virtualized-lists" {
16
16
  }
17
17
 
18
18
  declare module "react-native" {
19
+ interface ButtonProps {
20
+ className?: string;
21
+ }
19
22
  interface ScrollViewProps
20
23
  extends ViewProps,
21
24
  ScrollViewPropsIOS,