jfs-components 0.0.99 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (335) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/lib/commonjs/components/AreaLineChart/AreaLineChart.js +1 -1
  3. package/lib/commonjs/components/Balance/Balance.js +17 -12
  4. package/lib/commonjs/components/Card/Card.js +2 -1
  5. package/lib/commonjs/components/CardFeedback/CardFeedback.js +2 -1
  6. package/lib/commonjs/components/Checkbox/Checkbox.js +2 -1
  7. package/lib/commonjs/components/Drawer/Drawer.js +13 -4
  8. package/lib/commonjs/components/Dropdown/Dropdown.js +37 -18
  9. package/lib/commonjs/components/DropdownInput/DropdownInput.js +1 -1
  10. package/lib/commonjs/components/FullscreenModal/FullscreenModal.js +65 -4
  11. package/lib/commonjs/components/Image/Image.js +11 -5
  12. package/lib/commonjs/components/LottiePlayer/loadNativeLottieView.js +8 -13
  13. package/lib/commonjs/components/Overlay/Overlay.js +92 -0
  14. package/lib/commonjs/components/PlanComparisonCard/PlanComparisonCard.js +2 -1
  15. package/lib/commonjs/components/TestimonialsCard/TestimonialsCard.js +121 -0
  16. package/lib/commonjs/components/TextInput/TextInput.js +2 -1
  17. package/lib/commonjs/components/docs/modeControls.js +116 -0
  18. package/lib/commonjs/components/index.js +14 -0
  19. package/lib/commonjs/design-tokens/JFSThemeProvider.js +1 -1
  20. package/lib/commonjs/design-tokens/figma-modes.generated.js +391 -0
  21. package/lib/commonjs/design-tokens/index.js +11 -0
  22. package/lib/commonjs/icons/registry.js +1 -1
  23. package/lib/module/components/Accordion/Accordion.js +1 -2
  24. package/lib/module/components/AreaLineChart/AreaLineChart.js +1 -1
  25. package/lib/module/components/Balance/Balance.js +18 -13
  26. package/lib/module/components/Card/Card.js +1 -2
  27. package/lib/module/components/CardFeedback/CardFeedback.js +1 -2
  28. package/lib/module/components/Checkbox/Checkbox.js +1 -2
  29. package/lib/module/components/Drawer/Drawer.js +12 -4
  30. package/lib/module/components/Dropdown/Dropdown.js +37 -18
  31. package/lib/module/components/DropdownInput/DropdownInput.js +1 -1
  32. package/lib/module/components/FullscreenModal/FullscreenModal.js +67 -7
  33. package/lib/module/components/Image/Image.js +11 -5
  34. package/lib/module/components/InstitutionBadge/InstitutionBadge.js +1 -2
  35. package/lib/module/components/LottiePlayer/loadNativeLottieView.js +8 -13
  36. package/lib/module/components/MoneyValue/MoneyValue.js +1 -2
  37. package/lib/module/components/OTP/OTP.js +1 -2
  38. package/lib/module/components/Overlay/Overlay.js +87 -0
  39. package/lib/module/components/PlanComparisonCard/PlanComparisonCard.js +1 -2
  40. package/lib/module/components/PoweredByLabel/PoweredByLabel.js +1 -2
  41. package/lib/module/components/RechargeCard/RechargeCard.js +1 -2
  42. package/lib/module/components/Section/Section.js +1 -2
  43. package/lib/module/components/TestimonialsCard/TestimonialsCard.js +116 -0
  44. package/lib/module/components/TextInput/TextInput.js +1 -2
  45. package/lib/module/components/UpiHandle/UpiHandle.js +1 -2
  46. package/lib/module/components/docs/modeControls.js +111 -0
  47. package/lib/module/components/index.js +2 -0
  48. package/lib/module/design-tokens/JFSThemeProvider.js +1 -1
  49. package/lib/module/design-tokens/figma-modes.generated.js +387 -0
  50. package/lib/module/design-tokens/index.js +2 -1
  51. package/lib/module/icons/registry.js +1 -1
  52. package/lib/module/utils/react-utils.js +0 -1
  53. package/lib/typescript/scripts/extract-component-tokens.d.ts +1 -1
  54. package/lib/typescript/scripts/generate-mode-types.d.ts +2 -0
  55. package/lib/typescript/scripts/retype-modes.d.cts +2 -0
  56. package/lib/typescript/src/components/Accordion/Accordion.d.ts +2 -1
  57. package/lib/typescript/src/components/AccordionCheckbox/AccordionCheckbox.d.ts +2 -1
  58. package/lib/typescript/src/components/AccountCard/AccountCard.d.ts +2 -1
  59. package/lib/typescript/src/components/ActionFooter/ActionFooter.d.ts +2 -1
  60. package/lib/typescript/src/components/ActionTile/ActionTile.d.ts +2 -1
  61. package/lib/typescript/src/components/AllocationComparisonChart/AllocationComparisonChart.d.ts +2 -1
  62. package/lib/typescript/src/components/AmountInput/AmountInput.d.ts +2 -1
  63. package/lib/typescript/src/components/AppBar/AppBar.d.ts +2 -1
  64. package/lib/typescript/src/components/AreaLineChart/AreaLineChart.d.ts +3 -2
  65. package/lib/typescript/src/components/Attached/Attached.d.ts +2 -1
  66. package/lib/typescript/src/components/Avatar/Avatar.d.ts +2 -1
  67. package/lib/typescript/src/components/AvatarGroup/AvatarGroup.d.ts +2 -1
  68. package/lib/typescript/src/components/Badge/Badge.d.ts +2 -1
  69. package/lib/typescript/src/components/Balance/Balance.d.ts +2 -1
  70. package/lib/typescript/src/components/BottomNav/BottomNav.d.ts +2 -1
  71. package/lib/typescript/src/components/BottomNavItem/BottomNavItem.d.ts +2 -1
  72. package/lib/typescript/src/components/BrandChip/BrandChip.d.ts +2 -1
  73. package/lib/typescript/src/components/BubbleChart/BubbleChart.d.ts +2 -1
  74. package/lib/typescript/src/components/Button/Button.d.ts +2 -1
  75. package/lib/typescript/src/components/ButtonGroup/ButtonGroup.d.ts +2 -1
  76. package/lib/typescript/src/components/Card/Card.d.ts +3 -2
  77. package/lib/typescript/src/components/CardAdvisory/CardAdvisory.d.ts +2 -1
  78. package/lib/typescript/src/components/CardBankAccount/CardBankAccount.d.ts +2 -1
  79. package/lib/typescript/src/components/CardCTA/CardCTA.d.ts +2 -1
  80. package/lib/typescript/src/components/CardFeedback/CardFeedback.d.ts +7 -6
  81. package/lib/typescript/src/components/CardFinancialCondition/CardFinancialCondition.d.ts +2 -1
  82. package/lib/typescript/src/components/CardInsight/CardInsight.d.ts +2 -1
  83. package/lib/typescript/src/components/CardProviderInfo/CardProviderInfo.d.ts +2 -1
  84. package/lib/typescript/src/components/Carousel/Carousel.d.ts +4 -3
  85. package/lib/typescript/src/components/Checkbox/Checkbox.d.ts +2 -1
  86. package/lib/typescript/src/components/CheckboxGroup/CheckboxGroup.d.ts +2 -1
  87. package/lib/typescript/src/components/CheckboxItem/CheckboxItem.d.ts +2 -1
  88. package/lib/typescript/src/components/ChipGroup/ChipGroup.d.ts +2 -1
  89. package/lib/typescript/src/components/ChipSelect/ChipSelect.d.ts +2 -1
  90. package/lib/typescript/src/components/CircularProgressBar/CircularProgressBar.d.ts +2 -1
  91. package/lib/typescript/src/components/CircularProgressBarDoted/CircularProgressBarDoted.d.ts +2 -1
  92. package/lib/typescript/src/components/CircularRating/CircularRating.d.ts +2 -1
  93. package/lib/typescript/src/components/ClusterBubble/ClusterBubble.d.ts +2 -1
  94. package/lib/typescript/src/components/CoverageBarComparison/CoverageBarComparison.d.ts +3 -2
  95. package/lib/typescript/src/components/CoverageRing/CoverageRing.d.ts +2 -1
  96. package/lib/typescript/src/components/DebitCard/DebitCard.d.ts +2 -1
  97. package/lib/typescript/src/components/Disclaimer/Disclaimer.d.ts +2 -1
  98. package/lib/typescript/src/components/Divider/Divider.d.ts +2 -1
  99. package/lib/typescript/src/components/DonutChart/DonutChart.d.ts +4 -3
  100. package/lib/typescript/src/components/DonutChartSummary/DonutChartSummary.d.ts +3 -2
  101. package/lib/typescript/src/components/Drawer/Drawer.d.ts +15 -1
  102. package/lib/typescript/src/components/Dropdown/Dropdown.d.ts +3 -2
  103. package/lib/typescript/src/components/DropdownInput/DropdownInput.d.ts +2 -1
  104. package/lib/typescript/src/components/EmptyState/EmptyState.d.ts +2 -1
  105. package/lib/typescript/src/components/ExpandableCheckbox/ExpandableCheckbox.d.ts +2 -1
  106. package/lib/typescript/src/components/FilterBar/FilterBar.d.ts +3 -2
  107. package/lib/typescript/src/components/Form/Form.d.ts +2 -1
  108. package/lib/typescript/src/components/FormField/FormField.d.ts +2 -1
  109. package/lib/typescript/src/components/FullscreenModal/FullscreenModal.d.ts +9 -2
  110. package/lib/typescript/src/components/Gauge/Gauge.d.ts +2 -1
  111. package/lib/typescript/src/components/HStack/HStack.d.ts +2 -1
  112. package/lib/typescript/src/components/HoldingsCard/HoldingsCard.d.ts +2 -1
  113. package/lib/typescript/src/components/Icon/Icon.d.ts +2 -1
  114. package/lib/typescript/src/components/IconButton/IconButton.d.ts +2 -1
  115. package/lib/typescript/src/components/IconCapsule/IconCapsule.d.ts +2 -1
  116. package/lib/typescript/src/components/Image/Image.d.ts +17 -1
  117. package/lib/typescript/src/components/InputSearch/InputSearch.d.ts +2 -1
  118. package/lib/typescript/src/components/InstitutionBadge/InstitutionBadge.d.ts +2 -1
  119. package/lib/typescript/src/components/LazyList/LazyList.d.ts +2 -1
  120. package/lib/typescript/src/components/LinearMeter/LinearMeter.d.ts +3 -2
  121. package/lib/typescript/src/components/LinearProgress/LinearProgress.d.ts +2 -1
  122. package/lib/typescript/src/components/ListGroup/ListGroup.d.ts +2 -1
  123. package/lib/typescript/src/components/ListItem/ListItem.d.ts +2 -1
  124. package/lib/typescript/src/components/LottieIntroBlock/LottieIntroBlock.d.ts +2 -1
  125. package/lib/typescript/src/components/LottiePlayer/LottiePlayer.d.ts +2 -1
  126. package/lib/typescript/src/components/LottiePlayer/LottiePlayer.web.d.ts +2 -1
  127. package/lib/typescript/src/components/MediaCard/MediaCard.d.ts +6 -5
  128. package/lib/typescript/src/components/MerchantProfile/MerchantProfile.d.ts +2 -1
  129. package/lib/typescript/src/components/MessageField/MessageField.d.ts +2 -1
  130. package/lib/typescript/src/components/MetricLegendItem/MetricLegendItem.d.ts +2 -1
  131. package/lib/typescript/src/components/MoneyValue/MoneyValue.d.ts +2 -1
  132. package/lib/typescript/src/components/MonthlyStatusGrid/MonthlyStatusGrid.d.ts +4 -3
  133. package/lib/typescript/src/components/NavArrow/NavArrow.d.ts +2 -1
  134. package/lib/typescript/src/components/NoteInput/NoteInput.d.ts +2 -1
  135. package/lib/typescript/src/components/Nudge/Nudge.d.ts +2 -1
  136. package/lib/typescript/src/components/Numpad/Numpad.d.ts +2 -1
  137. package/lib/typescript/src/components/OTP/OTP.d.ts +3 -2
  138. package/lib/typescript/src/components/Overlay/Overlay.d.ts +52 -0
  139. package/lib/typescript/src/components/PageHero/PageHero.d.ts +2 -1
  140. package/lib/typescript/src/components/PaymentFeedback/PaymentFeedback.d.ts +2 -1
  141. package/lib/typescript/src/components/PlanComparisonCard/PlanComparisonCard.d.ts +2 -1
  142. package/lib/typescript/src/components/Popup/Popup.d.ts +2 -1
  143. package/lib/typescript/src/components/PortfolioHero/PortfolioHero.d.ts +2 -1
  144. package/lib/typescript/src/components/PoweredByLabel/PoweredByLabel.d.ts +2 -1
  145. package/lib/typescript/src/components/ProductLabel/ProductLabel.d.ts +2 -1
  146. package/lib/typescript/src/components/ProductOverview/ProductOverview.d.ts +2 -1
  147. package/lib/typescript/src/components/ProgressBadge/ProgressBadge.d.ts +2 -1
  148. package/lib/typescript/src/components/Radio/Radio.d.ts +2 -1
  149. package/lib/typescript/src/components/RangeTrack/RangeTrack.d.ts +3 -2
  150. package/lib/typescript/src/components/RechargeCard/RechargeCard.d.ts +2 -1
  151. package/lib/typescript/src/components/SavingsGoalSummary/SavingsGoalSummary.d.ts +2 -1
  152. package/lib/typescript/src/components/Screen/Screen.d.ts +2 -1
  153. package/lib/typescript/src/components/Section/Section.d.ts +3 -2
  154. package/lib/typescript/src/components/SegmentedControl/SegmentedControl.d.ts +2 -1
  155. package/lib/typescript/src/components/SegmentedTrack/SegmentedTrack.d.ts +4 -3
  156. package/lib/typescript/src/components/Slot/Slot.d.ts +2 -1
  157. package/lib/typescript/src/components/Spinner/Spinner.d.ts +2 -1
  158. package/lib/typescript/src/components/StatGroup/StatGroup.d.ts +2 -1
  159. package/lib/typescript/src/components/StatItem/StatItem.d.ts +2 -1
  160. package/lib/typescript/src/components/StatusHero/StatusHero.d.ts +2 -1
  161. package/lib/typescript/src/components/Stepper/Step.d.ts +2 -1
  162. package/lib/typescript/src/components/Stepper/StepLabel.d.ts +2 -1
  163. package/lib/typescript/src/components/Stepper/Stepper.d.ts +2 -1
  164. package/lib/typescript/src/components/StrengthIndicator/StrengthIndicator.d.ts +2 -1
  165. package/lib/typescript/src/components/SuggestiveSearch/SuggestiveSearch.d.ts +2 -1
  166. package/lib/typescript/src/components/SummaryTile/SummaryTile.d.ts +2 -1
  167. package/lib/typescript/src/components/SupportText/SupportText.d.ts +2 -1
  168. package/lib/typescript/src/components/SupportText/SupportTextIcon.d.ts +2 -1
  169. package/lib/typescript/src/components/SwappableAmount/SwappableAmount.d.ts +2 -1
  170. package/lib/typescript/src/components/Tabs/TabItem.d.ts +2 -1
  171. package/lib/typescript/src/components/Tabs/Tabs.d.ts +2 -1
  172. package/lib/typescript/src/components/TestimonialsCard/TestimonialsCard.d.ts +52 -0
  173. package/lib/typescript/src/components/Text/Text.d.ts +2 -1
  174. package/lib/typescript/src/components/TextInput/TextInput.d.ts +3 -2
  175. package/lib/typescript/src/components/ThreadHero/ThreadHero.d.ts +2 -1
  176. package/lib/typescript/src/components/Title/Title.d.ts +2 -1
  177. package/lib/typescript/src/components/Toast/Toast.d.ts +2 -1
  178. package/lib/typescript/src/components/Toast/ToastProvider.d.ts +2 -1
  179. package/lib/typescript/src/components/Toast/useToast.d.ts +3 -2
  180. package/lib/typescript/src/components/Toggle/Toggle.d.ts +2 -1
  181. package/lib/typescript/src/components/Tooltip/Tooltip.d.ts +2 -1
  182. package/lib/typescript/src/components/TransactionBubble/TransactionBubble.d.ts +2 -1
  183. package/lib/typescript/src/components/TransactionDetails/TransactionDetails.d.ts +3 -2
  184. package/lib/typescript/src/components/TransactionStatus/TransactionStatus.d.ts +2 -1
  185. package/lib/typescript/src/components/UpiHandle/UpiHandle.d.ts +2 -1
  186. package/lib/typescript/src/components/VStack/VStack.d.ts +2 -1
  187. package/lib/typescript/src/components/docs/modeControls.d.ts +28 -0
  188. package/lib/typescript/src/components/index.d.ts +2 -0
  189. package/lib/typescript/src/design-tokens/JFSThemeProvider.d.ts +4 -3
  190. package/lib/typescript/src/design-tokens/figma-modes.generated.d.ts +264 -0
  191. package/lib/typescript/src/design-tokens/index.d.ts +1 -0
  192. package/lib/typescript/src/icons/registry.d.ts +1 -1
  193. package/lib/typescript/src/skeleton/Skeleton.d.ts +2 -1
  194. package/lib/typescript/src/utils/react-utils.d.ts +2 -1
  195. package/package.json +3 -2
  196. package/src/components/Accordion/Accordion.tsx +2 -1
  197. package/src/components/AccordionCheckbox/AccordionCheckbox.tsx +2 -1
  198. package/src/components/AccountCard/AccountCard.tsx +2 -1
  199. package/src/components/ActionFooter/ActionFooter.tsx +2 -1
  200. package/src/components/ActionTile/ActionTile.tsx +2 -1
  201. package/src/components/AllocationComparisonChart/AllocationComparisonChart.tsx +2 -1
  202. package/src/components/AmountInput/AmountInput.tsx +2 -1
  203. package/src/components/AppBar/AppBar.tsx +2 -1
  204. package/src/components/AreaLineChart/AreaLineChart.tsx +8 -7
  205. package/src/components/Attached/Attached.tsx +2 -1
  206. package/src/components/Avatar/Avatar.tsx +3 -2
  207. package/src/components/AvatarGroup/AvatarGroup.tsx +2 -1
  208. package/src/components/Badge/Badge.tsx +2 -1
  209. package/src/components/Balance/Balance.tsx +18 -12
  210. package/src/components/BottomNav/BottomNav.tsx +2 -1
  211. package/src/components/BottomNavItem/BottomNavItem.tsx +3 -2
  212. package/src/components/BrandChip/BrandChip.tsx +3 -2
  213. package/src/components/BubbleChart/BubbleChart.tsx +2 -1
  214. package/src/components/Button/Button.tsx +3 -2
  215. package/src/components/ButtonGroup/ButtonGroup.tsx +2 -1
  216. package/src/components/Card/Card.tsx +4 -3
  217. package/src/components/CardAdvisory/CardAdvisory.tsx +3 -2
  218. package/src/components/CardBankAccount/CardBankAccount.tsx +2 -1
  219. package/src/components/CardCTA/CardCTA.tsx +3 -2
  220. package/src/components/CardFeedback/CardFeedback.tsx +11 -10
  221. package/src/components/CardFinancialCondition/CardFinancialCondition.tsx +3 -2
  222. package/src/components/CardInsight/CardInsight.tsx +2 -1
  223. package/src/components/CardProviderInfo/CardProviderInfo.tsx +2 -1
  224. package/src/components/Carousel/Carousel.tsx +5 -4
  225. package/src/components/Checkbox/Checkbox.tsx +2 -1
  226. package/src/components/CheckboxGroup/CheckboxGroup.tsx +2 -1
  227. package/src/components/CheckboxItem/CheckboxItem.tsx +2 -1
  228. package/src/components/ChipGroup/ChipGroup.tsx +2 -1
  229. package/src/components/ChipSelect/ChipSelect.tsx +2 -1
  230. package/src/components/CircularProgressBar/CircularProgressBar.tsx +2 -1
  231. package/src/components/CircularProgressBarDoted/CircularProgressBarDoted.tsx +2 -1
  232. package/src/components/CircularRating/CircularRating.tsx +3 -2
  233. package/src/components/ClusterBubble/ClusterBubble.tsx +2 -1
  234. package/src/components/CoverageBarComparison/CoverageBarComparison.tsx +3 -2
  235. package/src/components/CoverageRing/CoverageRing.tsx +2 -1
  236. package/src/components/DebitCard/DebitCard.tsx +2 -1
  237. package/src/components/Disclaimer/Disclaimer.tsx +2 -1
  238. package/src/components/Divider/Divider.tsx +2 -1
  239. package/src/components/DonutChart/DonutChart.tsx +6 -5
  240. package/src/components/DonutChartSummary/DonutChartSummary.tsx +3 -2
  241. package/src/components/Drawer/Drawer.tsx +21 -1
  242. package/src/components/Dropdown/Dropdown.tsx +42 -21
  243. package/src/components/DropdownInput/DropdownInput.tsx +5 -4
  244. package/src/components/EmptyState/EmptyState.tsx +2 -1
  245. package/src/components/ExpandableCheckbox/ExpandableCheckbox.tsx +2 -1
  246. package/src/components/FilterBar/FilterBar.tsx +3 -2
  247. package/src/components/Form/Form.tsx +2 -1
  248. package/src/components/FormField/FormField.tsx +3 -2
  249. package/src/components/FullscreenModal/FullscreenModal.tsx +77 -12
  250. package/src/components/Gauge/Gauge.tsx +2 -1
  251. package/src/components/HStack/HStack.tsx +2 -1
  252. package/src/components/HoldingsCard/HoldingsCard.tsx +2 -1
  253. package/src/components/Icon/Icon.tsx +3 -2
  254. package/src/components/IconButton/IconButton.tsx +3 -2
  255. package/src/components/IconCapsule/IconCapsule.tsx +3 -2
  256. package/src/components/Image/Image.tsx +29 -5
  257. package/src/components/InputSearch/InputSearch.tsx +3 -2
  258. package/src/components/InstitutionBadge/InstitutionBadge.tsx +3 -2
  259. package/src/components/LazyList/LazyList.tsx +2 -1
  260. package/src/components/LinearMeter/LinearMeter.tsx +3 -2
  261. package/src/components/LinearProgress/LinearProgress.tsx +2 -1
  262. package/src/components/ListGroup/ListGroup.tsx +2 -1
  263. package/src/components/ListItem/ListItem.tsx +3 -2
  264. package/src/components/LottieIntroBlock/LottieIntroBlock.tsx +2 -1
  265. package/src/components/LottiePlayer/LottiePlayer.tsx +3 -2
  266. package/src/components/LottiePlayer/LottiePlayer.web.tsx +3 -2
  267. package/src/components/LottiePlayer/loadNativeLottieView.tsx +9 -13
  268. package/src/components/MediaCard/MediaCard.tsx +7 -6
  269. package/src/components/MerchantProfile/MerchantProfile.tsx +2 -1
  270. package/src/components/MessageField/MessageField.tsx +3 -2
  271. package/src/components/MetricLegendItem/MetricLegendItem.tsx +2 -1
  272. package/src/components/MoneyValue/MoneyValue.tsx +2 -1
  273. package/src/components/MonthlyStatusGrid/MonthlyStatusGrid.tsx +5 -4
  274. package/src/components/NavArrow/NavArrow.tsx +3 -2
  275. package/src/components/NoteInput/NoteInput.tsx +2 -1
  276. package/src/components/Nudge/Nudge.tsx +3 -2
  277. package/src/components/Numpad/Numpad.tsx +2 -1
  278. package/src/components/OTP/OTP.tsx +3 -2
  279. package/src/components/Overlay/Overlay.tsx +114 -0
  280. package/src/components/PageHero/PageHero.tsx +2 -1
  281. package/src/components/PaymentFeedback/PaymentFeedback.tsx +2 -1
  282. package/src/components/PlanComparisonCard/PlanComparisonCard.tsx +2 -1
  283. package/src/components/Popup/Popup.tsx +2 -1
  284. package/src/components/PortfolioHero/PortfolioHero.tsx +2 -1
  285. package/src/components/PoweredByLabel/PoweredByLabel.tsx +2 -1
  286. package/src/components/ProductLabel/ProductLabel.tsx +2 -1
  287. package/src/components/ProductOverview/ProductOverview.tsx +2 -1
  288. package/src/components/ProgressBadge/ProgressBadge.tsx +2 -1
  289. package/src/components/Radio/Radio.tsx +2 -1
  290. package/src/components/RangeTrack/RangeTrack.tsx +3 -2
  291. package/src/components/RechargeCard/RechargeCard.tsx +2 -1
  292. package/src/components/SavingsGoalSummary/SavingsGoalSummary.tsx +2 -1
  293. package/src/components/Screen/Screen.tsx +2 -1
  294. package/src/components/Section/Section.tsx +6 -5
  295. package/src/components/SegmentedControl/SegmentedControl.tsx +3 -2
  296. package/src/components/SegmentedTrack/SegmentedTrack.tsx +5 -4
  297. package/src/components/Slot/Slot.tsx +2 -1
  298. package/src/components/Spinner/Spinner.tsx +2 -1
  299. package/src/components/StatGroup/StatGroup.tsx +3 -2
  300. package/src/components/StatItem/StatItem.tsx +2 -1
  301. package/src/components/StatusHero/StatusHero.tsx +2 -1
  302. package/src/components/Stepper/Step.tsx +2 -1
  303. package/src/components/Stepper/StepLabel.tsx +2 -1
  304. package/src/components/Stepper/Stepper.tsx +2 -1
  305. package/src/components/StrengthIndicator/StrengthIndicator.tsx +2 -1
  306. package/src/components/SuggestiveSearch/SuggestiveSearch.tsx +4 -3
  307. package/src/components/SummaryTile/SummaryTile.tsx +2 -1
  308. package/src/components/SupportText/SupportText.tsx +2 -1
  309. package/src/components/SupportText/SupportTextIcon.tsx +2 -1
  310. package/src/components/SwappableAmount/SwappableAmount.tsx +2 -1
  311. package/src/components/Tabs/TabItem.tsx +2 -1
  312. package/src/components/Tabs/Tabs.tsx +2 -1
  313. package/src/components/TestimonialsCard/TestimonialsCard.tsx +163 -0
  314. package/src/components/Text/Text.tsx +2 -1
  315. package/src/components/TextInput/TextInput.tsx +3 -2
  316. package/src/components/ThreadHero/ThreadHero.tsx +2 -1
  317. package/src/components/Title/Title.tsx +2 -1
  318. package/src/components/Toast/Toast.tsx +2 -1
  319. package/src/components/Toast/ToastProvider.tsx +2 -1
  320. package/src/components/Toast/useToast.ts +3 -2
  321. package/src/components/Toggle/Toggle.tsx +2 -1
  322. package/src/components/Tooltip/Tooltip.tsx +3 -2
  323. package/src/components/TransactionBubble/TransactionBubble.tsx +2 -1
  324. package/src/components/TransactionDetails/TransactionDetails.tsx +3 -2
  325. package/src/components/TransactionStatus/TransactionStatus.tsx +3 -2
  326. package/src/components/UpiHandle/UpiHandle.tsx +3 -2
  327. package/src/components/VStack/VStack.tsx +2 -1
  328. package/src/components/docs/modeControls.tsx +122 -0
  329. package/src/components/index.ts +2 -0
  330. package/src/design-tokens/JFSThemeProvider.tsx +4 -3
  331. package/src/design-tokens/figma-modes.generated.ts +396 -0
  332. package/src/design-tokens/index.ts +1 -0
  333. package/src/icons/registry.ts +1 -1
  334. package/src/skeleton/Skeleton.tsx +2 -1
  335. package/src/utils/react-utils.ts +3 -2
