@yahoo/uds-mobile 1.0.0

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 (447) hide show
  1. package/CONTRIBUTING.md +1174 -0
  2. package/README.md +614 -0
  3. package/cli/uds-mobile.js +10 -0
  4. package/dist/_virtual/rolldown_runtime.cjs +30 -0
  5. package/dist/bin/generateTheme.mjs +390 -0
  6. package/dist/bin/mobile/scripts/utils/configToRNMappings.mjs +74 -0
  7. package/dist/bin/uds/dist/fixtures.mjs +404 -0
  8. package/dist/bin/uds/dist/tokens/configs/palette/alwaysPalette.mjs +23 -0
  9. package/dist/bin/uds/dist/tokens/consts/defaultModes.mjs +6 -0
  10. package/dist/bin/uds/dist/tokens/consts/fontDeclarationsMap.mjs +652 -0
  11. package/dist/bin/uds-mobile.mjs +256 -0
  12. package/dist/components/Avatar.cjs +109 -0
  13. package/dist/components/Avatar.d.cts +60 -0
  14. package/dist/components/Avatar.d.cts.map +1 -0
  15. package/dist/components/Avatar.d.mts +60 -0
  16. package/dist/components/Avatar.d.mts.map +1 -0
  17. package/dist/components/Avatar.mjs +109 -0
  18. package/dist/components/Avatar.mjs.map +1 -0
  19. package/dist/components/Badge.cjs +68 -0
  20. package/dist/components/Badge.d.cts +43 -0
  21. package/dist/components/Badge.d.cts.map +1 -0
  22. package/dist/components/Badge.d.mts +43 -0
  23. package/dist/components/Badge.d.mts.map +1 -0
  24. package/dist/components/Badge.mjs +68 -0
  25. package/dist/components/Badge.mjs.map +1 -0
  26. package/dist/components/Box.cjs +114 -0
  27. package/dist/components/Box.d.cts +87 -0
  28. package/dist/components/Box.d.cts.map +1 -0
  29. package/dist/components/Box.d.mts +87 -0
  30. package/dist/components/Box.d.mts.map +1 -0
  31. package/dist/components/Box.mjs +114 -0
  32. package/dist/components/Box.mjs.map +1 -0
  33. package/dist/components/Button.cjs +187 -0
  34. package/dist/components/Button.d.cts +56 -0
  35. package/dist/components/Button.d.cts.map +1 -0
  36. package/dist/components/Button.d.mts +56 -0
  37. package/dist/components/Button.d.mts.map +1 -0
  38. package/dist/components/Button.mjs +186 -0
  39. package/dist/components/Button.mjs.map +1 -0
  40. package/dist/components/Checkbox.cjs +156 -0
  41. package/dist/components/Checkbox.d.cts +48 -0
  42. package/dist/components/Checkbox.d.cts.map +1 -0
  43. package/dist/components/Checkbox.d.mts +48 -0
  44. package/dist/components/Checkbox.d.mts.map +1 -0
  45. package/dist/components/Checkbox.mjs +155 -0
  46. package/dist/components/Checkbox.mjs.map +1 -0
  47. package/dist/components/Chip.cjs +124 -0
  48. package/dist/components/Chip.d.cts +60 -0
  49. package/dist/components/Chip.d.cts.map +1 -0
  50. package/dist/components/Chip.d.mts +60 -0
  51. package/dist/components/Chip.d.mts.map +1 -0
  52. package/dist/components/Chip.mjs +124 -0
  53. package/dist/components/Chip.mjs.map +1 -0
  54. package/dist/components/HStack.cjs +46 -0
  55. package/dist/components/HStack.d.cts +41 -0
  56. package/dist/components/HStack.d.cts.map +1 -0
  57. package/dist/components/HStack.d.mts +41 -0
  58. package/dist/components/HStack.d.mts.map +1 -0
  59. package/dist/components/HStack.mjs +46 -0
  60. package/dist/components/HStack.mjs.map +1 -0
  61. package/dist/components/Icon.cjs +150 -0
  62. package/dist/components/Icon.d.cts +90 -0
  63. package/dist/components/Icon.d.cts.map +1 -0
  64. package/dist/components/Icon.d.mts +90 -0
  65. package/dist/components/Icon.d.mts.map +1 -0
  66. package/dist/components/Icon.mjs +148 -0
  67. package/dist/components/Icon.mjs.map +1 -0
  68. package/dist/components/IconButton.cjs +127 -0
  69. package/dist/components/IconButton.d.cts +46 -0
  70. package/dist/components/IconButton.d.cts.map +1 -0
  71. package/dist/components/IconButton.d.mts +46 -0
  72. package/dist/components/IconButton.d.mts.map +1 -0
  73. package/dist/components/IconButton.mjs +127 -0
  74. package/dist/components/IconButton.mjs.map +1 -0
  75. package/dist/components/IconSlot.cjs +55 -0
  76. package/dist/components/IconSlot.d.cts +45 -0
  77. package/dist/components/IconSlot.d.cts.map +1 -0
  78. package/dist/components/IconSlot.d.mts +45 -0
  79. package/dist/components/IconSlot.d.mts.map +1 -0
  80. package/dist/components/IconSlot.mjs +55 -0
  81. package/dist/components/IconSlot.mjs.map +1 -0
  82. package/dist/components/Image.cjs +104 -0
  83. package/dist/components/Image.d.cts +85 -0
  84. package/dist/components/Image.d.cts.map +1 -0
  85. package/dist/components/Image.d.mts +85 -0
  86. package/dist/components/Image.d.mts.map +1 -0
  87. package/dist/components/Image.mjs +104 -0
  88. package/dist/components/Image.mjs.map +1 -0
  89. package/dist/components/Input.cjs +174 -0
  90. package/dist/components/Input.d.cts +39 -0
  91. package/dist/components/Input.d.cts.map +1 -0
  92. package/dist/components/Input.d.mts +39 -0
  93. package/dist/components/Input.d.mts.map +1 -0
  94. package/dist/components/Input.mjs +174 -0
  95. package/dist/components/Input.mjs.map +1 -0
  96. package/dist/components/Link.cjs +139 -0
  97. package/dist/components/Link.d.cts +45 -0
  98. package/dist/components/Link.d.cts.map +1 -0
  99. package/dist/components/Link.d.mts +45 -0
  100. package/dist/components/Link.d.mts.map +1 -0
  101. package/dist/components/Link.mjs +138 -0
  102. package/dist/components/Link.mjs.map +1 -0
  103. package/dist/components/Pressable.cjs +120 -0
  104. package/dist/components/Pressable.d.cts +90 -0
  105. package/dist/components/Pressable.d.cts.map +1 -0
  106. package/dist/components/Pressable.d.mts +90 -0
  107. package/dist/components/Pressable.d.mts.map +1 -0
  108. package/dist/components/Pressable.mjs +118 -0
  109. package/dist/components/Pressable.mjs.map +1 -0
  110. package/dist/components/Radio.cjs +153 -0
  111. package/dist/components/Radio.d.cts +46 -0
  112. package/dist/components/Radio.d.cts.map +1 -0
  113. package/dist/components/Radio.d.mts +46 -0
  114. package/dist/components/Radio.d.mts.map +1 -0
  115. package/dist/components/Radio.mjs +152 -0
  116. package/dist/components/Radio.mjs.map +1 -0
  117. package/dist/components/Screen.cjs +89 -0
  118. package/dist/components/Screen.d.cts +53 -0
  119. package/dist/components/Screen.d.cts.map +1 -0
  120. package/dist/components/Screen.d.mts +53 -0
  121. package/dist/components/Screen.d.mts.map +1 -0
  122. package/dist/components/Screen.mjs +89 -0
  123. package/dist/components/Screen.mjs.map +1 -0
  124. package/dist/components/Switch.cjs +172 -0
  125. package/dist/components/Switch.d.cts +42 -0
  126. package/dist/components/Switch.d.cts.map +1 -0
  127. package/dist/components/Switch.d.mts +42 -0
  128. package/dist/components/Switch.d.mts.map +1 -0
  129. package/dist/components/Switch.mjs +171 -0
  130. package/dist/components/Switch.mjs.map +1 -0
  131. package/dist/components/Text.cjs +107 -0
  132. package/dist/components/Text.d.cts +96 -0
  133. package/dist/components/Text.d.cts.map +1 -0
  134. package/dist/components/Text.d.mts +96 -0
  135. package/dist/components/Text.d.mts.map +1 -0
  136. package/dist/components/Text.mjs +107 -0
  137. package/dist/components/Text.mjs.map +1 -0
  138. package/dist/components/VStack.cjs +46 -0
  139. package/dist/components/VStack.d.cts +41 -0
  140. package/dist/components/VStack.d.cts.map +1 -0
  141. package/dist/components/VStack.d.mts +41 -0
  142. package/dist/components/VStack.d.mts.map +1 -0
  143. package/dist/components/VStack.mjs +46 -0
  144. package/dist/components/VStack.mjs.map +1 -0
  145. package/dist/icons/dist/glyphMap.cjs +5475 -0
  146. package/dist/icons/dist/glyphMap.d.cts +10 -0
  147. package/dist/icons/dist/glyphMap.d.cts.map +1 -0
  148. package/dist/icons/dist/glyphMap.d.mts +10 -0
  149. package/dist/icons/dist/glyphMap.d.mts.map +1 -0
  150. package/dist/icons/dist/glyphMap.mjs +5474 -0
  151. package/dist/icons/dist/glyphMap.mjs.map +1 -0
  152. package/dist/icons/dist/svgMap.cjs +525 -0
  153. package/dist/icons/dist/svgMap.d.cts +10 -0
  154. package/dist/icons/dist/svgMap.d.cts.map +1 -0
  155. package/dist/icons/dist/svgMap.d.mts +10 -0
  156. package/dist/icons/dist/svgMap.d.mts.map +1 -0
  157. package/dist/icons/dist/svgMap.mjs +524 -0
  158. package/dist/icons/dist/svgMap.mjs.map +1 -0
  159. package/dist/icons/dist/tokens.cjs +13 -0
  160. package/dist/icons/dist/tokens.mjs +13 -0
  161. package/dist/icons/dist/tokens.mjs.map +1 -0
  162. package/dist/icons/dist/types.d.cts +24 -0
  163. package/dist/icons/dist/types.d.cts.map +1 -0
  164. package/dist/icons/dist/types.d.mts +24 -0
  165. package/dist/icons/dist/types.d.mts.map +1 -0
  166. package/dist/motion.cjs +56 -0
  167. package/dist/motion.d.cts +46 -0
  168. package/dist/motion.d.cts.map +1 -0
  169. package/dist/motion.d.mts +46 -0
  170. package/dist/motion.d.mts.map +1 -0
  171. package/dist/motion.mjs +52 -0
  172. package/dist/motion.mjs.map +1 -0
  173. package/dist/types.cjs +1 -0
  174. package/dist/types.d.cts +13 -0
  175. package/dist/types.d.cts.map +1 -0
  176. package/dist/types.d.mts +13 -0
  177. package/dist/types.d.mts.map +1 -0
  178. package/dist/types.mjs +2 -0
  179. package/dist/uds/dist/components/Box.d.cts +3 -0
  180. package/dist/uds/dist/components/Box.d.mts +3 -0
  181. package/dist/uds/dist/components/Divider/Divider.d.cts +3 -0
  182. package/dist/uds/dist/components/Divider/Divider.d.mts +3 -0
  183. package/dist/uds/dist/components/Divider/DividerCore.d.cts +4 -0
  184. package/dist/uds/dist/components/Divider/DividerCore.d.mts +4 -0
  185. package/dist/uds/dist/components/Divider/DividerInternal.d.cts +4 -0
  186. package/dist/uds/dist/components/Divider/DividerInternal.d.mts +4 -0
  187. package/dist/uds/dist/components/Divider/index.d.cts +2 -0
  188. package/dist/uds/dist/components/Divider/index.d.mts +2 -0
  189. package/dist/uds/dist/components/FormLabel.d.cts +3 -0
  190. package/dist/uds/dist/components/FormLabel.d.mts +4 -0
  191. package/dist/uds/dist/components/HStack.d.cts +4 -0
  192. package/dist/uds/dist/components/HStack.d.mts +4 -0
  193. package/dist/uds/dist/components/Icon.d.cts +3 -0
  194. package/dist/uds/dist/components/Icon.d.mts +3 -0
  195. package/dist/uds/dist/components/Image.d.cts +2 -0
  196. package/dist/uds/dist/components/Image.d.mts +3 -0
  197. package/dist/uds/dist/components/Link.d.cts +3 -0
  198. package/dist/uds/dist/components/Link.d.mts +3 -0
  199. package/dist/uds/dist/components/Text.d.cts +3 -0
  200. package/dist/uds/dist/components/Text.d.mts +3 -0
  201. package/dist/uds/dist/components/VStack.d.cts +4 -0
  202. package/dist/uds/dist/components/VStack.d.mts +4 -0
  203. package/dist/uds/dist/components/client/Avatar/Avatar.d.cts +2 -0
  204. package/dist/uds/dist/components/client/Avatar/Avatar.d.mts +3 -0
  205. package/dist/uds/dist/components/client/Avatar/AvatarIcon.d.cts +2 -0
  206. package/dist/uds/dist/components/client/Avatar/AvatarIcon.d.mts +3 -0
  207. package/dist/uds/dist/components/client/Avatar/AvatarImage.d.cts +4 -0
  208. package/dist/uds/dist/components/client/Avatar/AvatarImage.d.mts +5 -0
  209. package/dist/uds/dist/components/client/Avatar/AvatarText.d.cts +3 -0
  210. package/dist/uds/dist/components/client/Avatar/AvatarText.d.mts +4 -0
  211. package/dist/uds/dist/components/client/Avatar/index.d.cts +5 -0
  212. package/dist/uds/dist/components/client/Avatar/index.d.mts +5 -0
  213. package/dist/uds/dist/components/client/Badge.d.cts +3 -0
  214. package/dist/uds/dist/components/client/Badge.d.mts +3 -0
  215. package/dist/uds/dist/components/client/Button.d.cts +3 -0
  216. package/dist/uds/dist/components/client/Button.d.mts +3 -0
  217. package/dist/uds/dist/components/client/Checkbox.d.cts +3 -0
  218. package/dist/uds/dist/components/client/Checkbox.d.mts +3 -0
  219. package/dist/uds/dist/components/client/Chip/Chip.d.cts +4 -0
  220. package/dist/uds/dist/components/client/Chip/Chip.d.mts +4 -0
  221. package/dist/uds/dist/components/client/Chip/ChipBase.d.cts +4 -0
  222. package/dist/uds/dist/components/client/Chip/ChipBase.d.mts +4 -0
  223. package/dist/uds/dist/components/client/Chip/ChipButton.d.cts +4 -0
  224. package/dist/uds/dist/components/client/Chip/ChipButton.d.mts +4 -0
  225. package/dist/uds/dist/components/client/Chip/ChipDismissible.d.cts +4 -0
  226. package/dist/uds/dist/components/client/Chip/ChipDismissible.d.mts +4 -0
  227. package/dist/uds/dist/components/client/Chip/ChipLink.d.cts +4 -0
  228. package/dist/uds/dist/components/client/Chip/ChipLink.d.mts +4 -0
  229. package/dist/uds/dist/components/client/Chip/ChipToggle.d.cts +4 -0
  230. package/dist/uds/dist/components/client/Chip/ChipToggle.d.mts +4 -0
  231. package/dist/uds/dist/components/client/Chip/index.d.cts +6 -0
  232. package/dist/uds/dist/components/client/Chip/index.d.mts +6 -0
  233. package/dist/uds/dist/components/client/IconButton.d.cts +3 -0
  234. package/dist/uds/dist/components/client/IconButton.d.mts +3 -0
  235. package/dist/uds/dist/components/client/Input/Input.d.cts +4 -0
  236. package/dist/uds/dist/components/client/Input/Input.d.mts +4 -0
  237. package/dist/uds/dist/components/client/Input/InputHelpText.d.cts +2 -0
  238. package/dist/uds/dist/components/client/Input/InputHelpText.d.mts +3 -0
  239. package/dist/uds/dist/components/client/Input/InputHelpTextInternal.d.cts +5 -0
  240. package/dist/uds/dist/components/client/Input/InputHelpTextInternal.d.mts +6 -0
  241. package/dist/uds/dist/components/client/Input/index.d.cts +3 -0
  242. package/dist/uds/dist/components/client/Input/index.d.mts +3 -0
  243. package/dist/uds/dist/components/client/Menu/Menu.Content.d.cts +4 -0
  244. package/dist/uds/dist/components/client/Menu/Menu.Content.d.mts +4 -0
  245. package/dist/uds/dist/components/client/Menu/Menu.Divider.d.cts +3 -0
  246. package/dist/uds/dist/components/client/Menu/Menu.Divider.d.mts +3 -0
  247. package/dist/uds/dist/components/client/Menu/Menu.Item.d.cts +4 -0
  248. package/dist/uds/dist/components/client/Menu/Menu.Item.d.mts +4 -0
  249. package/dist/uds/dist/components/client/Menu/Menu.ItemCheckbox.d.cts +4 -0
  250. package/dist/uds/dist/components/client/Menu/Menu.ItemCheckbox.d.mts +4 -0
  251. package/dist/uds/dist/components/client/Menu/Menu.Provider.d.cts +2 -0
  252. package/dist/uds/dist/components/client/Menu/Menu.Provider.d.mts +3 -0
  253. package/dist/uds/dist/components/client/Menu/Menu.Trigger.d.cts +4 -0
  254. package/dist/uds/dist/components/client/Menu/Menu.Trigger.d.mts +4 -0
  255. package/dist/uds/dist/components/client/Menu/Menu.d.cts +2 -0
  256. package/dist/uds/dist/components/client/Menu/Menu.d.mts +2 -0
  257. package/dist/uds/dist/components/client/Menu/Menu.index.d.cts +7 -0
  258. package/dist/uds/dist/components/client/Menu/Menu.index.d.mts +7 -0
  259. package/dist/uds/dist/components/client/Menu/index.d.cts +9 -0
  260. package/dist/uds/dist/components/client/Menu/index.d.mts +9 -0
  261. package/dist/uds/dist/components/client/Pressable.d.cts +3 -0
  262. package/dist/uds/dist/components/client/Pressable.d.mts +3 -0
  263. package/dist/uds/dist/components/client/Radio/Radio.d.cts +3 -0
  264. package/dist/uds/dist/components/client/Radio/Radio.d.mts +3 -0
  265. package/dist/uds/dist/components/client/Radio/RadioGroupProvider.d.cts +3 -0
  266. package/dist/uds/dist/components/client/Radio/RadioGroupProvider.d.mts +3 -0
  267. package/dist/uds/dist/components/client/Radio/index.d.cts +3 -0
  268. package/dist/uds/dist/components/client/Radio/index.d.mts +3 -0
  269. package/dist/uds/dist/components/client/SpringMotionConfig.d.cts +3 -0
  270. package/dist/uds/dist/components/client/SpringMotionConfig.d.mts +3 -0
  271. package/dist/uds/dist/components/client/Switch.d.cts +3 -0
  272. package/dist/uds/dist/components/client/Switch.d.mts +3 -0
  273. package/dist/uds/dist/components/client/index.d.cts +33 -0
  274. package/dist/uds/dist/components/client/index.d.mts +33 -0
  275. package/dist/uds/dist/components/index.d.cts +40 -0
  276. package/dist/uds/dist/components/index.d.mts +40 -0
  277. package/dist/uds/dist/index.d.cts +46 -0
  278. package/dist/uds/dist/index.d.mts +46 -0
  279. package/dist/uds/dist/styles/styler.d.cts +2 -0
  280. package/dist/uds/dist/styles/styler.d.mts +2 -0
  281. package/dist/uds/dist/styles/stylerTypes.d.cts +2 -0
  282. package/dist/uds/dist/styles/stylerTypes.d.mts +2 -0
  283. package/dist/uds/dist/tokens/automation/configs/avatar.d.cts +2 -0
  284. package/dist/uds/dist/tokens/automation/configs/avatar.d.mts +2 -0
  285. package/dist/uds/dist/tokens/automation/properties.d.cts +3 -0
  286. package/dist/uds/dist/tokens/automation/properties.d.mts +3 -0
  287. package/dist/uds/dist/tokens/automation/types/ComponentConfig.d.cts +3 -0
  288. package/dist/uds/dist/tokens/automation/types/ComponentConfig.d.mts +3 -0
  289. package/dist/uds/dist/tokens/configs/motion.cjs +109 -0
  290. package/dist/uds/dist/tokens/configs/motion.d.cts +20 -0
  291. package/dist/uds/dist/tokens/configs/motion.d.cts.map +1 -0
  292. package/dist/uds/dist/tokens/configs/motion.d.mts +20 -0
  293. package/dist/uds/dist/tokens/configs/motion.d.mts.map +1 -0
  294. package/dist/uds/dist/tokens/configs/motion.mjs +108 -0
  295. package/dist/uds/dist/tokens/configs/motion.mjs.map +1 -0
  296. package/dist/uds/dist/tokens/configs/palette/alwaysPalette.d.cts +32 -0
  297. package/dist/uds/dist/tokens/configs/palette/alwaysPalette.d.cts.map +1 -0
  298. package/dist/uds/dist/tokens/configs/palette/alwaysPalette.d.mts +32 -0
  299. package/dist/uds/dist/tokens/configs/palette/alwaysPalette.d.mts.map +1 -0
  300. package/dist/uds/dist/tokens/types.d.cts +426 -0
  301. package/dist/uds/dist/tokens/types.d.cts.map +1 -0
  302. package/dist/uds/dist/tokens/types.d.mts +426 -0
  303. package/dist/uds/dist/tokens/types.d.mts.map +1 -0
  304. package/dist/uds/dist/types.d.cts +2 -0
  305. package/dist/uds/dist/types.d.mts +2 -0
  306. package/fonts/centra-no2-black-italic.otf +0 -0
  307. package/fonts/centra-no2-black.otf +0 -0
  308. package/fonts/centra-no2-bold-italic.otf +0 -0
  309. package/fonts/centra-no2-bold.otf +0 -0
  310. package/fonts/centra-no2-book-italic.otf +0 -0
  311. package/fonts/centra-no2-book.otf +0 -0
  312. package/fonts/centra-no2-extrabold-italic.otf +0 -0
  313. package/fonts/centra-no2-extrabold.otf +0 -0
  314. package/fonts/centra-no2-hairline-italic.otf +0 -0
  315. package/fonts/centra-no2-hairline.otf +0 -0
  316. package/fonts/centra-no2-light-italic.otf +0 -0
  317. package/fonts/centra-no2-light.otf +0 -0
  318. package/fonts/centra-no2-medium-italic.otf +0 -0
  319. package/fonts/centra-no2-medium.otf +0 -0
  320. package/fonts/centra-no2-thin-italic.otf +0 -0
  321. package/fonts/centra-no2-thin.otf +0 -0
  322. package/fonts/gelica-black-italic.otf +0 -0
  323. package/fonts/gelica-black.otf +0 -0
  324. package/fonts/gelica-bold-italic.otf +0 -0
  325. package/fonts/gelica-bold.otf +0 -0
  326. package/fonts/gelica-extra-light-italic.otf +0 -0
  327. package/fonts/gelica-extra-light.otf +0 -0
  328. package/fonts/gelica-light-italic.otf +0 -0
  329. package/fonts/gelica-light.otf +0 -0
  330. package/fonts/gelica-medium-italic.otf +0 -0
  331. package/fonts/gelica-medium.otf +0 -0
  332. package/fonts/gelica-regular-italic.otf +0 -0
  333. package/fonts/gelica-regular.otf +0 -0
  334. package/fonts/gelica-semi-bold-italic.otf +0 -0
  335. package/fonts/gelica-semi-bold.otf +0 -0
  336. package/fonts/index.cjs +270 -0
  337. package/fonts/index.d.ts +10 -0
  338. package/fonts/index.mjs +272 -0
  339. package/fonts/inter-black.ttf +0 -0
  340. package/fonts/inter-bold.ttf +0 -0
  341. package/fonts/inter-extra-bold.ttf +0 -0
  342. package/fonts/inter-extra-light.ttf +0 -0
  343. package/fonts/inter-light.ttf +0 -0
  344. package/fonts/inter-medium.ttf +0 -0
  345. package/fonts/inter-regular.ttf +0 -0
  346. package/fonts/inter-semi-bold.ttf +0 -0
  347. package/fonts/inter-thin.ttf +0 -0
  348. package/fonts/roboto-mono-bold-italic.ttf +0 -0
  349. package/fonts/roboto-mono-bold.ttf +0 -0
  350. package/fonts/roboto-mono-light-italic.ttf +0 -0
  351. package/fonts/roboto-mono-light.ttf +0 -0
  352. package/fonts/roboto-mono-medium-italic.ttf +0 -0
  353. package/fonts/roboto-mono-medium.ttf +0 -0
  354. package/fonts/roboto-mono-regular-italic.ttf +0 -0
  355. package/fonts/roboto-mono-regular.ttf +0 -0
  356. package/fonts/roboto-mono-thin-italic.ttf +0 -0
  357. package/fonts/roboto-mono-thin.ttf +0 -0
  358. package/fonts/uds-icons.ttf +0 -0
  359. package/fonts/yahoo-product-sans-bold.otf +0 -0
  360. package/fonts/yahoo-product-sans-extended-black-italic.ttf +0 -0
  361. package/fonts/yahoo-product-sans-extended-black.ttf +0 -0
  362. package/fonts/yahoo-product-sans-extended-bold-italic.ttf +0 -0
  363. package/fonts/yahoo-product-sans-extended-bold.ttf +0 -0
  364. package/fonts/yahoo-product-sans-extended-light-italic.ttf +0 -0
  365. package/fonts/yahoo-product-sans-extended-light.ttf +0 -0
  366. package/fonts/yahoo-product-sans-extended-medium-italic.ttf +0 -0
  367. package/fonts/yahoo-product-sans-extended-medium.ttf +0 -0
  368. package/fonts/yahoo-product-sans-extended-regular-italic.ttf +0 -0
  369. package/fonts/yahoo-product-sans-extended-regular.ttf +0 -0
  370. package/fonts/yahoo-product-sans-extended-semibold-italic.ttf +0 -0
  371. package/fonts/yahoo-product-sans-extended-semibold.ttf +0 -0
  372. package/fonts/yahoo-product-sans-medium.otf +0 -0
  373. package/fonts/yahoo-product-sans-regular.otf +0 -0
  374. package/fonts/yahoo-sans-beta-bold.otf +0 -0
  375. package/fonts/yahoo-sans-beta-medium.otf +0 -0
  376. package/fonts/yahoo-sans-beta-regular.otf +0 -0
  377. package/fonts/yahoo-sans-black.otf +0 -0
  378. package/fonts/yahoo-sans-bold.otf +0 -0
  379. package/fonts/yahoo-sans-condensed-black.otf +0 -0
  380. package/fonts/yahoo-sans-condensed-bold.otf +0 -0
  381. package/fonts/yahoo-sans-condensed-light.otf +0 -0
  382. package/fonts/yahoo-sans-condensed-medium.otf +0 -0
  383. package/fonts/yahoo-sans-condensed-regular.otf +0 -0
  384. package/fonts/yahoo-sans-condensed-xbold.ttf +0 -0
  385. package/fonts/yahoo-sans-cr4-bold.ttf +0 -0
  386. package/fonts/yahoo-sans-cr4-medium.ttf +0 -0
  387. package/fonts/yahoo-sans-cr4-regular.ttf +0 -0
  388. package/fonts/yahoo-sans-extrabold.otf +0 -0
  389. package/fonts/yahoo-sans-extralight.otf +0 -0
  390. package/fonts/yahoo-sans-italic.otf +0 -0
  391. package/fonts/yahoo-sans-light.otf +0 -0
  392. package/fonts/yahoo-sans-medium.otf +0 -0
  393. package/fonts/yahoo-sans-regular-italic.otf +0 -0
  394. package/fonts/yahoo-sans-regular.otf +0 -0
  395. package/fonts/yahoo-sans-semibold.otf +0 -0
  396. package/fonts/yahoo-serif-display-black.otf +0 -0
  397. package/fonts/yahoo-serif-display-bold.otf +0 -0
  398. package/fonts/yahoo-serif-display-extrabold.otf +0 -0
  399. package/fonts/yahoo-serif-display-light.otf +0 -0
  400. package/fonts/yahoo-serif-display-regular.otf +0 -0
  401. package/fonts/yahoo-serif-text-bold-italic.ttf +0 -0
  402. package/fonts/yahoo-serif-text-bold.otf +0 -0
  403. package/fonts/yahoo-serif-text-italic.otf +0 -0
  404. package/fonts/yahoo-serif-text-regular.otf +0 -0
  405. package/fonts/yas-black-italic.otf +0 -0
  406. package/fonts/yas-black.otf +0 -0
  407. package/fonts/yas-bold-italic.otf +0 -0
  408. package/fonts/yas-bold.otf +0 -0
  409. package/fonts/yas-condensed-black-italic.otf +0 -0
  410. package/fonts/yas-condensed-black.otf +0 -0
  411. package/fonts/yas-condensed-bold-italic.otf +0 -0
  412. package/fonts/yas-condensed-bold.otf +0 -0
  413. package/fonts/yas-condensed-light-italic.otf +0 -0
  414. package/fonts/yas-condensed-light.otf +0 -0
  415. package/fonts/yas-condensed-medium-italic.otf +0 -0
  416. package/fonts/yas-condensed-medium.otf +0 -0
  417. package/fonts/yas-condensed-regular-italic.otf +0 -0
  418. package/fonts/yas-condensed-regular.otf +0 -0
  419. package/fonts/yas-condensed-semibold-italic.otf +0 -0
  420. package/fonts/yas-condensed-semibold.otf +0 -0
  421. package/fonts/yas-extended-black-italic.otf +0 -0
  422. package/fonts/yas-extended-black.otf +0 -0
  423. package/fonts/yas-extended-bold-italic.otf +0 -0
  424. package/fonts/yas-extended-bold.otf +0 -0
  425. package/fonts/yas-extended-light-italic.otf +0 -0
  426. package/fonts/yas-extended-light.otf +0 -0
  427. package/fonts/yas-extended-medium-italic.otf +0 -0
  428. package/fonts/yas-extended-medium.otf +0 -0
  429. package/fonts/yas-extended-regular-italic.otf +0 -0
  430. package/fonts/yas-extended-regular.otf +0 -0
  431. package/fonts/yas-extended-semibold-italic.otf +0 -0
  432. package/fonts/yas-extended-semibold.otf +0 -0
  433. package/fonts/yas-light-italic.otf +0 -0
  434. package/fonts/yas-light.otf +0 -0
  435. package/fonts/yas-medium-italic.otf +0 -0
  436. package/fonts/yas-medium.otf +0 -0
  437. package/fonts/yas-regular-italic.otf +0 -0
  438. package/fonts/yas-regular.otf +0 -0
  439. package/fonts/yas-semibold-italic.otf +0 -0
  440. package/fonts/yas-semibold.otf +0 -0
  441. package/generated/styles.cjs +4510 -0
  442. package/generated/styles.d.cts +1 -0
  443. package/generated/styles.d.mts +1 -0
  444. package/generated/styles.d.ts +2965 -0
  445. package/generated/styles.mjs +4510 -0
  446. package/generated/unistyles.d.ts +4320 -0
  447. package/package.json +308 -0
