rnwind 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. package/lib/cjs/core/parser/animation.cjs +427 -0
  2. package/lib/cjs/core/parser/animation.cjs.map +1 -0
  3. package/lib/cjs/core/parser/animation.d.ts +126 -0
  4. package/lib/cjs/core/parser/border-dispatcher.cjs +180 -0
  5. package/lib/cjs/core/parser/border-dispatcher.cjs.map +1 -0
  6. package/lib/cjs/core/parser/border-dispatcher.d.ts +15 -0
  7. package/lib/cjs/core/parser/case-convert.cjs +15 -0
  8. package/lib/cjs/core/parser/case-convert.cjs.map +1 -0
  9. package/lib/cjs/core/parser/case-convert.d.ts +6 -0
  10. package/lib/cjs/core/parser/color-properties-dispatcher.cjs +84 -0
  11. package/lib/cjs/core/parser/color-properties-dispatcher.cjs.map +1 -0
  12. package/lib/cjs/core/parser/color-properties-dispatcher.d.ts +19 -0
  13. package/lib/cjs/core/parser/color.cjs +193 -0
  14. package/lib/cjs/core/parser/color.cjs.map +1 -0
  15. package/lib/cjs/core/parser/color.d.ts +12 -0
  16. package/lib/cjs/core/parser/constants.cjs +21 -0
  17. package/lib/cjs/core/parser/constants.cjs.map +1 -0
  18. package/lib/cjs/core/parser/constants.d.ts +8 -0
  19. package/lib/cjs/core/parser/declaration.cjs +347 -0
  20. package/lib/cjs/core/parser/declaration.cjs.map +1 -0
  21. package/lib/cjs/core/parser/declaration.d.ts +15 -0
  22. package/lib/cjs/core/parser/gradient.cjs +132 -0
  23. package/lib/cjs/core/parser/gradient.cjs.map +1 -0
  24. package/lib/cjs/core/parser/gradient.d.ts +59 -0
  25. package/lib/cjs/core/parser/haptics.cjs +73 -0
  26. package/lib/cjs/core/parser/haptics.cjs.map +1 -0
  27. package/lib/cjs/core/parser/haptics.d.ts +47 -0
  28. package/lib/cjs/core/parser/index.d.ts +8 -0
  29. package/lib/cjs/core/parser/keyframes.cjs +95 -0
  30. package/lib/cjs/core/parser/keyframes.cjs.map +1 -0
  31. package/lib/cjs/core/parser/keyframes.d.ts +26 -0
  32. package/lib/cjs/core/parser/layout-dispatcher.cjs +120 -0
  33. package/lib/cjs/core/parser/layout-dispatcher.cjs.map +1 -0
  34. package/lib/cjs/core/parser/layout-dispatcher.d.ts +14 -0
  35. package/lib/cjs/core/parser/length.cjs +110 -0
  36. package/lib/cjs/core/parser/length.cjs.map +1 -0
  37. package/lib/cjs/core/parser/length.d.ts +51 -0
  38. package/lib/cjs/core/parser/motion-dispatcher.cjs +77 -0
  39. package/lib/cjs/core/parser/motion-dispatcher.cjs.map +1 -0
  40. package/lib/cjs/core/parser/motion-dispatcher.d.ts +11 -0
  41. package/lib/cjs/core/parser/property.cjs +22 -0
  42. package/lib/cjs/core/parser/property.cjs.map +1 -0
  43. package/lib/cjs/core/parser/property.d.ts +8 -0
  44. package/lib/cjs/core/parser/safe-area.cjs +404 -0
  45. package/lib/cjs/core/parser/safe-area.cjs.map +1 -0
  46. package/lib/cjs/core/parser/safe-area.d.ts +39 -0
  47. package/lib/cjs/core/parser/selector.cjs +22 -0
  48. package/lib/cjs/core/parser/selector.cjs.map +1 -0
  49. package/lib/cjs/core/parser/selector.d.ts +11 -0
  50. package/lib/cjs/core/parser/shorthand.cjs +188 -0
  51. package/lib/cjs/core/parser/shorthand.cjs.map +1 -0
  52. package/lib/cjs/core/parser/shorthand.d.ts +67 -0
  53. package/lib/cjs/core/parser/text-truncate.cjs +78 -0
  54. package/lib/cjs/core/parser/text-truncate.cjs.map +1 -0
  55. package/lib/cjs/core/parser/text-truncate.d.ts +44 -0
  56. package/lib/cjs/core/parser/theme-vars.cjs +467 -0
  57. package/lib/cjs/core/parser/theme-vars.cjs.map +1 -0
  58. package/lib/cjs/core/parser/theme-vars.d.ts +82 -0
  59. package/lib/cjs/core/parser/tokens.cjs +486 -0
  60. package/lib/cjs/core/parser/tokens.cjs.map +1 -0
  61. package/lib/cjs/core/parser/tokens.d.ts +45 -0
  62. package/lib/cjs/core/parser/transform.cjs +198 -0
  63. package/lib/cjs/core/parser/transform.cjs.map +1 -0
  64. package/lib/cjs/core/parser/transform.d.ts +36 -0
  65. package/lib/cjs/core/parser/tw-parser.cjs +1680 -0
  66. package/lib/cjs/core/parser/tw-parser.cjs.map +1 -0
  67. package/lib/cjs/core/parser/tw-parser.d.ts +210 -0
  68. package/lib/cjs/core/parser/types.d.ts +37 -0
  69. package/lib/cjs/core/parser/typography-dispatcher.cjs +108 -0
  70. package/lib/cjs/core/parser/typography-dispatcher.cjs.map +1 -0
  71. package/lib/cjs/core/parser/typography-dispatcher.d.ts +11 -0
  72. package/lib/cjs/core/parser/typography.cjs +97 -0
  73. package/lib/cjs/core/parser/typography.cjs.map +1 -0
  74. package/lib/cjs/core/parser/typography.d.ts +43 -0
  75. package/lib/cjs/core/style-builder/build-style.cjs +444 -0
  76. package/lib/cjs/core/style-builder/build-style.cjs.map +1 -0
  77. package/lib/cjs/core/style-builder/build-style.d.ts +54 -0
  78. package/lib/cjs/core/style-builder/index.d.ts +3 -0
  79. package/lib/cjs/core/style-builder/union-builder.cjs +326 -0
  80. package/lib/cjs/core/style-builder/union-builder.cjs.map +1 -0
  81. package/lib/cjs/core/style-builder/union-builder.d.ts +128 -0
  82. package/lib/cjs/core/types.d.ts +14 -0
  83. package/lib/cjs/metro/dts.cjs +127 -0
  84. package/lib/cjs/metro/dts.cjs.map +1 -0
  85. package/lib/cjs/metro/dts.d.ts +16 -0
  86. package/lib/cjs/metro/index.cjs +19 -0
  87. package/lib/cjs/metro/index.cjs.map +1 -0
  88. package/lib/cjs/metro/index.d.ts +9 -0
  89. package/lib/cjs/metro/resolver.cjs +47 -0
  90. package/lib/cjs/metro/resolver.cjs.map +1 -0
  91. package/lib/cjs/metro/resolver.d.ts +22 -0
  92. package/lib/cjs/metro/state.cjs +301 -0
  93. package/lib/cjs/metro/state.cjs.map +1 -0
  94. package/lib/cjs/metro/state.d.ts +88 -0
  95. package/lib/cjs/metro/transform-ast.cjs +1472 -0
  96. package/lib/cjs/metro/transform-ast.cjs.map +1 -0
  97. package/lib/cjs/metro/transform-ast.d.ts +88 -0
  98. package/lib/cjs/metro/transformer.cjs +372 -0
  99. package/lib/cjs/metro/transformer.cjs.map +1 -0
  100. package/lib/cjs/metro/transformer.d.ts +47 -0
  101. package/lib/cjs/metro/warn-unknown-classes.cjs +86 -0
  102. package/lib/cjs/metro/warn-unknown-classes.cjs.map +1 -0
  103. package/lib/cjs/metro/warn-unknown-classes.d.ts +21 -0
  104. package/lib/cjs/metro/with-config.cjs +196 -0
  105. package/lib/cjs/metro/with-config.cjs.map +1 -0
  106. package/lib/cjs/metro/with-config.d.ts +79 -0
  107. package/lib/cjs/runtime/chain-handlers.cjs +37 -0
  108. package/lib/cjs/runtime/chain-handlers.cjs.map +1 -0
  109. package/lib/cjs/runtime/chain-handlers.d.ts +33 -0
  110. package/lib/cjs/runtime/components/rnwind-provider.cjs +98 -0
  111. package/lib/cjs/runtime/components/rnwind-provider.cjs.map +1 -0
  112. package/lib/cjs/runtime/components/rnwind-provider.d.ts +84 -0
  113. package/lib/cjs/runtime/gradient-types.d.ts +58 -0
  114. package/lib/cjs/runtime/haptics.cjs +113 -0
  115. package/lib/cjs/runtime/haptics.cjs.map +1 -0
  116. package/lib/cjs/runtime/haptics.d.ts +48 -0
  117. package/lib/cjs/runtime/hooks/use-css.cjs +21 -0
  118. package/lib/cjs/runtime/hooks/use-css.cjs.map +1 -0
  119. package/lib/cjs/runtime/hooks/use-css.d.ts +11 -0
  120. package/lib/cjs/runtime/hooks/use-interact.cjs +46 -0
  121. package/lib/cjs/runtime/hooks/use-interact.cjs.map +1 -0
  122. package/lib/cjs/runtime/hooks/use-interact.d.ts +42 -0
  123. package/lib/cjs/runtime/hooks/use-scheme.cjs +68 -0
  124. package/lib/cjs/runtime/hooks/use-scheme.cjs.map +1 -0
  125. package/lib/cjs/runtime/hooks/use-scheme.d.ts +34 -0
  126. package/lib/cjs/runtime/index.cjs +45 -0
  127. package/lib/cjs/runtime/index.cjs.map +1 -0
  128. package/lib/cjs/runtime/index.d.ts +27 -0
  129. package/lib/cjs/runtime/interactive-box.cjs +35 -0
  130. package/lib/cjs/runtime/interactive-box.cjs.map +1 -0
  131. package/lib/cjs/runtime/interactive-box.d.ts +40 -0
  132. package/lib/cjs/runtime/lookup-css.cjs +542 -0
  133. package/lib/cjs/runtime/lookup-css.cjs.map +1 -0
  134. package/lib/cjs/runtime/lookup-css.d.ts +164 -0
  135. package/lib/cjs/runtime/types.d.ts +29 -0
  136. package/lib/cjs/testing/index.cjs +367 -0
  137. package/lib/cjs/testing/index.cjs.map +1 -0
  138. package/lib/cjs/testing/index.d.ts +145 -0
  139. package/lib/esm/core/parser/animation.d.ts +126 -0
  140. package/lib/esm/core/parser/animation.mjs +408 -0
  141. package/lib/esm/core/parser/animation.mjs.map +1 -0
  142. package/lib/esm/core/parser/border-dispatcher.d.ts +15 -0
  143. package/lib/esm/core/parser/border-dispatcher.mjs +178 -0
  144. package/lib/esm/core/parser/border-dispatcher.mjs.map +1 -0
  145. package/lib/esm/core/parser/case-convert.d.ts +6 -0
  146. package/lib/esm/core/parser/case-convert.mjs +13 -0
  147. package/lib/esm/core/parser/case-convert.mjs.map +1 -0
  148. package/lib/esm/core/parser/color-properties-dispatcher.d.ts +19 -0
  149. package/lib/esm/core/parser/color-properties-dispatcher.mjs +82 -0
  150. package/lib/esm/core/parser/color-properties-dispatcher.mjs.map +1 -0
  151. package/lib/esm/core/parser/color.d.ts +12 -0
  152. package/lib/esm/core/parser/color.mjs +191 -0
  153. package/lib/esm/core/parser/color.mjs.map +1 -0
  154. package/lib/esm/core/parser/constants.d.ts +8 -0
  155. package/lib/esm/core/parser/constants.mjs +13 -0
  156. package/lib/esm/core/parser/constants.mjs.map +1 -0
  157. package/lib/esm/core/parser/declaration.d.ts +15 -0
  158. package/lib/esm/core/parser/declaration.mjs +345 -0
  159. package/lib/esm/core/parser/declaration.mjs.map +1 -0
  160. package/lib/esm/core/parser/gradient.d.ts +59 -0
  161. package/lib/esm/core/parser/gradient.mjs +130 -0
  162. package/lib/esm/core/parser/gradient.mjs.map +1 -0
  163. package/lib/esm/core/parser/haptics.d.ts +47 -0
  164. package/lib/esm/core/parser/haptics.mjs +71 -0
  165. package/lib/esm/core/parser/haptics.mjs.map +1 -0
  166. package/lib/esm/core/parser/index.d.ts +8 -0
  167. package/lib/esm/core/parser/keyframes.d.ts +26 -0
  168. package/lib/esm/core/parser/keyframes.mjs +91 -0
  169. package/lib/esm/core/parser/keyframes.mjs.map +1 -0
  170. package/lib/esm/core/parser/layout-dispatcher.d.ts +14 -0
  171. package/lib/esm/core/parser/layout-dispatcher.mjs +118 -0
  172. package/lib/esm/core/parser/layout-dispatcher.mjs.map +1 -0
  173. package/lib/esm/core/parser/length.d.ts +51 -0
  174. package/lib/esm/core/parser/length.mjs +104 -0
  175. package/lib/esm/core/parser/length.mjs.map +1 -0
  176. package/lib/esm/core/parser/motion-dispatcher.d.ts +11 -0
  177. package/lib/esm/core/parser/motion-dispatcher.mjs +75 -0
  178. package/lib/esm/core/parser/motion-dispatcher.mjs.map +1 -0
  179. package/lib/esm/core/parser/property.d.ts +8 -0
  180. package/lib/esm/core/parser/property.mjs +20 -0
  181. package/lib/esm/core/parser/property.mjs.map +1 -0
  182. package/lib/esm/core/parser/safe-area.d.ts +39 -0
  183. package/lib/esm/core/parser/safe-area.mjs +402 -0
  184. package/lib/esm/core/parser/safe-area.mjs.map +1 -0
  185. package/lib/esm/core/parser/selector.d.ts +11 -0
  186. package/lib/esm/core/parser/selector.mjs +20 -0
  187. package/lib/esm/core/parser/selector.mjs.map +1 -0
  188. package/lib/esm/core/parser/shorthand.d.ts +67 -0
  189. package/lib/esm/core/parser/shorthand.mjs +180 -0
  190. package/lib/esm/core/parser/shorthand.mjs.map +1 -0
  191. package/lib/esm/core/parser/text-truncate.d.ts +44 -0
  192. package/lib/esm/core/parser/text-truncate.mjs +75 -0
  193. package/lib/esm/core/parser/text-truncate.mjs.map +1 -0
  194. package/lib/esm/core/parser/theme-vars.d.ts +82 -0
  195. package/lib/esm/core/parser/theme-vars.mjs +461 -0
  196. package/lib/esm/core/parser/theme-vars.mjs.map +1 -0
  197. package/lib/esm/core/parser/tokens.d.ts +45 -0
  198. package/lib/esm/core/parser/tokens.mjs +480 -0
  199. package/lib/esm/core/parser/tokens.mjs.map +1 -0
  200. package/lib/esm/core/parser/transform.d.ts +36 -0
  201. package/lib/esm/core/parser/transform.mjs +193 -0
  202. package/lib/esm/core/parser/transform.mjs.map +1 -0
  203. package/lib/esm/core/parser/tw-parser.d.ts +210 -0
  204. package/lib/esm/core/parser/tw-parser.mjs +1678 -0
  205. package/lib/esm/core/parser/tw-parser.mjs.map +1 -0
  206. package/lib/esm/core/parser/types.d.ts +37 -0
  207. package/lib/esm/core/parser/typography-dispatcher.d.ts +11 -0
  208. package/lib/esm/core/parser/typography-dispatcher.mjs +106 -0
  209. package/lib/esm/core/parser/typography-dispatcher.mjs.map +1 -0
  210. package/lib/esm/core/parser/typography.d.ts +43 -0
  211. package/lib/esm/core/parser/typography.mjs +91 -0
  212. package/lib/esm/core/parser/typography.mjs.map +1 -0
  213. package/lib/esm/core/style-builder/build-style.d.ts +54 -0
  214. package/lib/esm/core/style-builder/build-style.mjs +442 -0
  215. package/lib/esm/core/style-builder/build-style.mjs.map +1 -0
  216. package/lib/esm/core/style-builder/index.d.ts +3 -0
  217. package/lib/esm/core/style-builder/union-builder.d.ts +128 -0
  218. package/lib/esm/core/style-builder/union-builder.mjs +324 -0
  219. package/lib/esm/core/style-builder/union-builder.mjs.map +1 -0
  220. package/lib/esm/core/types.d.ts +14 -0
  221. package/lib/esm/metro/dts.d.ts +16 -0
  222. package/lib/esm/metro/dts.mjs +125 -0
  223. package/lib/esm/metro/dts.mjs.map +1 -0
  224. package/lib/esm/metro/index.d.ts +9 -0
  225. package/lib/esm/metro/index.mjs +6 -0
  226. package/lib/esm/metro/index.mjs.map +1 -0
  227. package/lib/esm/metro/resolver.d.ts +22 -0
  228. package/lib/esm/metro/resolver.mjs +43 -0
  229. package/lib/esm/metro/resolver.mjs.map +1 -0
  230. package/lib/esm/metro/state.d.ts +88 -0
  231. package/lib/esm/metro/state.mjs +291 -0
  232. package/lib/esm/metro/state.mjs.map +1 -0
  233. package/lib/esm/metro/transform-ast.d.ts +88 -0
  234. package/lib/esm/metro/transform-ast.mjs +1451 -0
  235. package/lib/esm/metro/transform-ast.mjs.map +1 -0
  236. package/lib/esm/metro/transformer.d.ts +47 -0
  237. package/lib/esm/metro/transformer.mjs +349 -0
  238. package/lib/esm/metro/transformer.mjs.map +1 -0
  239. package/lib/esm/metro/warn-unknown-classes.d.ts +21 -0
  240. package/lib/esm/metro/warn-unknown-classes.mjs +84 -0
  241. package/lib/esm/metro/warn-unknown-classes.mjs.map +1 -0
  242. package/lib/esm/metro/with-config.d.ts +79 -0
  243. package/lib/esm/metro/with-config.mjs +194 -0
  244. package/lib/esm/metro/with-config.mjs.map +1 -0
  245. package/lib/esm/runtime/chain-handlers.d.ts +33 -0
  246. package/lib/esm/runtime/chain-handlers.mjs +34 -0
  247. package/lib/esm/runtime/chain-handlers.mjs.map +1 -0
  248. package/lib/esm/runtime/components/rnwind-provider.d.ts +84 -0
  249. package/lib/esm/runtime/components/rnwind-provider.mjs +94 -0
  250. package/lib/esm/runtime/components/rnwind-provider.mjs.map +1 -0
  251. package/lib/esm/runtime/gradient-types.d.ts +58 -0
  252. package/lib/esm/runtime/haptics.d.ts +48 -0
  253. package/lib/esm/runtime/haptics.mjs +110 -0
  254. package/lib/esm/runtime/haptics.mjs.map +1 -0
  255. package/lib/esm/runtime/hooks/use-css.d.ts +11 -0
  256. package/lib/esm/runtime/hooks/use-css.mjs +19 -0
  257. package/lib/esm/runtime/hooks/use-css.mjs.map +1 -0
  258. package/lib/esm/runtime/hooks/use-interact.d.ts +42 -0
  259. package/lib/esm/runtime/hooks/use-interact.mjs +44 -0
  260. package/lib/esm/runtime/hooks/use-interact.mjs.map +1 -0
  261. package/lib/esm/runtime/hooks/use-scheme.d.ts +34 -0
  262. package/lib/esm/runtime/hooks/use-scheme.mjs +63 -0
  263. package/lib/esm/runtime/hooks/use-scheme.mjs.map +1 -0
  264. package/lib/esm/runtime/index.d.ts +27 -0
  265. package/lib/esm/runtime/index.mjs +18 -0
  266. package/lib/esm/runtime/index.mjs.map +1 -0
  267. package/lib/esm/runtime/interactive-box.d.ts +40 -0
  268. package/lib/esm/runtime/interactive-box.mjs +33 -0
  269. package/lib/esm/runtime/interactive-box.mjs.map +1 -0
  270. package/lib/esm/runtime/lookup-css.d.ts +164 -0
  271. package/lib/esm/runtime/lookup-css.mjs +531 -0
  272. package/lib/esm/runtime/lookup-css.mjs.map +1 -0
  273. package/lib/esm/runtime/types.d.ts +29 -0
  274. package/lib/esm/testing/index.d.ts +145 -0
  275. package/lib/esm/testing/index.mjs +344 -0
  276. package/lib/esm/testing/index.mjs.map +1 -0
  277. package/package.json +80 -13
  278. package/preset.css +1171 -0
  279. package/src/core/parser/animation.ts +404 -0
  280. package/src/core/parser/border-dispatcher.ts +176 -0
  281. package/src/core/parser/case-convert.ts +10 -0
  282. package/src/core/parser/color-properties-dispatcher.ts +78 -0
  283. package/src/core/parser/color.ts +191 -0
  284. package/src/core/parser/constants.ts +11 -0
  285. package/src/core/parser/declaration.ts +340 -0
  286. package/src/core/parser/gradient.ts +148 -0
  287. package/src/core/parser/haptics.ts +88 -0
  288. package/src/core/parser/index.ts +8 -0
  289. package/src/core/parser/keyframes.ts +84 -0
  290. package/src/core/parser/layout-dispatcher.ts +111 -0
  291. package/src/core/parser/length.ts +114 -0
  292. package/src/core/parser/motion-dispatcher.ts +89 -0
  293. package/src/core/parser/property.ts +15 -0
  294. package/src/core/parser/safe-area.ts +404 -0
  295. package/src/core/parser/selector.ts +17 -0
  296. package/src/core/parser/shorthand.ts +182 -0
  297. package/src/core/parser/text-truncate.ts +79 -0
  298. package/src/core/parser/theme-vars.ts +465 -0
  299. package/src/core/parser/tokens.ts +456 -0
  300. package/src/core/parser/transform.ts +195 -0
  301. package/src/core/parser/tw-parser.ts +1828 -0
  302. package/src/core/parser/types.ts +45 -0
  303. package/src/core/parser/typography-dispatcher.ts +97 -0
  304. package/src/core/parser/typography.ts +83 -0
  305. package/src/core/style-builder/build-style.ts +500 -0
  306. package/src/core/style-builder/index.ts +3 -0
  307. package/src/core/style-builder/union-builder.ts +328 -0
  308. package/src/core/types.ts +15 -0
  309. package/src/metro/dts.ts +128 -0
  310. package/src/metro/index.ts +9 -0
  311. package/src/metro/resolver.ts +42 -0
  312. package/src/metro/state.ts +305 -0
  313. package/src/metro/transform-ast.ts +1729 -0
  314. package/src/metro/transformer.ts +372 -0
  315. package/src/metro/warn-unknown-classes.ts +79 -0
  316. package/src/metro/with-config.ts +251 -0
  317. package/src/runtime/chain-handlers.ts +47 -0
  318. package/src/runtime/components/rnwind-provider.tsx +144 -0
  319. package/src/runtime/gradient-types.ts +60 -0
  320. package/src/runtime/haptics.ts +120 -0
  321. package/src/runtime/hooks/use-css.ts +16 -0
  322. package/src/runtime/hooks/use-interact.ts +65 -0
  323. package/src/runtime/hooks/use-scheme.ts +63 -0
  324. package/src/runtime/index.ts +54 -0
  325. package/src/runtime/interactive-box.tsx +57 -0
  326. package/src/runtime/lookup-css.ts +628 -0
  327. package/src/runtime/types.ts +32 -0
  328. package/src/testing/index.ts +507 -0
  329. package/src/types/tailwindcss-node.d.ts +33 -0
  330. package/src/index.ts +0 -1