@@ -1,8 +1,9 @@
1
- import React, { useMemo, useRef } from 'react'
1
+ import React, { useMemo, useRef, useState, useCallback } from 'react'
2
2
  import {
3
3
  View,
4
4
  Text,
5
5
  Animated,
6
+ type LayoutChangeEvent,
6
7
  type StyleProp,
7
8
  type ViewStyle,
8
9
  type TextStyle,
@@ -16,6 +17,7 @@ import Disclaimer from '../Disclaimer/Disclaimer'
16
17
  import IconButton from '../IconButton/IconButton'
17
18
  import ActionFooter from '../ActionFooter/ActionFooter'
18
19
  import Slot from '../Slot/Slot'
20
+ import type { Modes } from '../../design-tokens'
19
21
 
20
22
  // ---------------------------------------------------------------------------
21
23
  // Forced modes
@@ -71,6 +73,12 @@ export type FullscreenModalProps = {
71
73
  heroHeight?: number
72
74
  /** Whether to render the floating close button (top-right). Defaults to true. */
73
75
  showClose?: boolean
76
+ /**
77
+ * Additional vertical offset (in px) applied to the floating close button's
78
+ * top position, on top of the base inset (`12 + safe-area top`). Positive
79
+ * values push it further down. Defaults to 0.
80
+ */
81
+ closeOffsetY?: number
74
82
  /** Press handler for the close button. */
75
83
  onClose?: () => void
76
84
  /** Accessibility label for the close button. */
@@ -93,7 +101,7 @@ export type FullscreenModalProps = {
93
101
  * and `context5` is always forced to `'Fullscreen Modal'` (non-overridable).
94
102
  * The resolved modes cascade to the body, hero media, and the `ActionFooter`.
95
103
  */
96
- modes?: Record<string, any>
104
+ modes?: Modes
97
105
  /** Style overrides for the outer container. */
98
106
  style?: StyleProp<ViewStyle>
99
107
  /** Style overrides for the transparent body wrapper. */
@@ -112,7 +120,7 @@ type HeroTextProps = {
112
120
  headline?: string
113
121
  supportingText?: string
114
122
  priceText?: string
115
- modes: Record<string, any>
123
+ modes: Modes
116
124
  }
117
125
 
118
126
  function HeroText({ eyebrow, headline, supportingText, priceText, modes }: HeroTextProps) {
@@ -230,6 +238,7 @@ function FullscreenModal({
230
238
  heroMedia,
231
239
  heroHeight = 420,
232
240
  showClose = true,
241
+ closeOffsetY = 0,
233
242
  onClose,
234
243
  closeAccessibilityLabel = 'Close',
235
244
  footer,
@@ -268,8 +277,8 @@ function FullscreenModal({
268
277
  // SafeAreaProvider — every inset is 0, so the layout is unchanged.
269
278
  const insets = useSafeAreaInsets()
270
279
  const closeButtonInsetStyle = useMemo<ViewStyle>(
271
- () => ({ top: 12 + insets.top }),
272
- [insets.top]
280
+ () => ({ top: 12 + insets.top + closeOffsetY }),
281
+ [insets.top, closeOffsetY]
273
282
  )
274
283
  // Extend (not replace) the footer's token bottom padding by the bottom inset
275
284
  // so the action button never sits under the system navigation area.
@@ -293,11 +302,57 @@ function FullscreenModal({
293
302
  )
294
303
  const heroTranslateY = useMemo(() => Animated.multiply(scrollY, -1), [scrollY])
295
304
 
296
- const processedHeroMedia = useMemo(
297
- () =>
298
- heroMedia ? cloneChildrenWithModes(heroMedia, modes, FULLSCREEN_MODAL_FORCED_MODES) : null,
299
- [heroMedia, modes]
300
- )
305
+ // The hero media is a full-bleed background pinned to the top of the modal.
306
+ // Its wrapper is absolutely positioned (`top/left/right: 0`) so it never
307
+ // contributes to scroll height. We measure the modal's own width so we can
308
+ // give the hero media a DEFINITE { width, height } box (see
309
+ // `processedHeroMedia` below) — relying on the media's own `width: '100%'` +
310
+ // `aspectRatio` is unreliable inside an indefinite-height absolute box (RN's
311
+ // `<Image>` falls back to its intrinsic width and leaves a gap), so we size
312
+ // it explicitly here instead.
313
+ const [containerWidth, setContainerWidth] = useState(0)
314
+ const onContainerLayout = useCallback((e: LayoutChangeEvent) => {
315
+ const w = e.nativeEvent.layout.width
316
+ setContainerWidth((prev) => (prev !== w ? w : prev))
317
+ }, [])
318
+
319
+ const processedHeroMedia = useMemo(() => {
320
+ if (!heroMedia) return null
321
+ // Defer rendering the hero until we have measured the modal width. This
322
+ // matters for image sharpness: React Native decodes a bitmap once, on the
323
+ // first render, and caches it. If we rendered the media before knowing the
324
+ // final box, that first decode would be sized/sampled for the wrong box and
325
+ // the cached (downsampled) bitmap would then just be scaled up — blurry.
326
+ // Rendering only once the explicit { width, height } box is known means the
327
+ // very first decode is already full-resolution for the correct box.
328
+ if (containerWidth <= 0) return null
329
+ const withModes = cloneChildrenWithModes(heroMedia, modes, FULLSCREEN_MODAL_FORCED_MODES)
330
+
331
+ // Force the hero to fill the modal width edge to edge, top-aligned, with the
332
+ // height derived from the media's native aspect ratio.
333
+ //
334
+ // Why we inject explicit width/height instead of relying on the media's own
335
+ // `width: '100%'` + `aspectRatio`: the hero wrapper is absolutely positioned
336
+ // with an INDEFINITE height, and in that layout context React Native's
337
+ // `<Image>` falls back to its INTRINSIC width (so a 361px-wide asset renders
338
+ // 361px wide and leaves a gap on the right) rather than stretching to the
339
+ // parent. By computing `height = containerWidth / ratio` here and passing a
340
+ // DEFINITE { width, height } box (which makes `<Image>` skip aspectRatio and
341
+ // cover-fit into that exact box), the hero always fills the width with the
342
+ // correct ratio-derived height.
343
+ return React.Children.map(withModes, (child) => {
344
+ if (!React.isValidElement(child)) return child
345
+ const props = child.props as { ratio?: number; width?: unknown; height?: unknown }
346
+ const ratio = typeof props.ratio === 'number' && props.ratio > 0 ? props.ratio : undefined
347
+ // Only size media that exposes a numeric `ratio` and hasn't already been
348
+ // given an explicit box by the caller.
349
+ if (ratio == null || props.width != null || props.height != null) return child
350
+ return React.cloneElement(child, {
351
+ width: containerWidth,
352
+ height: containerWidth / ratio,
353
+ } as Partial<typeof props>)
354
+ })
355
+ }, [heroMedia, modes, containerWidth])
301
356
 
302
357
  const processedChildren = useMemo(
303
358
  () =>
@@ -362,7 +417,7 @@ function FullscreenModal({
362
417
  }
363
418
 
364
419
  return (
365
- <View style={[rootStyle, style]} testID={testID}>
420
+ <View style={[rootStyle, style]} testID={testID} onLayout={onContainerLayout}>
366
421
  {/*
367
422
  * Layout model:
368
423
  * - `processedHeroMedia` is a ROOT-LEVEL full-bleed background pinned to
@@ -380,7 +435,17 @@ function FullscreenModal({
380
435
  */}
381
436
  {processedHeroMedia ? (
382
437
  <Animated.View
383
- style={[heroBackgroundStyle, { transform: [{ translateY: heroTranslateY }] }]}
438
+ style={[
439
+ heroBackgroundStyle,
440
+ // Give the absolute wrapper a DEFINITE width (the measured modal
441
+ // width) so the media's `width: '100%'` + `aspectRatio` resolves to
442
+ // a true edge-to-edge fill with a ratio-derived height, top-aligned.
443
+ // Before the first layout pass `containerWidth` is 0 — fall back to
444
+ // stretching via `left/right: 0` so there is no flash of a mis-sized
445
+ // image.
446
+ containerWidth > 0 ? { width: containerWidth } : null,
447
+ { transform: [{ translateY: heroTranslateY }] },
448
+ ]}
384
449
  pointerEvents="none"
385
450
  >
386
451
  {processedHeroMedia}
@@ -5,6 +5,7 @@ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
5
5
  import { useTokens } from '../../design-tokens/JFSThemeProvider'
6
6
  import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils'
7
7
  import SupportText, { type SupportTextProps } from '../SupportText/SupportText'
8
+ import type { Modes } from '../../design-tokens'
8
9
 
9
10
  type GaugeBaseProps = Omit<React.ComponentProps<typeof View>, 'children' | 'style'>
10
11
 
@@ -32,7 +33,7 @@ export type GaugeProps = GaugeBaseProps & {
32
33
  /** Hides default support text when no custom readout slot is provided. */
33
34
  showSupportText?: boolean
34
35
  /** Design token modes forwarded to token lookups and slot children. */
35
- modes?: Record<string, any>
36
+ modes?: Modes
36
37
  /** Slot rendered in the center of the gauge arc. Receives `modes` recursively. */
37
38
  children?: React.ReactNode
38
39
  /** Container style override. */
@@ -3,6 +3,7 @@ import { View, StyleProp, ViewStyle, ViewProps } from 'react-native'
3
3
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
4
4
  import { useTokens } from '../../design-tokens/JFSThemeProvider'
5
5
  import { cloneChildrenWithModes, EMPTY_MODES } from '../../utils/react-utils'
6
+ import type { Modes } from '../../design-tokens'
6
7
 
7
8
  export interface HStackProps extends ViewProps {
8
9
  /**
@@ -35,7 +36,7 @@ export interface HStackProps extends ViewProps {
35
36
  /**
36
37
  * Modes object to override default variable values.
37
38
  */
38
- modes?: Record<string, any>;
39
+ modes?: Modes;
39
40
  }
40
41
 
41
42
  /**
@@ -11,6 +11,7 @@ import {
11
11
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
12
12
  import Radio from '../Radio/Radio'
13
13
  import { EMPTY_MODES } from '../../utils/react-utils'
14
+ import type { Modes } from '../../design-tokens'
14
15
 
15
16
  export interface HoldingsCardDetailItem {
16
17
  label: string
@@ -33,7 +34,7 @@ export interface HoldingsCardProps {
33
34
  /** Called when the card is pressed (toggles selection). */
34
35
  onPress?: () => void
35
36
  /** Modes object for design-token resolution. */
36
- modes?: Record<string, any>
37
+ modes?: Modes
37
38
  /** Custom style for the outer container. */
38
39
  style?: StyleProp<ViewStyle>
39
40
  /** Test ID for testing. */
@@ -10,6 +10,7 @@ import { useTokens } from '../../design-tokens/JFSThemeProvider'
10
10
  import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils'
11
11
  import BaseIcon from '../../icons/Icon'
12
12
  import type { UnifiedSource } from '../../utils/MediaSource'
13
+ import type { Modes } from '../../design-tokens'
13
14
 
14
15
  type IconProps = AccessibilityProps & {
15
16
  /**
@@ -43,7 +44,7 @@ type IconProps = AccessibilityProps & {
43
44
  * from the `icon/size` design token.
44
45
  */
45
46
  size?: number
46
- modes?: Record<string, any>
47
+ modes?: Modes
47
48
  style?: StyleProp<ViewStyle>
48
49
  }
49
50
 
@@ -53,7 +54,7 @@ interface IconTokens {
53
54
  iconSize: number
54
55
  }
55
56
 
56
- function resolveIconTokens(modes: Record<string, any>): IconTokens {
57
+ function resolveIconTokens(modes: Modes): IconTokens {
57
58
  const iconColor = (getVariableByName('icon/color', modes) || '#ad8444') as string
58
59
  const iconSize = (getVariableByName('icon/size', modes) || 18) as number
59
60
  const paddingLeft = (getVariableByName('icon/padding/left', modes) || 0) as number
@@ -14,6 +14,7 @@ import { EMPTY_MODES } from '../../utils/react-utils'
14
14
  import type { UnifiedSource } from '../../utils/MediaSource'
15
15
  import Skeleton from '../../skeleton/Skeleton'
16
16
  import { useSkeleton } from '../../skeleton/SkeletonGroup'
17
+ import type { Modes } from '../../design-tokens'
17
18
 
18
19
  type IconButtonProps = SafePressableProps & {
19
20
  /** Built-in icon name from the registry (default state). */
@@ -26,7 +27,7 @@ type IconButtonProps = SafePressableProps & {
26
27
  * follows design tokens just like a built-in icon. See {@link UnifiedSource}.
27
28
  */
28
29
  source?: UnifiedSource;
29
- modes?: Record<string, any>;
30
+ modes?: Modes;
30
31
  onPress?: () => void;
31
32
  disabled?: boolean;
32
33
  style?: StyleProp<ViewStyle>;
@@ -96,7 +97,7 @@ interface IconButtonTokens {
96
97
  iconSize: number;
97
98
  }
98
99
 
99
- function resolveIconButtonTokens(modes: Record<string, any>, disabled: boolean): IconButtonTokens {
100
+ function resolveIconButtonTokens(modes: Modes, disabled: boolean): IconButtonTokens {
100
101
  const radiusRaw = (getVariableByName('iconButton/radius', modes) ?? 9999) as number
101
102
  const padding = (getVariableByName('iconButton/padding', modes) ?? 12) as number
102
103
  const backgroundColor = (getVariableByName('iconButton/background', modes) ?? '#cfa159') as string
@@ -5,6 +5,7 @@ import { useTokens } from '../../design-tokens/JFSThemeProvider'
5
5
  import { EMPTY_MODES } from '../../utils/react-utils'
6
6
  import Icon from '../../icons/Icon'
7
7
  import type { UnifiedSource } from '../../utils/MediaSource'
8
+ import type { Modes } from '../../design-tokens'
8
9
 
9
10
  type IconCapsuleProps = {
10
11
  iconName?: string;
@@ -17,7 +18,7 @@ type IconCapsuleProps = {
17
18
  * {@link UnifiedSource}.
18
19
  */
19
20
  source?: UnifiedSource;
20
- modes?: Record<string, any>;
21
+ modes?: Modes;
21
22
  accessibilityLabel?: string;
22
23
  accessibilityRole?: string;
23
24
  } & React.ComponentProps<typeof View>;
@@ -28,7 +29,7 @@ interface IconCapsuleTokens {
28
29
  iconSize: number;
29
30
  }
30
31
 
31
- function resolveIconCapsuleTokens(modes: Record<string, any>): IconCapsuleTokens {
32
+ function resolveIconCapsuleTokens(modes: Modes): IconCapsuleTokens {
32
33
  const size = (getVariableByName('iconCapsule/size', modes) || 42) as number
33
34
  const radiusRaw = (getVariableByName('iconCapsule/radius', modes) || 9999) as number
34
35
  const backgroundColor = (getVariableByName('iconCapsule/background', modes) || '#cfa159') as string
@@ -8,6 +8,8 @@ import {
8
8
  type ViewStyle,
9
9
  type ImageResizeMode,
10
10
  } from 'react-native'
11
+
12
+ type ImageResizeMethod = 'auto' | 'resize' | 'scale' | 'none'
11
13
  import Skeleton from '../../skeleton/Skeleton'
12
14
  import { useSkeleton } from '../../skeleton/SkeletonGroup'
13
15
 
@@ -33,6 +35,21 @@ export type ImageProps = {
33
35
  ratio?: number | undefined
34
36
  /** How the image is fit inside its box. Defaults to `'cover'`. */
35
37
  resizeMode?: ImageResizeMode | undefined
38
+ /**
39
+ * (Android only) How the bitmap is resampled when the source resolution
40
+ * differs from the rendered box.
41
+ *
42
+ * RN's own default is `'auto'`, which for large source images silently picks
43
+ * `'resize'`: a pre-decode software downsample that DESTROYS detail and makes
44
+ * big hero/background images look soft/pixelated even when the asset is
45
+ * high-res. To avoid that, this component defaults to:
46
+ * - `'none'` when an explicit `width` + `height` box is set (full-bleed
47
+ * hero/background usage — full resolution, maximum sharpness), and
48
+ * - `'scale'` otherwise (GPU scaling — high quality and memory-safe for
49
+ * ordinary aspect-ratio images).
50
+ * Pass an explicit value to override. No-op on iOS/web.
51
+ */
52
+ resizeMethod?: ImageResizeMethod | undefined
36
53
  /**
37
54
  * Optional explicit width. If omitted and a `ratio` is set, the image
38
55
  * defaults to `width: '100%'` so it fills its parent.
@@ -96,6 +113,7 @@ function Image({
96
113
  imageSource,
97
114
  ratio = DEFAULT_RATIO,
98
115
  resizeMode = 'cover',
116
+ resizeMethod,
99
117
  width,
100
118
  height,
101
119
  borderRadius,
@@ -107,11 +125,16 @@ function Image({
107
125
  }: ImageProps) {
108
126
  const source = useMemo(() => normalizeSource(imageSource), [imageSource])
109
127
 
128
+ // Explicit { width, height } means a "fill an exact box" layout — typically a
129
+ // full-bleed hero/background where the asset is high-res and sharpness
130
+ // matters most. There, default to `'none'` (full-resolution, no pre-decode
131
+ // downsample) so detail is never thrown away. Aspect-ratio images keep the
132
+ // memory-safe `'scale'` default. A caller-supplied `resizeMethod` always wins.
133
+ const isExplicitBox = width != null && height != null
134
+ const effectiveResizeMethod: ImageResizeMethod =
135
+ resizeMethod ?? (isExplicitBox ? 'none' : 'scale')
136
+
110
137
  const layoutStyle: ImageStyle = useMemo(() => {
111
- // If the caller has fully specified width AND height, they're doing a
112
- // non-aspect layout (e.g. "fill the parent") — respect that and skip
113
- // `aspectRatio` so it doesn't conflict.
114
- const isExplicitBox = width != null && height != null
115
138
  const s: ImageStyle = {
116
139
  width: width ?? '100%',
117
140
  ...(isExplicitBox
@@ -120,7 +143,7 @@ function Image({
120
143
  }
121
144
  if (borderRadius != null) s.borderRadius = borderRadius
122
145
  return s
123
- }, [ratio, width, height, borderRadius])
146
+ }, [ratio, width, height, borderRadius, isExplicitBox])
124
147
 
125
148
  const { active: groupActive } = useSkeleton()
126
149
  const isLoading = loading ?? groupActive
@@ -146,6 +169,7 @@ function Image({
146
169
  source={source}
147
170
  style={[layoutStyle, style]}
148
171
  resizeMode={resizeMode}
172
+ resizeMethod={effectiveResizeMethod}
149
173
  accessibilityLabel={accessibilityLabel}
150
174
  accessibilityElementsHidden={accessibilityElementsHidden}
151
175
  importantForAccessibility={importantForAccessibility}
@@ -4,6 +4,7 @@ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
4
4
  import { EMPTY_MODES } from '../../utils/react-utils'
5
5
  import Icon from '../../icons/Icon'
6
6
  import TextInput from '../TextInput/TextInput'
7
+ import type { Modes } from '../../design-tokens'
7
8
 
8
9
  /**
9
10
  * SupportText component derived from Figma design.
@@ -15,7 +16,7 @@ type SupportTextProps = {
15
16
  * Defaults to 'ic_info'.
16
17
  */
17
18
  iconName?: string;
18
- modes?: Record<string, any>;
19
+ modes?: Modes;
19
20
  style?: StyleProp<ViewStyle>;
20
21
  }
21
22
 
@@ -64,7 +65,7 @@ export type InputSearchProps = {
64
65
  * (e.g. 'ic_info', 'ic_cart'). Defaults to 'ic_info'.
65
66
  */
66
67
  supportTextIcon?: string;
67
- modes?: Record<string, any>;
68
+ modes?: Modes;
68
69
  containerStyle?: StyleProp<ViewStyle>;
69
70
 
70
71
  // Props to pass through to TextInput
@@ -10,6 +10,7 @@ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
10
10
  import { useTokens } from '../../design-tokens/JFSThemeProvider'
11
11
  import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils'
12
12
  import MediaSource, { type UnifiedSource } from '../../utils/MediaSource'
13
+ import type { Modes } from '../../design-tokens'
13
14
 
14
15
  // Default avatar asset (shared with the Avatar component) so that
15
16
  // InstitutionBadge has a sensible visual fallback when no `source` is
@@ -35,7 +36,7 @@ export type InstitutionBadgeProps = InstitutionBadgeBaseProps & {
35
36
  /** Slot replacing the default Avatar (e.g. for monogram avatars). Receives `modes` recursively. */
36
37
  avatarSlot?: React.ReactNode
37
38
  /** Design token modes forwarded to token lookups and the Avatar slot. */
38
- modes?: Record<string, any>
39
+ modes?: Modes
39
40
  /** Container style override. */
40
41
  style?: StyleProp<ViewStyle>
41
42
  /** Label style override. */
@@ -77,7 +78,7 @@ const toFontWeight = (value: unknown, fallback: TextStyle['fontWeight']) => {
77
78
  }
78
79
 
79
80
  function resolveInstitutionBadgeTokens(
80
- modes: Record<string, any>
81
+ modes: Modes
81
82
  ): InstitutionBadgeTokens {
82
83
  const gap = toNumber(getVariableByName('institutionBadge/gap', modes), 8)
83
84
 
@@ -2,10 +2,11 @@ import React from 'react'
2
2
  import { View, type StyleProp, type ViewStyle } from 'react-native'
3
3
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
4
4
  import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils'
5
+ import type { Modes } from '../../design-tokens'
5
6
 
6
7
  type LazyListProps = {
7
8
  listGroupsSlot?: React.ReactNode;
8
- modes?: Record<string, any>;
9
+ modes?: Modes;
9
10
  style?: StyleProp<ViewStyle>;
10
11
  accessibilityLabel?: string;
11
12
  accessibilityHint?: string;
@@ -4,10 +4,11 @@ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
4
4
  import { EMPTY_MODES } from '../../utils/react-utils'
5
5
  import MoneyValue from '../MoneyValue/MoneyValue'
6
6
  import LinearProgress from '../LinearProgress/LinearProgress'
7
+ import type { Modes } from '../../design-tokens'
7
8
 
8
9
  type LinearMeterLabelProps = {
9
10
  children: React.ReactNode
10
- modes?: Record<string, any>
11
+ modes?: Modes
11
12
  style?: StyleProp<TextStyle>
12
13
  } & React.ComponentProps<typeof Text>
13
14
 
@@ -41,7 +42,7 @@ const LinearMeterLabel = ({
41
42
 
42
43
  export type LinearMeterProps = {
43
44
  value?: number // 0 to 1
44
- modes?: Record<string, any>
45
+ modes?: Modes
45
46
  style?: StyleProp<ViewStyle>
46
47
  trackStyle?: StyleProp<ViewStyle>
47
48
  indicatorStyle?: StyleProp<ViewStyle>
@@ -7,12 +7,13 @@ import {
7
7
  } from 'react-native'
8
8
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
9
9
  import { EMPTY_MODES } from '../../utils/react-utils'
10
+ import type { Modes } from '../../design-tokens'
10
11
 
11
12
  export type LinearProgressProps = {
12
13
  /** Progress value between 0 and 1. Values are clamped. */
13
14
  value?: number
14
15
  /** Design token modes for theming */
15
- modes?: Record<string, any>
16
+ modes?: Modes
16
17
  /** Override container styles (the track wrapper) */
17
18
  style?: StyleProp<ViewStyle>
18
19
  /** Override the track styles */
@@ -7,12 +7,13 @@ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
7
7
  * This ensures that all child components in slots receive the modes prop from the parent.
8
8
  */
9
9
  import { EMPTY_MODES, cloneChildrenWithModes, flattenChildren } from '../../utils/react-utils'
10
+ import type { Modes } from '../../design-tokens'
10
11
 
11
12
  type ListGroupProps = {
12
13
  label?: string;
13
14
  listGroupSlot?: React.ReactNode;
14
15
  children?: React.ReactNode;
15
- modes?: Record<string, any>;
16
+ modes?: Modes;
16
17
  style?: StyleProp<ViewStyle>;
17
18
  accessibilityLabel?: string;
18
19
  accessibilityHint?: string;
@@ -14,6 +14,7 @@ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
14
14
  import NavArrow from '../NavArrow/NavArrow'
15
15
  import { usePressableWebSupport, type WebAccessibilityProps } from '../../utils/web-platform-utils'
16
16
  import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils'
17
+ import type { Modes } from '../../design-tokens'
17
18
 
18
19
  type ListItemProps = {
19
20
  layout?: 'Vertical' | 'Horizontal';
@@ -33,7 +34,7 @@ type ListItemProps = {
33
34
  endSlot?: React.ReactNode;
34
35
  /** Whether to show the NavArrow on the far right (Horizontal layout only). Defaults to true. */
35
36
  navArrow?: boolean;
36
- modes?: Record<string, any>;
37
+ modes?: Modes;
37
38
  onPress?: () => void;
38
39
  style?: StyleProp<ViewStyle>;
39
40
  contentStyle?: StyleProp<ViewStyle>;
@@ -79,7 +80,7 @@ interface ListItemTokens {
79
80
  resolvedModes: Record<string, any>;
80
81
  }
81
82
 
82
- function resolveListItemTokens(modes: Record<string, any>): ListItemTokens {
83
+ function resolveListItemTokens(modes: Modes): ListItemTokens {
83
84
  // Modes used to cascade into slot children (leading / supportSlot / trailing).
84
85
  // We do NOT inject an `AppearanceBrand` default here: slot content such as
85
86
  // Buttons or Badges carry their own intended appearance, so forcing one onto
@@ -10,6 +10,7 @@ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
10
10
  import { useTokens } from '../../design-tokens/JFSThemeProvider'
11
11
  import Button from '../Button/Button'
12
12
  import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils'
13
+ import type { Modes } from '../../design-tokens'
13
14
 
14
15
  const DEFAULT_MEDIA_SIZE = 117
15
16
 
@@ -40,7 +41,7 @@ export type LottieIntroBlockProps = {
40
41
  */
41
42
  buttonSlot?: React.ReactNode
42
43
  /** Mode configuration for design-token theming. */
43
- modes?: Record<string, any>
44
+ modes?: Modes
44
45
  /** Style overrides applied to the outer container. */
45
46
  style?: StyleProp<ViewStyle>
46
47
  testID?: string
@@ -4,6 +4,7 @@ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
4
4
  import { useTokens } from '../../design-tokens/JFSThemeProvider'
5
5
  import { EMPTY_MODES } from '../../utils/react-utils'
6
6
  import { getNativeLottieView } from './loadNativeLottieView'
7
+ import type { Modes } from '../../design-tokens'
7
8
 
8
9
  /**
9
10
  * A parsed Lottie animation. The JSON object you get from
@@ -39,7 +40,7 @@ export type LottiePlayerProps = {
39
40
  /** Loop the animation. Defaults to `true`. */
40
41
  loop?: boolean
41
42
  /** Mode configuration for design-token theming. */
42
- modes?: Record<string, any>
43
+ modes?: Modes
43
44
  /** Style overrides applied to the underlying view. */
44
45
  style?: StyleProp<ViewStyle>
45
46
  /** Accessibility label. Lottie is decorative by default. */
@@ -51,7 +52,7 @@ const DEFAULT_SIZE = 117
51
52
 
52
53
  function resolveSize(
53
54
  size: LottiePlayerProps['size'],
54
- modes: Record<string, any>
55
+ modes: Modes
55
56
  ) {
56
57
  if (typeof size === 'number') return { width: size, height: size }
57
58
  if (size && typeof size === 'object') return size
@@ -4,6 +4,7 @@ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
4
4
  import { useTokens } from '../../design-tokens/JFSThemeProvider'
5
5
  import { EMPTY_MODES } from '../../utils/react-utils'
6
6
  import { getWebLottieView } from './loadWebLottieView'
7
+ import type { Modes } from '../../design-tokens'
7
8
 
8
9
  export type LottieAnimationSource = Record<string, unknown>
9
10
 
@@ -12,7 +13,7 @@ export type LottiePlayerProps = {
12
13
  size?: number | { width: number; height: number }
13
14
  autoPlay?: boolean
14
15
  loop?: boolean
15
- modes?: Record<string, any>
16
+ modes?: Modes
16
17
  style?: StyleProp<ViewStyle>
17
18
  accessibilityLabel?: string
18
19
  testID?: string
@@ -22,7 +23,7 @@ const DEFAULT_SIZE = 117
22
23
 
23
24
  function resolveSize(
24
25
  size: LottiePlayerProps['size'],
25
- modes: Record<string, any>
26
+ modes: Modes
26
27
  ) {
27
28
  if (typeof size === 'number') return { width: size, height: size }
28
29
  if (size && typeof size === 'object') return size
@@ -14,17 +14,6 @@ const INSTALL_HINT =
14
14
  ' npm install lottie-react-native\n' +
15
15
  ' cd ios && pod install'
16
16
 
17
- /**
18
- * Metro resolves `require('lottie-react-native')` at bundle time even inside
19
- * try/catch, which breaks apps that import `jfs-components` without having
20
- * the optional peer installed. Splitting the module id into a runtime string
21
- * keeps Metro from statically linking it — the native module is loaded only
22
- * when present in the consumer's node_modules.
23
- */
24
- function resolveNativeLottieModuleName() {
25
- return ['lottie', '-react', '-native'].join('')
26
- }
27
-
28
17
  function LottieUnavailableView({ style }: Pick<NativeLottieViewProps, 'style'>) {
29
18
  if (__DEV__) {
30
19
  return (
@@ -75,10 +64,17 @@ export function getNativeLottieView(): React.ComponentType<NativeLottieViewProps
75
64
  if (cachedView !== undefined) return cachedView
76
65
 
77
66
  try {
78
- const mod = require(resolveNativeLottieModuleName()) as {
67
+ // Static require so Metro resolves the module by its build-time numeric id.
68
+ // A runtime-constructed string path is NOT resolvable by Metro's `require`
69
+ // (it indexes modules by number, not path), so it would always throw and
70
+ // fall back to the install hint even when the package is installed. The
71
+ // dependency stays an *optional* peer: apps that use LottiePlayer install
72
+ // it; apps that don't simply never import this module.
73
+ const mod = require('lottie-react-native') as {
79
74
  default?: React.ComponentType<NativeLottieViewProps>
75
+ LottieView?: React.ComponentType<NativeLottieViewProps>
80
76
  }
81
- cachedView = mod.default ?? LottieUnavailable
77
+ cachedView = mod.default ?? mod.LottieView ?? LottieUnavailable
82
78
  } catch {
83
79
  cachedView = LottieUnavailable
84
80
  }