@@ -0,0 +1,1174 @@
1
+ # Contributing to @yahoo/uds-mobile
2
+
3
+ This guide covers the internal architecture and development workflow for the UDS Mobile package.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Architecture Overview](#architecture-overview)
8
+ - [Architecture Proposals](#architecture-proposals)
9
+ - [Dependency Bundling](#dependency-bundling)
10
+ - [Generated Files](#generated-files)
11
+ - [Code Generation Pipeline](#code-generation-pipeline)
12
+ - [Theme Generation](#theme-generation)
13
+ - [Component Styling System](#component-styling-system)
14
+ - [Unistyles Patterns](#unistyles-patterns)
15
+ - [Reanimated + Unistyles](#reanimated--unistyles)
16
+ - [Development Workflow](#development-workflow)
17
+ - [Adding New Components](#adding-new-components)
18
+ - [Debugging](#debugging)
19
+
20
+ ## Architecture Overview
21
+
22
+ The `@yahoo/uds-mobile` package provides React Native components styled with [Unistyles](https://www.unistyl.es//). The package has two distinct concerns:
23
+
24
+ 1. **Library Code** (`src/`): Components, hooks, and utilities
25
+ 2. **Generated Code** (`generated/`): Auto-generated styles and types from UDS tokens
26
+
27
+ ```
28
+ packages/mobile/
29
+ ├── bin/ # CLI tools for consumers
30
+ │ ├── uds-mobile.ts # Main CLI entry (sync command)
31
+ │ └── generateTheme.ts # Theme generation logic
32
+ ├── scripts/ # Internal code generation
33
+ │ ├── generate.ts # Main orchestrator
34
+ │ ├── generateStyles.ts # Generates styles.ts
35
+ │ ├── generateTypes.ts # Generates unistyles.d.ts
36
+ │ ├── generateFonts.ts # Generates font manifests
37
+ │ └── utils/ # Generation utilities
38
+ ├── src/
39
+ │ ├── components/ # React Native components
40
+ │ ├── generated/ # AUTO-GENERATED (do not edit)
41
+ │ │ ├── styles.ts # Unistyles variants
42
+ │ │ └── unistyles.d.ts # Type declarations
43
+ │ ├── types.ts # Exported types
44
+ │ ├── motion.ts # Animation utilities
45
+ │ └── index.ts # Public exports
46
+ ├── fonts/ # Font files + generated manifests
47
+ └── docs/
48
+ ├── proposals/ # Architecture proposals and recommendations
49
+ └── *.md # Architecture decision records and issue documentation
50
+ ```
51
+
52
+ ## Architecture Proposals
53
+
54
+ See [docs/proposals/](./docs/proposals/) for architectural proposals and recommendations for improving the mobile package and UDS ecosystem:
55
+
56
+ - **[PACKAGE_DECOMPOSITION_BENEFITS.md](./docs/proposals/PACKAGE_DECOMPOSITION_BENEFITS.md)** - Proposal to extract shared types, fixtures, and motion tokens into separate packages
57
+ - **[CONFIG_TRANSFORMATION_ARCHITECTURE.md](./docs/proposals/CONFIG_TRANSFORMATION_ARCHITECTURE.md)** - Proposal for platform-specific config transformation architecture
58
+ - **[HARDCODED_VALUES.md](./docs/proposals/HARDCODED_VALUES.md)** - Documentation of hardcoded values that should come from design tokens
59
+
60
+ ## Dependency Bundling
61
+
62
+ The mobile package bundles both `@yahoo/uds` and `@yahoo/uds-icons` into its distribution. This means consumers do **not** need to install these packages separately.
63
+
64
+ ### What Gets Bundled
65
+
66
+ - **Runtime JS**: Both packages' JavaScript code via `noExternal: ['@yahoo/uds', '@yahoo/uds-icons']`
67
+ - **TypeScript types**: Both packages' type definitions via `dts.resolve: ['@yahoo/uds', '@yahoo/uds-icons']`
68
+
69
+ This produces two folders in `dist/`:
70
+
71
+ - `dist/uds/` - Bundled `@yahoo/uds` code and types
72
+ - `dist/icons/` - Bundled `@yahoo/uds-icons` code and types
73
+
74
+ ### Why Both Packages Are Bundled Together
75
+
76
+ We bundle both packages because of a technical constraint in TypeScript declaration bundling: **you cannot bundle `@yahoo/uds` types without also bundling `@yahoo/uds-icons` types**.
77
+
78
+ The `@yahoo/uds` web package has components that directly import from `@yahoo/uds-icons` (e.g., `ChipDismissible` imports `Cross`, `Menu.ItemCheckbox` imports `Check`). When `dts.resolve` bundles `@yahoo/uds` types, it follows these import references transitively and automatically bundles `@yahoo/uds-icons` types as well.
79
+
80
+ There is no way to configure the bundler to "bundle A but keep B external" when A references B - it's all-or-nothing.
81
+
82
+ **See [docs/BUNDLING_UDS_AND_ICONS.md](./docs/BUNDLING_UDS_AND_ICONS.md) for:**
83
+
84
+ - Detailed technical explanation
85
+ - Why standard solutions (external array, subpath imports) don't work
86
+ - Future roadmap for making `@yahoo/uds-icons` a peer dependency
87
+
88
+ ## Generated Files
89
+
90
+ ### `generated/styles.ts`
91
+
92
+ This is the most important generated file. It contains all Unistyles stylesheets that map UDS design tokens to React Native styles.
93
+
94
+ **What it contains:**
95
+
96
+ 1. **Foundation styles** (`styles.foundation`): Base style variants for layout props
97
+ - `backgroundColor`, `borderRadius`, `spacing`, `color`, `fontFamily`, etc.
98
+ - Maps UDS token names to theme paths (e.g., `'primary'` → `theme.colors.background['primary']`)
99
+
100
+ 2. **Component styles** (`avatarStyles`, `buttonStyles`, etc.): Per-component stylesheets
101
+ - Uses Unistyles `variants` and `compoundVariants` for state management
102
+ - Each component has layers: `root`, `text`, `icon`, etc. matching structure from UDS config.
103
+
104
+ **Example input** (from `uds.config.ts` - see `packages/configurator/uds.config.ts`):
105
+
106
+ ```typescript
107
+ import type { UniversalTokensConfig } from '@yahoo/uds';
108
+
109
+ export const config: UniversalTokensConfig = {
110
+ // Component configs use path-based keys: '{dimension}/{value}/{layer}'
111
+ button: {
112
+ defaults: {
113
+ size: 'md',
114
+ variant: 'primary',
115
+ },
116
+ variables: {
117
+ // Size variants
118
+ 'size/lg/root': {
119
+ gap: {
120
+ rest: { type: 'spacingAliases', value: '2', valueType: 'alias' },
121
+ },
122
+ spacingHorizontal: {
123
+ rest: { type: 'spacingAliases', value: '5', valueType: 'alias' },
124
+ },
125
+ textVariant: {
126
+ rest: { type: 'textVariants', value: 'label1', valueType: 'alias' },
127
+ },
128
+ },
129
+ 'size/md/root': {
130
+ gap: {
131
+ rest: { type: 'spacingAliases', value: '1.5', valueType: 'alias' },
132
+ },
133
+ spacingHorizontal: {
134
+ rest: { type: 'spacingAliases', value: '4', valueType: 'alias' },
135
+ },
136
+ },
137
+ // Variant styles with states (rest, pressed, disabled)
138
+ 'variant/primary/root': {
139
+ backgroundColor: {
140
+ rest: { type: 'backgroundPaletteColors', value: 'accent', valueType: 'alias' },
141
+ pressed: { type: 'spectrumColors', value: 'carbon-5', valueType: 'alias' },
142
+ disabled: { type: 'backgroundPaletteColors', value: 'accent', valueType: 'alias' },
143
+ },
144
+ borderRadius: {
145
+ rest: { type: 'borderRadii', value: 'md', valueType: 'alias' },
146
+ },
147
+ },
148
+ 'variant/primary/icon': {
149
+ color: {
150
+ rest: { type: 'foregroundPaletteColors', value: 'on-color', valueType: 'alias' },
151
+ },
152
+ },
153
+ },
154
+ },
155
+ // ... other components (avatar, badge, checkbox, etc.)
156
+ };
157
+ ```
158
+
159
+ **Example output** (generated `styles.ts`):
160
+
161
+ ```typescript
162
+ // Foundation variants
163
+ export const styles = StyleSheet.create((theme) => ({
164
+ foundation: {
165
+ variants: {
166
+ backgroundColor: {
167
+ primary: { backgroundColor: theme.colors.background['primary'] },
168
+ secondary: { backgroundColor: theme.colors.background['secondary'] },
169
+ // ...
170
+ },
171
+ spacing: {
172
+ '4': { padding: theme.spacing['4'] },
173
+ // ...
174
+ },
175
+ },
176
+ },
177
+ }));
178
+
179
+ // Component variants
180
+ export const buttonStyles = StyleSheet.create((theme) => ({
181
+ root: {
182
+ variants: {
183
+ size: {
184
+ lg: theme.components['button/size/lg/root/rest'],
185
+ md: theme.components['button/size/md/root/rest'],
186
+ },
187
+ variant: {
188
+ primary: theme.components['button/variant/primary/root/rest'],
189
+ // ...
190
+ },
191
+ disabled: { true: {} },
192
+ pressed: { true: {} },
193
+ },
194
+ compoundVariants: [
195
+ {
196
+ variant: 'primary',
197
+ pressed: true,
198
+ styles: theme.components['button/variant/primary/root/pressed'],
199
+ },
200
+ // ...
201
+ ],
202
+ },
203
+ }));
204
+ ```
205
+
206
+ ### Web vs Mobile: Generated Styles Comparison
207
+
208
+ The mobile `styles.ts` serves the same purpose as `packages/uds/src/styles/variants.ts` on web, but with key architectural differences:
209
+
210
+ **Web (`variants.ts`)** - Maps UDS props to **CSS class names**:
211
+
212
+ ```typescript
213
+ // Web uses Tailwind-style class names
214
+ export const variants = {
215
+ backgroundColor: {
216
+ primary: 'bg-primary', // CSS class
217
+ secondary: 'bg-secondary',
218
+ accent: 'bg-accent',
219
+ },
220
+ spacing: {
221
+ '4': 'p-4', // Tailwind padding class
222
+ },
223
+ borderRadius: {
224
+ md: 'rounded-md',
225
+ },
226
+ };
227
+ ```
228
+
229
+ **Mobile (`styles.ts`)** - Maps UDS props to **React Native style objects**:
230
+
231
+ ```typescript
232
+ // Mobile uses Unistyles theme references
233
+ export const styles = StyleSheet.create((theme) => ({
234
+ foundation: {
235
+ variants: {
236
+ backgroundColor: {
237
+ primary: { backgroundColor: theme.colors.background['primary'] }, // RN style
238
+ secondary: { backgroundColor: theme.colors.background['secondary'] },
239
+ },
240
+ spacing: {
241
+ '4': { padding: theme.spacing['4'] }, // Numeric value from theme
242
+ },
243
+ borderRadius: {
244
+ md: { borderRadius: theme.borderRadius['md'] },
245
+ },
246
+ },
247
+ },
248
+ }));
249
+ ```
250
+
251
+ | Aspect | Web | Mobile |
252
+ | ------------- | ------------------------------------------------- | ------------------------------------------------------------- |
253
+ | Output format | CSS class names (`'bg-primary'`) | RN style objects (`{ backgroundColor: ... }`) |
254
+ | Theming | CSS custom properties (`var(--color-bg-primary)`) | Unistyles theme object (`theme.colors.background['primary']`) |
255
+ | Dark mode | CSS class toggle (`.dark`) | Unistyles theme switching |
256
+ | File location | `packages/uds/src/styles/variants.ts` | `packages/mobile/generated/styles.ts` |
257
+
258
+ ### Component Styles Comparison
259
+
260
+ For component-level styles, the pattern is similar but maps to component-specific theme values:
261
+
262
+ **Web (`autoVariants.ts`)** - Maps component variants to **CSS class names**:
263
+
264
+ ```typescript
265
+ // packages/uds/generated/autoVariants.ts
266
+ export const autoVariants = {
267
+ buttonVariantRoot: {
268
+ primary: 'uds-button-variant-primary-root', // CSS class
269
+ secondary: 'uds-button-variant-secondary-root',
270
+ brand: 'uds-button-variant-brand-root',
271
+ },
272
+ buttonSizeRoot: {
273
+ lg: 'uds-button-size-lg-root',
274
+ md: 'uds-button-size-md-root',
275
+ sm: 'uds-button-size-sm-root',
276
+ },
277
+ buttonVariantIcon: {
278
+ primary: 'uds-button-variant-primary-icon',
279
+ secondary: 'uds-button-variant-secondary-icon',
280
+ },
281
+ };
282
+ ```
283
+
284
+ **Mobile (`styles.ts`)** - Maps component variants to **theme component style objects**:
285
+
286
+ ```typescript
287
+ // packages/mobile/generated/styles.ts
288
+ export const buttonStyles = StyleSheet.create((theme) => ({
289
+ root: {
290
+ variants: {
291
+ size: {
292
+ lg: theme.components['button/size/lg/root/rest'], // RN style object
293
+ md: theme.components['button/size/md/root/rest'],
294
+ sm: theme.components['button/size/sm/root/rest'],
295
+ },
296
+ variant: {
297
+ primary: theme.components['button/variant/primary/root/rest'],
298
+ secondary: theme.components['button/variant/secondary/root/rest'],
299
+ brand: theme.components['button/variant/brand/root/rest'],
300
+ },
301
+ disabled: { true: {} },
302
+ pressed: { true: {} },
303
+ },
304
+ compoundVariants: [
305
+ {
306
+ variant: 'primary',
307
+ pressed: true,
308
+ styles: theme.components['button/variant/primary/root/pressed'],
309
+ },
310
+ {
311
+ variant: 'primary',
312
+ disabled: true,
313
+ styles: theme.components['button/variant/primary/root/disabled'],
314
+ },
315
+ ],
316
+ },
317
+ text: {
318
+ variants: {
319
+ variant: {
320
+ primary: theme.components['button/variant/primary/text/rest'],
321
+ secondary: theme.components['button/variant/secondary/text/rest'],
322
+ },
323
+ },
324
+ },
325
+ icon: {
326
+ variants: {
327
+ size: {
328
+ lg: theme.components['button/size/lg/icon/rest'],
329
+ md: theme.components['button/size/md/icon/rest'],
330
+ },
331
+ variant: {
332
+ primary: theme.components['button/variant/primary/icon/rest'],
333
+ secondary: theme.components['button/variant/secondary/icon/rest'],
334
+ },
335
+ },
336
+ },
337
+ }));
338
+ ```
339
+
340
+ | Aspect | Web | Mobile |
341
+ | -------------- | ---------------------------------------- | ---------------------------------------------------- |
342
+ | Key format | camelCase (`buttonVariantRoot`) | Slash-separated (`button/variant/primary/root/rest`) |
343
+ | State handling | Separate class toggle | `compoundVariants` with pressed/disabled states |
344
+ | Multi-layer | Separate keys per layer (`Root`, `Icon`) | Nested style objects (`root`, `text`, `icon`) |
345
+ | Theme access | CSS variables in classes | Direct theme object reference |
346
+
347
+ ### Generated Theme Shape
348
+
349
+ The theme exists in two forms:
350
+
351
+ 1. **TypeScript types** (`generated/unistyles.d.ts`) - Generated by `scripts/generateTypes.ts` during package development. These provide full type safety for component development without needing actual runtime values. This is what allows IDE autocomplete and type checking in `styles.ts`.
352
+
353
+ 2. **JavaScript runtime values** - Generated when consumers run `uds-mobile sync`. This creates the actual theme object with real color values, spacing numbers, etc. in their app (e.g., `lib/unistyles.uds.ts`).
354
+
355
+ This separation means we can develop type-safe components in the package without bundling theme values, while consumers get their own themed values at sync time.
356
+
357
+ Here's the theme shape (from the generated types):
358
+
359
+ ```typescript
360
+ // Generated theme structure (simplified)
361
+ interface AppTheme {
362
+ // Foundation tokens
363
+ colors: {
364
+ background: { primary: string; secondary: string; brand: string /* ... */ };
365
+ foreground: { primary: string; secondary: string /* ... */ };
366
+ line: { primary: string; secondary: string /* ... */ };
367
+ spectrum: { 'gray-0': string; 'gray-1': string /* ... */ };
368
+ };
369
+ spacing: { '0': number; '1': number; '2': number /* ... */ };
370
+ borderRadius: { none: number; sm: number; md: number; lg: number; full: number };
371
+ borderWidth: { none: number; sm: number; md: number /* ... */ };
372
+ iconSize: { sm: number; md: number; lg: number /* ... */ };
373
+ typography: { 'body-md': TypographyVariant; 'heading-lg': TypographyVariant /* ... */ };
374
+ shadow: { sm: ShadowValue; md: ShadowValue /* ... */ };
375
+ font: { 'YahooSans-Bold': string; 'YahooSans-Regular': string /* ... */ };
376
+
377
+ // Component-specific styles (flat key structure)
378
+ components: {
379
+ 'button/size/lg/root/rest': { gap: number; paddingHorizontal: number; paddingVertical: number };
380
+ 'button/size/md/root/rest': { gap: number; paddingHorizontal: number; paddingVertical: number };
381
+ 'button/variant/primary/root/rest': { backgroundColor: string /* ... */ };
382
+ 'button/variant/primary/root/pressed': { backgroundColor: string /* ... */ };
383
+ 'button/variant/primary/root/disabled': { opacity: number /* ... */ };
384
+ 'button/variant/primary/text/rest': { color: string /* ... */ };
385
+ 'button/variant/primary/icon/rest': { color: string /* ... */ };
386
+ // ... hundreds more component style entries
387
+ };
388
+ }
389
+ ```
390
+
391
+ #### Component Key Format
392
+
393
+ Component styles use a slash-separated key format:
394
+
395
+ ```
396
+ {component}/{dimension}/{value}/{layer}/{state}
397
+ ```
398
+
399
+ | Segment | Description | Examples |
400
+ | ----------- | ------------------------------------------------- | ---------------------------------- |
401
+ | `component` | Component name | `button`, `badge`, `avatar` |
402
+ | `dimension` | Variant dimension (size, variant, or nested type) | `size`, `variant`, `icon/variant` |
403
+ | `value` | Specific value for that dimension | `lg`, `md`, `primary`, `secondary` |
404
+ | `layer` | UI layer within the component | `root`, `text`, `icon`, `rootText` |
405
+ | `state` | Interaction state | `rest`, `pressed`, `disabled` |
406
+
407
+ Examples:
408
+
409
+ - `button/size/lg/root/rest` → Button, size=lg, root layer, rest state
410
+ - `button/variant/primary/icon/pressed` → Button, variant=primary, icon layer, pressed state
411
+ - `avatar/icon/variant/secondary/root/rest` → Avatar (icon type), variant=secondary, root layer
412
+
413
+ This flat structure allows `styles.ts` to reference exact theme values:
414
+
415
+ ```typescript
416
+ // In styles.ts
417
+ export const buttonStyles = StyleSheet.create((theme) => ({
418
+ root: {
419
+ variants: {
420
+ size: {
421
+ lg: theme.components['button/size/lg/root/rest'], // ← Direct lookup
422
+ md: theme.components['button/size/md/root/rest'],
423
+ },
424
+ },
425
+ },
426
+ }));
427
+ ```
428
+
429
+ ### How Unistyles Variants Work
430
+
431
+ Unistyles variants allow styles to change based on props passed to `useVariants()`. The structure can be confusing at first because of the nesting, so here's a breakdown:
432
+
433
+ #### Basic Structure
434
+
435
+ ```typescript
436
+ const buttonStyles = StyleSheet.create((theme) => ({
437
+ // Each top-level key is a "layer" (root, text, icon, etc.)
438
+ root: {
439
+ // Base styles applied to ALL variants
440
+ flexDirection: 'row',
441
+ alignItems: 'center',
442
+
443
+ // Variants object defines conditional styles
444
+ variants: {
445
+ // Each key here is a "variant dimension" (size, variant, disabled, etc.)
446
+ size: {
447
+ // Each nested key is a possible value for that dimension
448
+ lg: { paddingHorizontal: 24, paddingVertical: 16 },
449
+ md: { paddingHorizontal: 16, paddingVertical: 12 },
450
+ sm: { paddingHorizontal: 12, paddingVertical: 8 },
451
+ },
452
+ variant: {
453
+ primary: { backgroundColor: theme.colors.background.brand },
454
+ secondary: { backgroundColor: theme.colors.background.secondary },
455
+ },
456
+ // Boolean variants use `true` as the key
457
+ disabled: {
458
+ true: { opacity: 0.5 },
459
+ },
460
+ pressed: {
461
+ true: {}, // Empty - handled by compoundVariants
462
+ },
463
+ },
464
+ },
465
+ }));
466
+ ```
467
+
468
+ #### Using Variants in Components
469
+
470
+ ```typescript
471
+ function Button({ size = 'md', variant = 'primary', disabled }) {
472
+ const [pressed, setPressed] = useState(false);
473
+
474
+ // Call useVariants with current prop values
475
+ // This "selects" which variant styles to apply
476
+ buttonStyles.useVariants({
477
+ size, // 'lg' | 'md' | 'sm'
478
+ variant, // 'primary' | 'secondary' | ...
479
+ disabled, // true | false
480
+ pressed, // true | false
481
+ });
482
+
483
+ return (
484
+ <Pressable
485
+ style={buttonStyles.root} // Styles auto-update based on useVariants
486
+ onPressIn={() => setPressed(true)}
487
+ onPressOut={() => setPressed(false)}
488
+ >
489
+ <Text style={buttonStyles.text}>Press me</Text>
490
+ </Pressable>
491
+ );
492
+ }
493
+ ```
494
+
495
+ #### Style Resolution
496
+
497
+ When `useVariants({ size: 'lg', variant: 'primary', disabled: false })` is called:
498
+
499
+ ```typescript
500
+ // Final styles for `buttonStyles.root` are merged in order:
501
+ {
502
+ // 1. Base styles (always applied)
503
+ flexDirection: 'row',
504
+ alignItems: 'center',
505
+
506
+ // 2. Size variant styles (size: 'lg')
507
+ paddingHorizontal: 24,
508
+ paddingVertical: 16,
509
+
510
+ // 3. Variant styles (variant: 'primary')
511
+ backgroundColor: theme.colors.background.brand,
512
+
513
+ // 4. Disabled styles (disabled: false → not applied)
514
+ // opacity: 0.5 ← skipped because disabled is false
515
+ }
516
+ ```
517
+
518
+ #### Compound Variants
519
+
520
+ Compound variants apply styles when **multiple conditions are true simultaneously**. This is essential for state-specific styling that depends on the variant:
521
+
522
+ ```typescript
523
+ const buttonStyles = StyleSheet.create((theme) => ({
524
+ root: {
525
+ variants: {
526
+ variant: {
527
+ primary: { backgroundColor: theme.colors.background.brand },
528
+ secondary: { backgroundColor: theme.colors.background.secondary },
529
+ },
530
+ pressed: { true: {} }, // Empty placeholder - actual styles in compoundVariants
531
+ },
532
+
533
+ // Compound variants: apply when ALL specified conditions match
534
+ compoundVariants: [
535
+ {
536
+ variant: 'primary',
537
+ pressed: true,
538
+ styles: { backgroundColor: theme.colors.background.brandHover },
539
+ },
540
+ {
541
+ variant: 'secondary',
542
+ pressed: true,
543
+ styles: { backgroundColor: theme.colors.background.secondaryHover },
544
+ },
545
+ ],
546
+ },
547
+ }));
548
+ ```
549
+
550
+ **Why compound variants?** Each button variant needs a different pressed color. Without compound variants, you'd need a single `pressed: { true: { ... } }` style that works for all variants—impossible when different variants need different pressed colors.
551
+
552
+ #### Resolution Order
553
+
554
+ Styles are merged in this priority (later wins):
555
+
556
+ 1. **Base styles** - Always applied
557
+ 2. **Single variants** - Applied when their condition matches
558
+ 3. **Compound variants** - Applied when ALL their conditions match (highest priority)
559
+
560
+ ```typescript
561
+ // With useVariants({ variant: 'primary', pressed: true }):
562
+ {
563
+ // 1. Base: flexDirection, alignItems
564
+ // 2. variant='primary': backgroundColor: brand
565
+ // 3. pressed=true: (empty)
566
+ // 4. COMPOUND (variant='primary' + pressed=true): backgroundColor: brandHover ← wins!
567
+ }
568
+ ```
569
+
570
+ ### `generated/unistyles.d.ts`
571
+
572
+ Type declarations for Unistyles theme augmentation. Ensures TypeScript knows the shape of the theme object.
573
+
574
+ ### `fonts/index.cjs` and `fonts/index.mjs`
575
+
576
+ Font manifests that export:
577
+
578
+ - `fonts`: Array of font file paths for Expo's font plugin
579
+ - `fontAliasToPostscript`: Mapping of font IDs to PostScript names (required by React Native)
580
+
581
+ ## Code Generation Pipeline
582
+
583
+ The generation pipeline runs via `bun scripts/generate.ts` (or `bun run generate`):
584
+
585
+ ```
586
+ ┌─────────────────────────────────────────────────────────────────────┐
587
+ │ generate.ts │
588
+ │ 1. generateTypes() → generated/unistyles.d.ts │
589
+ │ 2. generateStyles() → generated/styles.ts │
590
+ │ 3. generateFonts() → fonts/index.{cjs,mjs} │
591
+ └─────────────────────────────────────────────────────────────────────┘
592
+ ```
593
+
594
+ ### Step 1: generateTypes.ts
595
+
596
+ Uses [ts-morph](https://ts-morph.com/) to:
597
+
598
+ 1. Load `@yahoo/uds/tokens` type definitions
599
+ 2. Generate a temporary theme using `generateTheme()`
600
+ 3. Infer TypeScript types from runtime values
601
+ 4. Write `unistyles.d.ts` with proper theme augmentation
602
+
603
+ ### Step 2: generateStyles.ts
604
+
605
+ The most complex generation step:
606
+
607
+ 1. **Load TypeScript definitions** via ts-morph:
608
+ - Reads `StyleProps` interfaces from `@yahoo/uds/tokens/types.ts`
609
+ - Extracts all possible values for each prop (e.g., `backgroundColor: 'primary' | 'secondary' | ...`)
610
+
611
+ 2. **Validate against React Native types**:
612
+ - Loads Unistyles' `AllAvailableStyles` type
613
+ - Filters out values not valid in React Native (e.g., `'grid'` for `display`)
614
+
615
+ 3. **Map UDS props to theme paths**:
616
+ - Uses `themeConfig.ts` to map type names to theme locations
617
+ - Example: `BackgroundColor` type → `theme.colors.background`
618
+
619
+ 4. **Generate component styles**:
620
+ - Uses `generateLayerBasedComponentStyles.ts` to create per-component stylesheets
621
+ - Reads component configs from `@yahoo/uds/tokens`
622
+ - Maps component keys like `button/size/lg/root/rest` to theme references
623
+
624
+ 5. **Output formatted TypeScript**:
625
+ - Uses Prettier for consistent formatting
626
+ - Writes to `generated/styles.ts`
627
+
628
+ ### Step 3: generateFonts.ts
629
+
630
+ 1. Scans `fonts/` directory for `.otf` and `.ttf` files
631
+ 2. Uses `fontkit` to extract PostScript names from font files
632
+ 3. Generates CommonJS and ESM manifests for Expo compatibility
633
+
634
+ ## Theme Generation
635
+
636
+ The CLI (`uds-mobile sync`) generates themes for consumer apps:
637
+
638
+ ```
639
+ ┌─────────────────────────────────────────────────────────────────────┐
640
+ │ Consumer App │
641
+ │ │
642
+ │ uds.config.ts ──────► uds-mobile sync ──────► unistyles.uds.ts │
643
+ │ (UDS tokens) (CLI command) (theme objects) │
644
+ └─────────────────────────────────────────────────────────────────────┘
645
+ ```
646
+
647
+ ### How `generateTheme.ts` works:
648
+
649
+ 1. **Input**: `UniversalTokensConfig` from `@yahoo/uds/tokens`
650
+
651
+ 2. **Color Processing**:
652
+ - Generates spectrum colors (hue + step combinations)
653
+ - Creates semantic colors (background, foreground, line)
654
+ - Handles `always/*` colors that don't change with theme
655
+
656
+ 3. **Typography**:
657
+ - Converts CSS font-family + weight to PostScript names
658
+ - React Native requires PostScript names for custom fonts
659
+
660
+ 4. **Component Styles**:
661
+ - Flattens component config into key-value pairs
662
+ - Keys use format: `component/variant/value/layer/state`
663
+ - Example: `button/variant/primary/root/pressed`
664
+
665
+ 5. **Output**: Light and dark theme objects ready for Unistyles
666
+
667
+ ### Config Assumptions & Workarounds
668
+
669
+ The theme generator makes assumptions about config structure. When configs don't honor these assumptions, workarounds are required. These are documented in `packages/mobile/docs/`.
670
+
671
+ #### Text-Only Props in Root Layers
672
+
673
+ **Problem:** React Native's `color` only works on `<Text>`, not `<View>`. Config defines `color` in root layers expecting CSS cascade behavior.
674
+
675
+ **Why it matters:** On web, CSS `color` on a parent cascades to child text. In RN, applying `color` to a `<View>` does nothing—text stays black. Without this workaround, 74 style definitions across 7 components would have broken text colors.
676
+
677
+ **Workaround:** The generator detects text-only props (`color`) in root layers and extracts them into a separate `rootText` layer, which components apply to their `<Text>` children:
678
+
679
+ ```tsx
680
+ // Generated theme has both layers
681
+ theme.components['button/variant/primary/root/rest'] // backgroundColor, etc.
682
+ theme.components['button/variant/primary/rootText/rest'] // color (for Text)
683
+
684
+ // Component applies them separately
685
+ <Pressable style={buttonStyles.root}>
686
+ <Text style={buttonStyles.text}>{children}</Text> {/* Gets color */}
687
+ </Pressable>
688
+ ```
689
+
690
+ **Affected:** 7 components, 74 root paths (avatar, badge, button, checkbox, chip, link, radio)
691
+
692
+ See: `docs/TEXT_ONLY_PROPS_WORKAROUND.md`
693
+
694
+ #### Missing Disabled States
695
+
696
+ **Problem:** Some components don't define `disabled` state in config but need disabled styling.
697
+
698
+ **Why it matters:** Users expect disabled components to look disabled. Without config-defined states, the generator can't output disabled styles, so components would look fully interactive even when `disabled={true}`.
699
+
700
+ **Workaround:** Manual `opacity: 0.5` in component files:
701
+
702
+ ```tsx
703
+ <Pressable
704
+ disabled={disabled}
705
+ style={[styles.root, disabled && { opacity: 0.5 }]}
706
+ >
707
+ ```
708
+
709
+ This is hardcoded in each component rather than generated from config.
710
+
711
+ **Affected:** radio, switch, chip, link, menu, iconButton
712
+
713
+ See: `docs/MISSING_DISABLED_STATES.md`
714
+
715
+ #### Always Palette Special Handling
716
+
717
+ **Problem:** `always/current` uses `currentColor` (CSS-only concept), and `alwaysPaletteAliases` is a separate type not in spectrum.
718
+
719
+ **Why it matters:** The `always/*` palette contains colors that don't change between light/dark themes (e.g., `always/light`, `always/dark`). But `always/current` maps to CSS `currentColor`—a concept that doesn't exist in React Native. If the generator tried to resolve it, it would crash or produce invalid styles.
720
+
721
+ **Workaround:**
722
+
723
+ ```typescript
724
+ // In generateTheme.ts
725
+ if (value === 'always/current') {
726
+ return undefined; // Skip - no RN equivalent
727
+ }
728
+
729
+ // alwaysPaletteAliases handled separately from spectrum colors
730
+ if (type === 'alwaysPaletteAliases') {
731
+ return theme.colors.always[value]; // Special lookup
732
+ }
733
+ ```
734
+
735
+ See: `docs/ALWAYS_PALETTE_HANDLING.md`
736
+
737
+ #### Property Name Inconsistency (`iconSize` vs `size`)
738
+
739
+ **Problem:** Avatar uses `iconSize` but Button/Badge/Input/Switch use `size` for their icon layers—yet all have type `iconSizes`.
740
+
741
+ **Why it matters:** The generator maps config properties to React Native style properties. For icon fonts, we need `fontSize` and `lineHeight`. With inconsistent naming, we must handle **both** property names:
742
+
743
+ ```typescript
744
+ // In configToRNMappings.ts - both map to the same RN props
745
+ const propToStyleProps = {
746
+ iconSize: ['fontSize', 'lineHeight'], // Avatar uses this
747
+ size: ['fontSize', 'lineHeight'], // Everyone else uses this
748
+ };
749
+ ```
750
+
751
+ Without this, Avatar icons wouldn't get proper sizing.
752
+
753
+ **Workaround:** Added `fontSize`/`lineHeight` mapping for **both** `iconSize` and `size` properties.
754
+
755
+ See: `docs/CONFIG_INCONSISTENCIES.md`
756
+
757
+ #### textStyle vs textVariant
758
+
759
+ **Problem:** Link config uses `textStyle` as variant name, but component exposes `textVariant` prop.
760
+
761
+ **Why it matters:** The generated styles use config variant names as keys. When the component prop name differs, you can't directly pass the prop value to the stylesheet:
762
+
763
+ ```tsx
764
+ // Config defines: link/textStyle/body1/root
765
+ // Component receives: textVariant="body1"
766
+
767
+ // This doesn't work - key mismatch
768
+ linkStyles.useVariants({ textVariant }); // ❌ No 'textVariant' variant
769
+
770
+ // Must map prop to config key
771
+ linkStyles.useVariants({ textStyle: textVariant }); // ✅ Works
772
+ ```
773
+
774
+ **Workaround:** Link component maps `textVariant` prop to `textStyle` variant key internally.
775
+
776
+ See: `docs/CONFIG_INCONSISTENCIES.md`
777
+
778
+ > **📋 Full documentation:** See `packages/mobile/docs/` for all workarounds and their proper fixes.
779
+
780
+ ### Adding New Config Workarounds
781
+
782
+ When you encounter a new config inconsistency, here's where to add the fix:
783
+
784
+ | Workaround Type | File | Purpose |
785
+ | ----------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------- |
786
+ | **Property name mapping** | `scripts/utils/configToRNMappings.ts` | Map config prop names to RN style props (e.g., `iconSize` → `fontSize`) |
787
+ | **Text-only prop extraction** | `scripts/utils/configToRNMappings.ts` | `TEXT_ONLY_PROPS` set — props like `color` that must go on `<Text>`, not `<View>` |
788
+ | **Layer normalization** | `scripts/utils/generateComponentStyles.ts` | Transform layer names (e.g., `rootText` → `text`) |
789
+ | **Value resolution** | `bin/generateTheme.ts` | Handle special value types (e.g., `alwaysPaletteAliases`) |
790
+ | **Type mappings** | `scripts/utils/typesToThemePaths.ts` | Map UDS types to theme paths (e.g., `spacingAliases` → `theme.spacing`) |
791
+ | **Component-level** | `src/components/[Component].tsx` | Runtime fixes (e.g., manual `opacity: 0.5` for missing disabled states) |
792
+
793
+ #### Workflow for Adding a Workaround
794
+
795
+ 1. **Identify the issue** - What's wrong with the config? Missing state, wrong property name, etc.
796
+
797
+ 2. **Determine the fix location:**
798
+ - Can it be fixed in generation? → Use scripts/bin files
799
+ - Must be fixed at runtime? → Use component file
800
+
801
+ 3. **Implement the fix** with clear comments:
802
+
803
+ ```typescript
804
+ // In configToRNMappings.ts
805
+ // WORKAROUND: Avatar uses 'iconSize' but others use 'size'
806
+ // See: docs/CONFIG_INCONSISTENCIES.md
807
+ iconSize: ['fontSize', 'lineHeight'],
808
+ size: ['fontSize', 'lineHeight'],
809
+ ```
810
+
811
+ 4. **Document the workaround** in `packages/mobile/docs/`:
812
+ - Create a new `.md` file or update existing one
813
+ - Include: Problem, Why it matters, Workaround, Proper fix
814
+
815
+ 5. **Regenerate styles** to verify:
816
+
817
+ ```bash
818
+ cd packages/mobile
819
+ bun run generate
820
+ ```
821
+
822
+ ## Component Styling System
823
+
824
+ ### Layer-Based Architecture
825
+
826
+ Components use a layer-based styling system:
827
+
828
+ ```
829
+ Component
830
+ ├── root # Container/pressable layer
831
+ ├── text # Text content layer (rootText in configs)
832
+ ├── icon # Icon layer
833
+ └── [custom] # Component-specific layers (e.g., checkbox, handle)
834
+ ```
835
+
836
+ ### Variant Key Format
837
+
838
+ Component styles in the theme use this key format:
839
+
840
+ ```
841
+ {component}/{dimension}/{value}/{layer}/{state}
842
+
843
+ Examples:
844
+ - button/size/lg/root/rest
845
+ - button/variant/primary/icon/pressed
846
+ - checkbox/variant/primary/value/checked/checkbox/disabled
847
+ ```
848
+
849
+ ### Using Component Styles
850
+
851
+ ```typescript
852
+ // In a component
853
+ const { styles: rootStyles } = buttonStyles.useVariants({
854
+ size: 'md',
855
+ variant: 'primary',
856
+ disabled: isDisabled,
857
+ pressed: isPressed,
858
+ });
859
+
860
+ return (
861
+ <Pressable style={rootStyles.root}>
862
+ <Text style={rootStyles.text}>{children}</Text>
863
+ </Pressable>
864
+ );
865
+ ```
866
+
867
+ ## Unistyles Patterns
868
+
869
+ ### Avoiding useUnistyles Re-renders
870
+
871
+ `useUnistyles()` hook causes component re-renders on theme changes. For better performance, use **dynamic functions** in stylesheets:
872
+
873
+ ```tsx
874
+ // ❌ Bad: useUnistyles causes re-renders
875
+ import { useUnistyles } from 'react-native-unistyles';
876
+
877
+ function ColorSwatch({ colorKey }: { colorKey: string }) {
878
+ const { theme } = useUnistyles();
879
+ const backgroundColor = theme.colors.background[colorKey];
880
+ return <View style={{ backgroundColor }} />;
881
+ }
882
+
883
+ // ✅ Good: Dynamic function in stylesheet (no hook needed)
884
+ import { StyleSheet } from 'react-native-unistyles';
885
+
886
+ function ColorSwatch({ colorKey }: { colorKey: string }) {
887
+ return <View style={styles.swatch(colorKey)} />;
888
+ }
889
+
890
+ const styles = StyleSheet.create((theme) => ({
891
+ swatch: (colorKey: string) => ({
892
+ backgroundColor: theme.colors.background[colorKey],
893
+ width: 64,
894
+ height: 64,
895
+ }),
896
+ }));
897
+ ```
898
+
899
+ Dynamic functions can accept multiple parameters:
900
+
901
+ ```tsx
902
+ const styles = StyleSheet.create((theme) => ({
903
+ container: (maxWidth: number, isOdd: boolean) => ({
904
+ backgroundColor: theme.colors.background.primary,
905
+ maxWidth,
906
+ borderBottomWidth: isOdd ? 1 : undefined,
907
+ }),
908
+ }));
909
+
910
+ // Usage
911
+ <View style={styles.container(300, true)} />;
912
+ ```
913
+
914
+ ### When to Use Each Approach
915
+
916
+ | Approach | Use Case |
917
+ | ------------------ | ------------------------------------------- |
918
+ | Dynamic functions | Static theme access with parameters |
919
+ | `useAnimatedTheme` | Animated worklet access (zero re-renders) |
920
+ | `useUnistyles` | When you need runtime theme object in logic |
921
+
922
+ ## Reanimated + Unistyles
923
+
924
+ When animating components, we use Reanimated with Unistyles. There are important patterns and gotchas to follow.
925
+
926
+ ### ⚠️ Critical: Never Mix Styles Inside useAnimatedStyle
927
+
928
+ **Never spread Unistyles styles inside `useAnimatedStyle`:**
929
+
930
+ ```tsx
931
+ // ❌ BAD: Spreading Unistyles inside useAnimatedStyle
932
+ const animatedStyle = useAnimatedStyle(() => ({
933
+ ...styles.container, // 💥 Never do this!
934
+ opacity: opacity.value,
935
+ }));
936
+
937
+ return <Animated.View style={animatedStyle} />;
938
+ ```
939
+
940
+ **Why this breaks:** This creates a single style object with both Unistyles C++ state and Reanimated animation metadata. Both libraries try to update the same style nodes at the ShadowTree level, causing performance issues and visual bugs.
941
+
942
+ ```tsx
943
+ // ✅ GOOD: Keep styles separate in array
944
+ const animatedStyle = useAnimatedStyle(() => ({
945
+ opacity: opacity.value,
946
+ }));
947
+
948
+ return <Animated.View style={[styles.container, animatedStyle]} />;
949
+ ```
950
+
951
+ > **📖 Unistyles docs:** [Reanimated Integration Guide](https://www.unistyl.es/v3/guides/reanimated#:~:text=new%20color%20automatically.-,Merging%20styles,-When%20you%20want)
952
+
953
+ ### Animating Theme Colors
954
+
955
+ Use `useAnimatedVariantColor` for color properties:
956
+
957
+ ```tsx
958
+ import { useAnimatedVariantColor } from 'react-native-unistyles/reanimated';
959
+
960
+ const backgroundColor = useAnimatedVariantColor(buttonStyles.root, 'backgroundColor');
961
+ const borderColor = useAnimatedVariantColor(buttonStyles.root, 'borderColor');
962
+
963
+ const animatedStyle = useAnimatedStyle(() => ({
964
+ backgroundColor: withTiming(backgroundColor.value, { duration: 220 }),
965
+ borderColor: withTiming(borderColor.value, { duration: 220 }),
966
+ }));
967
+ ```
968
+
969
+ ### Animating Non-Color Theme Values
970
+
971
+ Use `useAnimatedTheme` for non-color properties (`boxShadow`, etc.):
972
+
973
+ ```tsx
974
+ import { useAnimatedTheme } from 'react-native-unistyles/reanimated';
975
+
976
+ const animatedTheme = useAnimatedTheme(); // Zero re-renders!
977
+
978
+ const animatedStyle = useAnimatedStyle(() => {
979
+ const shadowPressed =
980
+ animatedTheme.value.components[`button/variant/${variant}/root/pressed`]?.boxShadow ?? '';
981
+
982
+ return {
983
+ boxShadow: interpolateShadowAlpha(shadowPressed, pressProgress.value),
984
+ };
985
+ });
986
+ ```
987
+
988
+ ### State-Driven Animations
989
+
990
+ Prefer `useDerivedValue` over `useEffect` + `useSharedValue`:
991
+
992
+ ```tsx
993
+ // ❌ Avoid: useEffect pattern
994
+ const progress = useSharedValue(0);
995
+ useEffect(() => {
996
+ progress.value = withTiming(visible ? 1 : 0);
997
+ }, [visible]);
998
+
999
+ // ✅ Prefer: useDerivedValue
1000
+ const progress = useDerivedValue(() => withTiming(visible ? 1 : 0), [visible]);
1001
+ ```
1002
+
1003
+ **Why:** No `useEffect` overhead, animation computed on UI thread, cleaner dependency tracking.
1004
+
1005
+ ### Staggered Animations
1006
+
1007
+ Use `interpolate` with clamping for staggered effects:
1008
+
1009
+ ```tsx
1010
+ const progress = useDerivedValue(() => withSpring(visible ? 1 : 0, SPRING_CONFIG), [visible]);
1011
+
1012
+ const animatedStyle = useAnimatedStyle(() => {
1013
+ // Width animates full range
1014
+ const width = interpolate(progress.value, [0, 1], [0, totalWidth]);
1015
+
1016
+ // Opacity/scale start at 50% progress - creates stagger effect
1017
+ const opacity = interpolate(progress.value, [0.5, 1], [0, 1], 'clamp');
1018
+ const scale = interpolate(progress.value, [0.5, 1], [0.7, 1], 'clamp');
1019
+
1020
+ return { width, opacity, transform: [{ scale }] };
1021
+ });
1022
+ ```
1023
+
1024
+ ### Worklet Functions
1025
+
1026
+ Mark functions that run on the UI thread:
1027
+
1028
+ ```tsx
1029
+ function interpolateShadowAlpha(shadow: string, alpha: number): string {
1030
+ 'worklet'; // Required for UI thread execution
1031
+ if (!shadow || alpha >= 1) return shadow;
1032
+ if (alpha <= 0) return '';
1033
+
1034
+ return shadow.replace(/rgba\(([^,]+),\s*([^,]+),\s*([^,]+),\s*([^)]+)\)/g, (_, r, g, b, a) => {
1035
+ const newAlpha = parseFloat(a) * alpha;
1036
+ return `rgba(${r}, ${g}, ${b}, ${newAlpha.toFixed(3)})`;
1037
+ });
1038
+ }
1039
+ ```
1040
+
1041
+ ### When to Use Each Hook
1042
+
1043
+ | Property Type | Hook | Example Properties |
1044
+ | ------------- | ------------------------- | ----------------------------------------- |
1045
+ | Colors | `useAnimatedVariantColor` | `backgroundColor`, `borderColor`, `color` |
1046
+ | Non-colors | `useAnimatedTheme` | `boxShadow`, `opacity`, custom values |
1047
+ | Computed | `useDerivedValue` | Progress values based on props/state |
1048
+
1049
+ ## Development Workflow
1050
+
1051
+ ### Initial Setup
1052
+
1053
+ ```bash
1054
+ # From monorepo root
1055
+ bun install
1056
+
1057
+ # Build the package
1058
+ cd packages/mobile
1059
+ bun turbo build
1060
+ ```
1061
+
1062
+ ### Making Changes
1063
+
1064
+ 1. **Components** (`src/components/`): Edit directly, run `bun turbo dev` for watch mode
1065
+ 2. **Styles generation**: Edit `scripts/generateStyles.ts`, then run `bun run generate`
1066
+ 3. **Types**: Edit `scripts/generateTypes.ts`, then run `bun run generate`
1067
+ 4. **Theme generation**: Edit `bin/generateTheme.ts`
1068
+
1069
+ ### Testing Changes
1070
+
1071
+ ```bash
1072
+ # Run tests
1073
+ bun turbo test
1074
+
1075
+ # Type check
1076
+ bun turbo typecheck
1077
+
1078
+ # Lint
1079
+ bun turbo lint
1080
+ ```
1081
+
1082
+ ### Rebuilding Generated Files
1083
+
1084
+ ```bash
1085
+ bun turbo build
1086
+ ```
1087
+
1088
+ ## Adding New Components
1089
+
1090
+ ### 1. Create the Component File
1091
+
1092
+ ```typescript
1093
+ // src/components/MyComponent.tsx
1094
+ import { Pressable, type PressableProps } from 'react-native';
1095
+ import { myComponentStyles } from '../generated/styles';
1096
+ import { Text } from './Text';
1097
+
1098
+ export interface MyComponentProps extends PressableProps {
1099
+ size?: 'sm' | 'md' | 'lg';
1100
+ variant?: 'primary' | 'secondary';
1101
+ children: React.ReactNode;
1102
+ }
1103
+
1104
+ export function MyComponent({
1105
+ size = 'md',
1106
+ variant = 'primary',
1107
+ disabled,
1108
+ children,
1109
+ ...props
1110
+ }: MyComponentProps) {
1111
+ const { styles } = myComponentStyles.useVariants({
1112
+ size,
1113
+ variant,
1114
+ disabled: !!disabled,
1115
+ });
1116
+
1117
+ return (
1118
+ <Pressable style={styles.root} disabled={disabled} {...props}>
1119
+ <Text style={styles.text}>{children}</Text>
1120
+ </Pressable>
1121
+ );
1122
+ }
1123
+ ```
1124
+
1125
+ ### 2. Export from Index
1126
+
1127
+ ```typescript
1128
+ // src/index.ts
1129
+ export { MyComponent, type MyComponentProps } from './components/MyComponent';
1130
+ ```
1131
+
1132
+ ### 3. Ensure Component Styles Exist
1133
+
1134
+ The component styles are generated from `@yahoo/uds/tokens` component configs. If the component doesn't exist in UDS tokens:
1135
+
1136
+ 1. Add the component config to `@yahoo/uds`
1137
+ 2. Run `bun run generate` to regenerate styles
1138
+ 3. The component stylesheet will be auto-generated
1139
+
1140
+ ### 4. Update Types (if needed)
1141
+
1142
+ Add prop types to `src/types.ts` if exposing new semantic types.
1143
+
1144
+ ## Debugging
1145
+
1146
+ ### Generated Styles Issues
1147
+
1148
+ 1. Check `scripts/utils/themeConfig.ts` for type → theme path mappings
1149
+ 2. Run `bun run generate` with verbose logging
1150
+ 3. Check the console output for skipped props/values
1151
+
1152
+ ### Component Styles Not Applying
1153
+
1154
+ 1. Verify the component config exists in `@yahoo/uds/tokens`
1155
+ 2. Check `generated/styles.ts` for the component stylesheet
1156
+ 3. Ensure you're calling `useVariants()` with correct prop names
1157
+
1158
+ ### Theme Mismatch
1159
+
1160
+ 1. Regenerate the consumer app's theme: `uds-mobile sync`
1161
+ 2. Clear Metro cache: `expo start --clear`
1162
+ 3. Verify `uds.config.ts` matches the expected format
1163
+
1164
+ ### Font Issues
1165
+
1166
+ 1. Check `fonts/index.cjs` for the font mapping
1167
+ 2. Verify PostScript names match what React Native expects
1168
+ 3. Ensure fonts are properly linked in `app.config.ts`
1169
+
1170
+ ## Questions?
1171
+
1172
+ - Check the [README.md](./README.md) for usage documentation
1173
+ - Review `docs/` for architecture decisions
1174
+ - Open an issue for bugs or feature requests