@@ -0,0 +1,628 @@
1
+ /**
2
+ * Runtime resolver for rnwind-transformed files.
3
+ *
4
+ * Hot path is ONE WeakMap.get + cached-array return for stable atoms
5
+ * (no `active:`/`focus:`/`*-safe` variance beyond what the cache key
6
+ * captures). First call per (hoist, scheme, stateIndex) walks the
7
+ * atoms once, looks each up as
8
+ *
9
+ * `cache.atoms[scheme]?.[atom] ?? cache.atoms.common?.[atom]`
10
+ *
11
+ * and caches the result. `registerAtoms(scheme, record)` bumps a
12
+ * version counter; the next lookup notices the mismatch and rebuilds.
13
+ *
14
+ * Keyframes are inlined directly into atom values via `animationName`
15
+ * at build time — no separate registry.
16
+ */
17
+
18
+ import type { RnwindState } from './components/rnwind-provider'
19
+
20
+ /** Empty sentinel returned when the input is null / undefined / empty. */
21
+ const EMPTY_STYLES: readonly unknown[] = []
22
+
23
+ /** Registry key for the always-loaded fallback scheme. */
24
+ const COMMON_SCHEME = 'common'
25
+
26
+ /** Atom name prefix marking a press-state-gated atom. */
27
+ const ACTIVE_PREFIX = 'active:'
28
+
29
+ /** Atom name prefix marking a focus-state-gated atom. */
30
+ const FOCUS_PREFIX = 'focus:'
31
+
32
+ /** Partial record — missing keys resolve to undefined, which the fallback handles. */
33
+ type SchemeAtomsRecord = Partial<Record<string, unknown>>
34
+
35
+ /** 0 = idle, 1 = active, 2 = focus, 3 = both. */
36
+ type StateIndex = 0 | 1 | 2 | 3
37
+
38
+ /**
39
+ * One entry in the sorted-by-threshold breakpoints array. The runtime
40
+ * derives an atom's threshold by matching its `<prefix>:` against
41
+ * `name`; the array form is preferred over a Map so the hot-path
42
+ * `tierFor(width)` walk is a tight numeric loop.
43
+ */
44
+ interface BreakpointEntry {
45
+ readonly name: string
46
+ readonly minWidth: number
47
+ }
48
+
49
+ /**
50
+ * Process-global style cache. Replaced key-by-key by {@link registerAtoms}.
51
+ * Plain record-of-records: `scheme → atom → style`. Active scheme
52
+ * lookup is `cache.atoms[scheme]?.[atom]` — two property reads with
53
+ * an `?? cache.atoms.common[atom]` fallback. No loops over the
54
+ * registry, ever.
55
+ *
56
+ * `breakpoints` mirrors the build-time table the manifest module
57
+ * registers via {@link registerBreakpoints} — `name → px-threshold` for
58
+ * fast prefix-based atom filtering plus the sorted-by-threshold list
59
+ * for cheap tier-index computation in `lookupCss`.
60
+ */
61
+ const cache = {
62
+ atoms: Object.create(null) as Partial<Record<string, SchemeAtomsRecord>>,
63
+ breakpoints: Object.create(null) as Partial<Record<string, number>>,
64
+ breakpointList: [] as readonly BreakpointEntry[],
65
+ }
66
+
67
+ /**
68
+ * Bumps on every {@link registerAtoms} call. {@link HoistCache} entries
69
+ * stamp themselves with the current version; a mismatch on read
70
+ * triggers a rebuild so HMR-reloaded atoms propagate without manual
71
+ * invalidation.
72
+ */
73
+ let atomVersion = 0
74
+
75
+ /** Optional window-height provider for the `screen-minus-y` marker. */
76
+ type WindowHeightProvider = () => number
77
+ let windowHeightProvider: WindowHeightProvider | null = null
78
+
79
+ /**
80
+ * Optional scheme loader. Registered by the generated manifest module
81
+ * (`rnwind/__generated/schemes`) once at import time. SchemeProvider
82
+ * calls it synchronously on every render with the active scheme name;
83
+ * first call per scheme pulls the scheme's style module in via an
84
+ * inline `require()` — subsequent calls are a no-op through Metro's
85
+ * module cache.
86
+ */
87
+ type SchemeLoader = (scheme: string) => void
88
+ let schemeLoader: SchemeLoader | null = null
89
+
90
+ /** Module-scope flag so the missing-insets warning fires at most once. */
91
+ let WARNED_MISSING_INSETS = false
92
+
93
+ /** Atoms we've already dev-warned about — keeps the noise to ONE line per typo per session. */
94
+ const WARNED_UNKNOWN_ATOMS = new Set<string>()
95
+
96
+ /**
97
+ * Compute the state-array index from the live interactState. Bit-or
98
+ * encoding: 0 = idle, 1 = active, 2 = focus, 3 = both.
99
+ * @param interactState Snapshot from `useInteract()` (or undefined).
100
+ * @returns 0 / 1 / 2 / 3.
101
+ */
102
+ function stateIndexFor(interactState: InteractState | undefined): StateIndex {
103
+ if (!interactState) return 0
104
+ return (((interactState.active ? 1 : 0) | (interactState.focus ? 2 : 0)) as StateIndex)
105
+ }
106
+
107
+ /**
108
+ * Fetch the px inset for one side. Falls back to 0 when insets is undefined.
109
+ * @param side Compact side tag (`t` / `r` / `b` / `l`).
110
+ * @param insets Active insets.
111
+ * @returns Px value for that side.
112
+ */
113
+ function insetOf(side: string, insets: LookupInsets | undefined): number {
114
+ if (!insets) return 0
115
+ if (side === 't') return insets.top
116
+ if (side === 'r') return insets.right
117
+ if (side === 'b') return insets.bottom
118
+ if (side === 'l') return insets.left
119
+ return 0
120
+ }
121
+
122
+ /**
123
+ * Collapse one safe-area marker into a concrete px number using the
124
+ * active insets.
125
+ * @param spec Marker spec tuple `[cssKey, sideTag, or, offset]`.
126
+ * @param insets Active insets (or undefined → 0).
127
+ * @returns Resolved px number.
128
+ */
129
+ function resolveMarker(spec: SafeMarkerSpec, insets: LookupInsets | undefined): number {
130
+ const [, side, or_, offset] = spec
131
+ if (side === 'screen-minus-y') {
132
+ const h = windowHeightProvider ? windowHeightProvider() : 0
133
+ return Math.max(0, h - insetOf('t', insets) - insetOf('b', insets))
134
+ }
135
+ let base = insetOf(side, insets)
136
+ if (or_ !== undefined) base = Math.max(base, or_)
137
+ if (offset !== undefined) base += offset
138
+ return base
139
+ }
140
+
141
+ /**
142
+ * Emit a one-shot dev warning when a safe-area atom resolves without
143
+ * real insets in scope.
144
+ * @param insets Insets received by the resolver.
145
+ */
146
+ function warnMissingInsetsOnce(insets: LookupInsets | undefined): void {
147
+ if (WARNED_MISSING_INSETS) return
148
+ const isDevelopment = typeof __DEV__ === 'undefined' || __DEV__
149
+ if (!isDevelopment) return
150
+ if (insets && (insets.top !== 0 || insets.right !== 0 || insets.bottom !== 0 || insets.left !== 0)) return
151
+ WARNED_MISSING_INSETS = true
152
+ // eslint-disable-next-line no-console
153
+ console.warn(
154
+ 'rnwind: a `*-safe` utility resolved with zero insets. Wire `insets` on <SchemeProvider> ' +
155
+ '(e.g. `insets={useSafeAreaInsets()}` from react-native-safe-area-context).',
156
+ )
157
+ }
158
+
159
+ /**
160
+ * Resolve precomputed safe-area marker specs into a fresh RN style
161
+ * object. Cannot be cached — insets vary per render with rotation /
162
+ * keyboard.
163
+ * @param specs Array of spec tuples.
164
+ * @param insets Live safe-area insets.
165
+ * @returns Fresh RN style object with concrete numbers.
166
+ */
167
+ function resolveSafe(specs: readonly SafeMarkerSpec[], insets: LookupInsets | undefined): Record<string, number> {
168
+ warnMissingInsetsOnce(insets)
169
+ const out: Record<string, number> = {}
170
+ for (const spec of specs) out[spec[0]] = resolveMarker(spec, insets)
171
+ return out
172
+ }
173
+
174
+ /**
175
+ * Multiply `fontSize` / `lineHeight` in a resolved atom value by the
176
+ * active font scale. Early-returns the original reference for any atom
177
+ * that doesn't carry either property (most of them) — zero allocation
178
+ * on the hot path for non-text atoms.
179
+ * @param value Atom value as registered in the global table.
180
+ * @param fontScale Multiplier from `useWindowDimensions().fontScale`.
181
+ * @returns Scaled style object, or the original when no scaling applied.
182
+ */
183
+ function applyFontScale(value: unknown, fontScale: number): unknown {
184
+ if (fontScale === 1) return value
185
+ if (typeof value !== 'object' || value === null) return value
186
+ const record = value as Record<string, unknown>
187
+ const fs = record.fontSize
188
+ const lh = record.lineHeight
189
+ if (typeof fs !== 'number' && typeof lh !== 'number') return value
190
+ const scaled: Record<string, unknown> = { ...record }
191
+ if (typeof fs === 'number') scaled.fontSize = fs * fontScale
192
+ if (typeof lh === 'number') scaled.lineHeight = lh * fontScale
193
+ return scaled
194
+ }
195
+
196
+ /**
197
+ * Read the precomputed safe-area marker spec list off an atom value.
198
+ * Build-side `envelopeSafeMarkers` wraps safe atoms in
199
+ * `{__safeStyle: [...]}`; this is a single property access.
200
+ * @param value Atom value as registered in the global table.
201
+ * @returns Spec array when the atom is safe-area, else null.
202
+ */
203
+ function readSafeSpecs(value: unknown): readonly SafeMarkerSpec[] | null {
204
+ if (typeof value !== 'object' || value === null) return null
205
+ const safe = (value as { __safeStyle?: readonly SafeMarkerSpec[] }).__safeStyle
206
+ return safe ?? null
207
+ }
208
+
209
+ /**
210
+ * Per-atom lookup. Two property reads: scheme's own table then the
211
+ * common fallback. Returns `undefined` for unknown atoms — the caller
212
+ * skips them.
213
+ * @param scheme Active scheme.
214
+ * @param atom Atom name.
215
+ * @returns Resolved value, or undefined.
216
+ */
217
+ function lookupAtom(scheme: string, atom: string): unknown {
218
+ const schemeTable = cache.atoms[scheme]
219
+ if (schemeTable !== undefined) {
220
+ const own = schemeTable[atom]
221
+ if (own !== undefined) return own
222
+ }
223
+ const common = cache.atoms[COMMON_SCHEME]
224
+ return common === undefined ? undefined : common[atom]
225
+ }
226
+
227
+ /**
228
+ * Whether an atom should participate in a given interact-state index.
229
+ * - idle (0): no `active:` / `focus:` atoms.
230
+ * - active (1): base + `active:`.
231
+ * - focus (2): base + `focus:`.
232
+ * - both (3): base + `active:` + `focus:`.
233
+ * @param atom Atom name.
234
+ * @param stateIndex Encoded state (0/1/2/3).
235
+ * @returns True when the atom should be emitted for this state.
236
+ */
237
+ function atomMatchesState(atom: string, stateIndex: StateIndex): boolean {
238
+ // Cheap prefix check — check the first code point before the full
239
+ // `startsWith` so we skip it for any atom whose first letter isn't
240
+ // `a` / `f`.
241
+ const code = atom.codePointAt(0)
242
+ if (code === 97 /* a */ && atom.startsWith(ACTIVE_PREFIX)) return (stateIndex & 1) !== 0
243
+ if (code === 102 /* f */ && atom.startsWith(FOCUS_PREFIX)) return (stateIndex & 2) !== 0
244
+ return true
245
+ }
246
+
247
+ /**
248
+ * Whether an atom passes the responsive-breakpoint gate for the
249
+ * current `windowWidth`. Atoms without a registered `<prefix>:` are
250
+ * always-on (the common case — `bg-red-500`, `active:bg-blue-700`).
251
+ * Atoms whose first prefix matches a registered breakpoint name pass
252
+ * only when `windowWidth >= threshold`.
253
+ * @param atom Atom name.
254
+ * @param windowWidth Live `useWindowDimensions().width` snapshot.
255
+ * @returns True when the atom should be emitted for this width.
256
+ */
257
+ function atomMatchesBreakpoint(atom: string, windowWidth: number): boolean {
258
+ const colon = atom.indexOf(':')
259
+ if (colon === -1) return true
260
+ const prefix = atom.slice(0, colon)
261
+ const threshold = cache.breakpoints[prefix]
262
+ if (threshold === undefined) return true
263
+ return windowWidth >= threshold
264
+ }
265
+
266
+ /**
267
+ * Tier index — count of registered breakpoints whose threshold is
268
+ * `<= windowWidth`. Bounded by the breakpoint count, so it's a stable
269
+ * cache-key dimension instead of the unbounded raw width. Crossings
270
+ * happen ~5 times across the device-width spectrum, not per-pixel.
271
+ * @param windowWidth Live width.
272
+ * @returns Tier 0..N where N = `cache.breakpointList.length`.
273
+ */
274
+ function tierFor(windowWidth: number): number {
275
+ let tier = 0
276
+ for (const entry of cache.breakpointList) {
277
+ if (windowWidth >= entry.minWidth) tier += 1
278
+ else break
279
+ }
280
+ return tier
281
+ }
282
+
283
+ /**
284
+ * Build the style array for a (hoist, scheme, state, width) tuple.
285
+ * Walks the atom list, applies the interact-state and breakpoint
286
+ * filters, resolves each atom via scheme→common fallback, and
287
+ * envelopes safe values via {@link resolveSafe}.
288
+ * @param atoms Atom name list (build-time constant).
289
+ * @param scheme Active scheme.
290
+ * @param stateIndex Encoded active/focus state.
291
+ * @param insets Live safe-area insets.
292
+ * @param fontScale Font scale multiplier.
293
+ * @param windowWidth Live window width — gates `md:*` / `lg:*` atoms.
294
+ * @returns Fresh style array.
295
+ */
296
+ function buildStyleArray(
297
+ atoms: readonly string[],
298
+ scheme: string,
299
+ stateIndex: StateIndex,
300
+ insets: LookupInsets | undefined,
301
+ fontScale: number,
302
+ windowWidth: number,
303
+ ): readonly unknown[] {
304
+ const out: unknown[] = []
305
+ for (const atom of atoms) {
306
+ if (!atomMatchesState(atom, stateIndex)) continue
307
+ if (!atomMatchesBreakpoint(atom, windowWidth)) continue
308
+ const value = lookupAtom(scheme, atom)
309
+ if (value === undefined) {
310
+ warnUnknownAtomOnce(atom)
311
+ continue
312
+ }
313
+ const safe = readSafeSpecs(value)
314
+ const resolved = safe === null ? value : resolveSafe(safe, insets)
315
+ out.push(applyFontScale(resolved, fontScale))
316
+ }
317
+ return out
318
+ }
319
+
320
+ /**
321
+ * Emit a one-shot dev warning when an atom name doesn't resolve in the
322
+ * registry. The two real causes are a typo (`bg-red-501`) or a class
323
+ * the build-time scanner never saw because it lives in a string the
324
+ * oxide tokeniser can't see (e.g. computed at runtime). Either way, a
325
+ * silent empty style is the worst possible UX — surface it.
326
+ *
327
+ * Filters cosmetic non-issues: empty strings, build-time `__safeStyle`
328
+ * envelopes that wandered in, etc.
329
+ * @param atom Class name that didn't resolve.
330
+ */
331
+ function warnUnknownAtomOnce(atom: string): void {
332
+ if (atom.length === 0) return
333
+ const isDevelopment = typeof __DEV__ === 'undefined' || __DEV__
334
+ if (!isDevelopment) return
335
+ if (WARNED_UNKNOWN_ATOMS.has(atom)) return
336
+ WARNED_UNKNOWN_ATOMS.add(atom)
337
+ // eslint-disable-next-line no-console
338
+ console.warn(
339
+ `rnwind: unknown class "${atom}" — typo, or the class is built dynamically and the build-time ` +
340
+ `scanner never saw it. Static literals + ternaries are scanned automatically; runtime-built ` +
341
+ `strings need to appear somewhere as a literal so oxide can pick them up.`,
342
+ )
343
+ }
344
+
345
+ /**
346
+ * Per-hoist cache entry. `version` stamps `atomVersion` at build time
347
+ * so HMR reloads (which bump the counter) invalidate cleanly on next
348
+ * read. `hasSafe` prevents caching results whose values depend on
349
+ * per-render insets. `byKey` maps `"${scheme}|${stateIndex}"` to the
350
+ * cached result.
351
+ */
352
+ interface HoistCache {
353
+ version: number
354
+ hasSafe: boolean
355
+ byKey: Partial<Record<string, readonly unknown[]>>
356
+ }
357
+
358
+ /**
359
+ * Per-atom-list cache keyed on the hoist reference. WeakMap so
360
+ * hoists GC with their host module on HMR.
361
+ */
362
+ const resultCache = new WeakMap<readonly string[], HoistCache>()
363
+
364
+ /**
365
+ * Walk the atom list once to detect safe-area atoms — results that
366
+ * vary per render with `insets`. When any atom envelopes safe specs
367
+ * we skip the cache and rebuild every call.
368
+ * @param atoms Hoist atom list.
369
+ * @param scheme Active scheme.
370
+ * @returns Whether the hoist resolves a safe atom under this scheme.
371
+ */
372
+ function detectHasSafe(atoms: readonly string[], scheme: string): boolean {
373
+ for (const atom of atoms) {
374
+ const value = lookupAtom(scheme, atom)
375
+ if (readSafeSpecs(value) !== null) return true
376
+ }
377
+ return false
378
+ }
379
+
380
+ /**
381
+ * Cache-keyed resolution for the common static-schema case. Returns a
382
+ * stable array reference across renders until `atomVersion` bumps.
383
+ * For hoists containing safe atoms — which depend on per-render
384
+ * insets — rebuilds every call.
385
+ *
386
+ * The `tier` dimension keeps the cache bounded under responsive
387
+ * variants: instead of keying on raw `windowWidth` (which would explode
388
+ * the cache to one entry per pixel), we key on the count of registered
389
+ * breakpoints whose threshold is reached. That gives at most
390
+ * `breakpointCount + 1` cache rows per (scheme, state, fontScale).
391
+ * @param atoms Hoist atom list.
392
+ * @param scheme Active scheme.
393
+ * @param stateIndex Encoded interact state.
394
+ * @param insets Live safe-area insets.
395
+ * @param fontScale Font scale multiplier.
396
+ * @param windowWidth Live window width.
397
+ * @returns Style array.
398
+ */
399
+ function lookupCached(
400
+ atoms: readonly string[],
401
+ scheme: string,
402
+ stateIndex: StateIndex,
403
+ insets: LookupInsets | undefined,
404
+ fontScale: number,
405
+ windowWidth: number,
406
+ ): readonly unknown[] {
407
+ let entry = resultCache.get(atoms)
408
+ if (entry?.version !== atomVersion) {
409
+ entry = { version: atomVersion, hasSafe: detectHasSafe(atoms, scheme), byKey: Object.create(null) }
410
+ resultCache.set(atoms, entry)
411
+ }
412
+ if (entry.hasSafe) return buildStyleArray(atoms, scheme, stateIndex, insets, fontScale, windowWidth)
413
+ const tier = tierFor(windowWidth)
414
+ const key = `${scheme}|${stateIndex}|${fontScale}|${tier}`
415
+ const cached = entry.byKey[key]
416
+ if (cached !== undefined) return cached
417
+ const fresh = buildStyleArray(atoms, scheme, stateIndex, insets, fontScale, windowWidth)
418
+ entry.byKey[key] = fresh
419
+ return fresh
420
+ }
421
+
422
+ /**
423
+ * Per-render snapshot of which interactive states (active, focus) are
424
+ * currently engaged. Forwarded from the `useInteract()` hook the
425
+ * transformer injects.
426
+ */
427
+ export interface InteractState {
428
+ active?: boolean
429
+ focus?: boolean
430
+ }
431
+
432
+ /**
433
+ * Safe-area insets bundle the transformer passes to `lookupCss` when a
434
+ * file uses any `*-safe` utility.
435
+ */
436
+ export interface LookupInsets {
437
+ top: number
438
+ right: number
439
+ bottom: number
440
+ left: number
441
+ }
442
+
443
+
444
+ /**
445
+ * Precomputed safe-area marker spec emitted by the build-side
446
+ * `envelopeSafeMarkers`. Tuple form: `[cssKey, sideTag, or, offset]`.
447
+ */
448
+ export type SafeMarkerSpec = readonly [string, string, number | undefined, number | undefined]
449
+
450
+ /** Type alias: the atom-list build output the transformer emits. */
451
+ export type HoistedClassName = readonly string[]
452
+
453
+ /**
454
+ * Register a window-height provider used by the `screen-minus-y`
455
+ * safe-area variant. When not wired, `h-screen-safe` resolves to `0`.
456
+ * @param provider Callback returning the current window height in px.
457
+ */
458
+ export function setWindowHeightProvider(provider: WindowHeightProvider | null): void {
459
+ windowHeightProvider = provider
460
+ }
461
+
462
+ /**
463
+ * Register the scheme-loader function exported by the generated
464
+ * manifest module. Called once at manifest-module evaluation time —
465
+ * subsequent registrations override the previous loader (useful for
466
+ * tests).
467
+ * @param loader Manifest's `ensureSchemeLoaded` function, or null to
468
+ * detach (tests).
469
+ */
470
+ export function registerSchemeLoader(loader: SchemeLoader | null): void {
471
+ schemeLoader = loader
472
+ }
473
+
474
+ /**
475
+ * Ensure the given scheme's style module is loaded. Safe to call in
476
+ * render — zero-cost after the first call per scheme thanks to
477
+ * Metro's module cache, and a no-op when no loader is registered
478
+ * (tests, or a bundle without rnwind-transformed sources).
479
+ * @param scheme Active scheme name.
480
+ */
481
+ export function loadScheme(scheme: string): void {
482
+ if (schemeLoader) schemeLoader(scheme)
483
+ }
484
+
485
+ /**
486
+ * Register (or re-register) one scheme's atoms in the global registry.
487
+ * Pure property assignment — no iteration, no allocation. The version
488
+ * counter bump invalidates every hoist-level result cache lazily on
489
+ * next read.
490
+ * @param scheme Registry key — `'common'` for the always-loaded
491
+ * fallback, or a variant name (`'dark'`, `'light'`, `'brand'`, ...).
492
+ * @param atoms Plain record keyed by atom name.
493
+ */
494
+ export function registerAtoms(scheme: string, atoms: Record<string, unknown>): void {
495
+ cache.atoms[scheme] = atoms
496
+ atomVersion += 1
497
+ }
498
+
499
+ /**
500
+ * Register the responsive-breakpoint table the manifest module emits at
501
+ * load time. Replaces the prior table — calling with `{}` clears it.
502
+ * Bumps `atomVersion` so any cached lookup invalidates on next read,
503
+ * which matters during a theme HMR cycle that adds/removes breakpoints.
504
+ * @param breakpoints Breakpoint name → minimum-width threshold (px).
505
+ */
506
+ export function registerBreakpoints(breakpoints: Record<string, number>): void {
507
+ const fresh: Partial<Record<string, number>> = Object.create(null)
508
+ const list: BreakpointEntry[] = []
509
+ for (const name of Object.keys(breakpoints)) {
510
+ const minWidth = breakpoints[name]
511
+ if (!Number.isFinite(minWidth) || minWidth <= 0) continue
512
+ fresh[name] = minWidth
513
+ list.push({ name, minWidth })
514
+ }
515
+ list.sort((a, b) => a.minWidth - b.minWidth || a.name.localeCompare(b.name))
516
+ cache.breakpoints = fresh
517
+ cache.breakpointList = list
518
+ atomVersion += 1
519
+ }
520
+
521
+ /**
522
+ * Snapshot of the registered breakpoints, for callers that want to
523
+ * compute their own derivations (e.g. the provider deriving the active
524
+ * breakpoint name). Returns a fresh array — callers can iterate without
525
+ * worrying about concurrent mutation from a manifest reload.
526
+ * @returns Breakpoints sorted by ascending min-width threshold.
527
+ */
528
+ export function getBreakpoints(): readonly BreakpointEntry[] {
529
+ return cache.breakpointList
530
+ }
531
+
532
+ /**
533
+ * Sentinel name returned by {@link activeBreakpointFor} ONLY when no
534
+ * breakpoints are registered at all (bundle without rnwind-transformed
535
+ * sources, fresh test setup). When at least one breakpoint is
536
+ * registered, the function falls back to the smallest registered name
537
+ * instead — so phone-width devices (402 dp on a stock iPhone, well
538
+ * below `sm = 640`) report `activeBreakpoint === 'sm'` rather than the
539
+ * abstract `'base'`. This matches the user expectation that the value
540
+ * is always a real Tailwind breakpoint label they can branch on.
541
+ *
542
+ * Note: this is decoupled from the className filter. `sm:*` atoms
543
+ * still only fire at `windowWidth >= 640` per Tailwind's mobile-first
544
+ * spec — `activeBreakpoint === 'sm'` at 402 means "I'm in the smallest
545
+ * tier", not "`sm:` classes are firing".
546
+ */
547
+ export const BASE_BREAKPOINT = 'base'
548
+
549
+ /**
550
+ * Resolve the currently-active breakpoint name for a width:
551
+ * - `windowWidth >= some threshold` → the highest matching breakpoint name.
552
+ * - below every registered threshold → the smallest registered name.
553
+ * - no breakpoints registered → {@link BASE_BREAKPOINT}.
554
+ * Always returns a string so consumers can branch on it without
555
+ * null-handling.
556
+ * @param windowWidth Live window width in px.
557
+ * @returns Active breakpoint name (never null).
558
+ */
559
+ export function activeBreakpointFor(windowWidth: number): string {
560
+ const list = cache.breakpointList
561
+ if (list.length === 0) return BASE_BREAKPOINT
562
+ let active: string = list[0]!.name
563
+ for (const entry of list) {
564
+ if (windowWidth >= entry.minWidth) active = entry.name
565
+ else break
566
+ }
567
+ return active
568
+ }
569
+
570
+ /**
571
+ * Resolve a className input against the active rnwind context. Hot
572
+ * path:
573
+ * - Array input (build hoist): ONE WeakMap.get + ONE record-access
574
+ * + cached array return. No per-render allocation when there's no
575
+ * userStyle and the hoist has no safe atoms.
576
+ * - String input (dynamic `className={expr}`): tokenise + walk.
577
+ * @param input Hoisted atom list or raw className string.
578
+ * @param ctx Rnwind context — `{scheme, fontScale, insets}` (extra
579
+ * fields ignored). Pass the result of `useRnwind()` directly.
580
+ * @param userStyle Optional caller-supplied style appended last.
581
+ * @param interactState Live active/focus flags from `useInteract()`.
582
+ * @returns Style array for React Native's `style` prop.
583
+ */
584
+ export function lookupCss(
585
+ input: HoistedClassName | string | null | undefined,
586
+ ctx: RnwindState,
587
+ userStyle?: unknown,
588
+ interactState?: InteractState,
589
+ ): readonly unknown[] {
590
+ if (input === null || input === undefined) {
591
+ return userStyle === undefined || userStyle === null ? EMPTY_STYLES : [userStyle]
592
+ }
593
+ const { scheme, insets, fontScale, windowWidth } = ctx
594
+ if (typeof input === 'string') {
595
+ const trimmed = input.trim()
596
+ if (trimmed.length === 0) {
597
+ return userStyle === undefined || userStyle === null ? EMPTY_STYLES : [userStyle]
598
+ }
599
+ const atoms = trimmed.split(/\s+/)
600
+ const out = buildStyleArray(atoms, scheme, stateIndexFor(interactState), insets, fontScale, windowWidth)
601
+ if (userStyle === undefined || userStyle === null) return out
602
+ return [...out, userStyle]
603
+ }
604
+ const base = lookupCached(input, scheme, stateIndexFor(interactState), insets, fontScale, windowWidth)
605
+ if (userStyle === undefined || userStyle === null) return base
606
+ return [...base, userStyle]
607
+ }
608
+
609
+ /** Test-only — clear the global registry between suites. */
610
+ export function __resetLookupCssState(): void {
611
+ for (const key of Object.keys(cache.atoms)) delete cache.atoms[key]
612
+ for (const key of Object.keys(cache.breakpoints)) delete cache.breakpoints[key]
613
+ cache.breakpointList = []
614
+ windowHeightProvider = null
615
+ schemeLoader = null
616
+ WARNED_MISSING_INSETS = false
617
+ WARNED_UNKNOWN_ATOMS.clear()
618
+ atomVersion += 1
619
+ }
620
+
621
+ /**
622
+ * Test-only sugar: accept a single-scheme record and register it as the
623
+ * `common` table.
624
+ * @param record Atom name → value record (registered under `common`).
625
+ */
626
+ export function __registerAtomsFromRecord(record: Record<string, unknown>): void {
627
+ registerAtoms(COMMON_SCHEME, record)
628
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * App-level configuration projected into the type system. Apps extend this
3
+ * interface from their generated `rnwind-types.d.ts` — which rnwind writes
4
+ * alongside the CSS theme on every Metro start — to narrow `Scheme` to the
5
+ * exact scheme names declared in `global.css`.
6
+ *
7
+ * Left empty here so library code stays buildable without a generated
8
+ * augmentation; `Scheme` falls back to `string` under that default.
9
+ * @example
10
+ * ```ts
11
+ * // rnwind-types.d.ts (auto-generated)
12
+ * declare module 'rnwind' {
13
+ * export interface RnwindConfig {
14
+ * themes: readonly ['light', 'dark', 'brand']
15
+ * }
16
+ * }
17
+ * ```
18
+ */
19
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
20
+ export interface RnwindConfig {}
21
+
22
+ /**
23
+ * Type of the `scheme` prop + the value returned by `useScheme()`. Resolves
24
+ * to the literal union declared on {@link RnwindConfig.themes} when the app
25
+ * provides one via `rnwind-types.d.ts`; falls back to `string` otherwise so
26
+ * consumers without generated types keep compiling.
27
+ */
28
+ export type Scheme = RnwindConfig extends { themes: infer T }
29
+ ? T extends readonly (infer S)[]
30
+ ? Extract<S, string>
31
+ : string
32
+ : string