jfs-components 0.1.2 → 0.1.12

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 (287) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/lib/commonjs/components/Accordion/Accordion.js +2 -1
  3. package/lib/commonjs/components/AccordionCheckbox/AccordionCheckbox.js +4 -3
  4. package/lib/commonjs/components/AccountCard/AccountCard.js +4 -3
  5. package/lib/commonjs/components/AllocationComparisonChart/AllocationComparisonChart.js +9 -6
  6. package/lib/commonjs/components/AmountInput/AmountInput.js +8 -5
  7. package/lib/commonjs/components/AreaLineChart/AreaLineChart.js +11 -7
  8. package/lib/commonjs/components/Badge/Badge.js +47 -8
  9. package/lib/commonjs/components/BenefitCard/BenefitCard.js +231 -0
  10. package/lib/commonjs/components/BrandChip/BrandChip.js +3 -3
  11. package/lib/commonjs/components/Button/Button.js +2 -1
  12. package/lib/commonjs/components/CardAdvisory/CardAdvisory.js +2 -1
  13. package/lib/commonjs/components/CardBankAccount/CardBankAccount.js +3 -2
  14. package/lib/commonjs/components/CardCTA/CardCTA.js +197 -27
  15. package/lib/commonjs/components/CardInsight/CardInsight.js +5 -1
  16. package/lib/commonjs/components/CcCard/CcCard.js +470 -0
  17. package/lib/commonjs/components/Checkbox/Checkbox.js +4 -3
  18. package/lib/commonjs/components/CheckboxItem/CheckboxItem.js +4 -3
  19. package/lib/commonjs/components/CircularProgressBar/CircularProgressBar.js +7 -3
  20. package/lib/commonjs/components/CircularProgressBarDoted/CircularProgressBarDoted.js +3 -2
  21. package/lib/commonjs/components/CircularRating/CircularRating.js +2 -1
  22. package/lib/commonjs/components/ClusterBubble/ClusterBubble.js +3 -2
  23. package/lib/commonjs/components/CompareTable/CompareTable.js +401 -0
  24. package/lib/commonjs/components/ComparisonBar/ComparisonBar.js +266 -0
  25. package/lib/commonjs/components/CoverageBarComparison/CoverageBarComparison.js +3 -2
  26. package/lib/commonjs/components/DonutChart/DonutChart.js +4 -3
  27. package/lib/commonjs/components/Dropdown/Dropdown.js +3 -2
  28. package/lib/commonjs/components/DropdownInput/DropdownInput.js +38 -5
  29. package/lib/commonjs/components/ExpandableCheckbox/ExpandableCheckbox.js +2 -1
  30. package/lib/commonjs/components/FormField/FormField.js +45 -4
  31. package/lib/commonjs/components/Gauge/Gauge.js +1 -1
  32. package/lib/commonjs/components/HoldingsCard/HoldingsCard.js +3 -2
  33. package/lib/commonjs/components/InputSearch/InputSearch.js +6 -4
  34. package/lib/commonjs/components/InstitutionBadge/InstitutionBadge.js +2 -1
  35. package/lib/commonjs/components/ListGroup/ListGroup.js +2 -1
  36. package/lib/commonjs/components/ListItem/ListItem.js +3 -2
  37. package/lib/commonjs/components/MediaCard/MediaCard.js +4 -2
  38. package/lib/commonjs/components/MetricLegendItem/MetricLegendItem.js +3 -2
  39. package/lib/commonjs/components/MonthlyStatusGrid/MonthlyStatusGrid.js +6 -3
  40. package/lib/commonjs/components/NoteInput/NoteInput.js +6 -5
  41. package/lib/commonjs/components/PdpCcCard/PdpCcCard.js +273 -0
  42. package/lib/commonjs/components/PoweredByLabel/PoweredByLabel.js +3 -2
  43. package/lib/commonjs/components/ProductMerchandisingCard/ProductMerchandisingCard.js +427 -0
  44. package/lib/commonjs/components/ProductOverview/ProductOverview.js +4 -3
  45. package/lib/commonjs/components/ProgressBadge/ProgressBadge.js +2 -2
  46. package/lib/commonjs/components/ProjectionMarker/ProjectionMarker.js +162 -0
  47. package/lib/commonjs/components/Radio/Radio.js +5 -5
  48. package/lib/commonjs/components/Section/Section.js +3 -2
  49. package/lib/commonjs/components/Slider/Slider.js +474 -0
  50. package/lib/commonjs/components/Stack/Stack.js +86 -0
  51. package/lib/commonjs/components/SuggestiveSearch/SuggestiveSearch.js +10 -1
  52. package/lib/commonjs/components/SummaryTile/SummaryTile.js +3 -2
  53. package/lib/commonjs/components/Table/Table.js +324 -0
  54. package/lib/commonjs/components/Text/Text.js +2 -1
  55. package/lib/commonjs/components/TextInput/TextInput.js +22 -9
  56. package/lib/commonjs/components/TextSegment/TextSegment.js +119 -0
  57. package/lib/commonjs/components/ThreadHero/ThreadHero.js +4 -5
  58. package/lib/commonjs/components/Title/Title.js +2 -1
  59. package/lib/commonjs/components/Toast/Toast.js +3 -2
  60. package/lib/commonjs/components/TransactionBubble/TransactionBubble.js +2 -1
  61. package/lib/commonjs/components/TransactionStatus/TransactionStatus.js +3 -2
  62. package/lib/commonjs/components/UpiHandle/UpiHandle.js +2 -2
  63. package/lib/commonjs/components/index.js +107 -0
  64. package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
  65. package/lib/commonjs/design-tokens/figma-modes.generated.js +39 -9
  66. package/lib/commonjs/icons/registry.js +1 -1
  67. package/lib/commonjs/utils/GlassFill/GlassFill.js +271 -0
  68. package/lib/commonjs/utils/GlassFill/GlassFill.web.js +120 -0
  69. package/lib/commonjs/utils/react-utils.js +78 -0
  70. package/lib/commonjs/utils/web-platform-utils.js +59 -0
  71. package/lib/module/components/Accordion/Accordion.js +3 -2
  72. package/lib/module/components/AccordionCheckbox/AccordionCheckbox.js +5 -4
  73. package/lib/module/components/AccountCard/AccountCard.js +5 -4
  74. package/lib/module/components/AllocationComparisonChart/AllocationComparisonChart.js +10 -7
  75. package/lib/module/components/AmountInput/AmountInput.js +6 -4
  76. package/lib/module/components/AreaLineChart/AreaLineChart.js +12 -8
  77. package/lib/module/components/Badge/Badge.js +49 -10
  78. package/lib/module/components/BenefitCard/BenefitCard.js +225 -0
  79. package/lib/module/components/BrandChip/BrandChip.js +4 -4
  80. package/lib/module/components/Button/Button.js +3 -2
  81. package/lib/module/components/CardAdvisory/CardAdvisory.js +3 -2
  82. package/lib/module/components/CardBankAccount/CardBankAccount.js +4 -3
  83. package/lib/module/components/CardCTA/CardCTA.js +198 -28
  84. package/lib/module/components/CardInsight/CardInsight.js +5 -1
  85. package/lib/module/components/CcCard/CcCard.js +464 -0
  86. package/lib/module/components/Checkbox/Checkbox.js +5 -4
  87. package/lib/module/components/CheckboxItem/CheckboxItem.js +5 -4
  88. package/lib/module/components/CircularProgressBar/CircularProgressBar.js +8 -4
  89. package/lib/module/components/CircularProgressBarDoted/CircularProgressBarDoted.js +4 -3
  90. package/lib/module/components/CircularRating/CircularRating.js +3 -2
  91. package/lib/module/components/ClusterBubble/ClusterBubble.js +4 -3
  92. package/lib/module/components/CompareTable/CompareTable.js +396 -0
  93. package/lib/module/components/ComparisonBar/ComparisonBar.js +260 -0
  94. package/lib/module/components/CoverageBarComparison/CoverageBarComparison.js +4 -3
  95. package/lib/module/components/DonutChart/DonutChart.js +5 -4
  96. package/lib/module/components/Dropdown/Dropdown.js +4 -3
  97. package/lib/module/components/DropdownInput/DropdownInput.js +40 -7
  98. package/lib/module/components/ExpandableCheckbox/ExpandableCheckbox.js +2 -1
  99. package/lib/module/components/FormField/FormField.js +48 -7
  100. package/lib/module/components/Gauge/Gauge.js +1 -1
  101. package/lib/module/components/HoldingsCard/HoldingsCard.js +4 -3
  102. package/lib/module/components/InputSearch/InputSearch.js +6 -4
  103. package/lib/module/components/InstitutionBadge/InstitutionBadge.js +3 -2
  104. package/lib/module/components/ListGroup/ListGroup.js +3 -2
  105. package/lib/module/components/ListItem/ListItem.js +4 -3
  106. package/lib/module/components/MediaCard/MediaCard.js +4 -2
  107. package/lib/module/components/MetricLegendItem/MetricLegendItem.js +4 -3
  108. package/lib/module/components/MonthlyStatusGrid/MonthlyStatusGrid.js +7 -4
  109. package/lib/module/components/NoteInput/NoteInput.js +7 -6
  110. package/lib/module/components/PdpCcCard/PdpCcCard.js +267 -0
  111. package/lib/module/components/PoweredByLabel/PoweredByLabel.js +4 -3
  112. package/lib/module/components/ProductMerchandisingCard/ProductMerchandisingCard.js +421 -0
  113. package/lib/module/components/ProductOverview/ProductOverview.js +5 -4
  114. package/lib/module/components/ProgressBadge/ProgressBadge.js +3 -3
  115. package/lib/module/components/ProjectionMarker/ProjectionMarker.js +157 -0
  116. package/lib/module/components/Radio/Radio.js +5 -4
  117. package/lib/module/components/Section/Section.js +4 -3
  118. package/lib/module/components/Slider/Slider.js +469 -0
  119. package/lib/module/components/Stack/Stack.js +81 -0
  120. package/lib/module/components/SuggestiveSearch/SuggestiveSearch.js +10 -1
  121. package/lib/module/components/SummaryTile/SummaryTile.js +4 -3
  122. package/lib/module/components/Table/Table.js +315 -0
  123. package/lib/module/components/Text/Text.js +3 -2
  124. package/lib/module/components/TextInput/TextInput.js +24 -11
  125. package/lib/module/components/TextSegment/TextSegment.js +114 -0
  126. package/lib/module/components/ThreadHero/ThreadHero.js +5 -6
  127. package/lib/module/components/Title/Title.js +3 -2
  128. package/lib/module/components/Toast/Toast.js +4 -3
  129. package/lib/module/components/TransactionBubble/TransactionBubble.js +3 -2
  130. package/lib/module/components/TransactionStatus/TransactionStatus.js +4 -3
  131. package/lib/module/components/UpiHandle/UpiHandle.js +3 -3
  132. package/lib/module/components/index.js +11 -0
  133. package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
  134. package/lib/module/design-tokens/figma-modes.generated.js +39 -9
  135. package/lib/module/icons/registry.js +1 -1
  136. package/lib/module/utils/GlassFill/GlassFill.js +265 -0
  137. package/lib/module/utils/GlassFill/GlassFill.web.js +115 -0
  138. package/lib/module/utils/react-utils.js +75 -0
  139. package/lib/module/utils/web-platform-utils.js +58 -0
  140. package/lib/typescript/src/components/Accordion/Accordion.d.ts +7 -1
  141. package/lib/typescript/src/components/AccordionCheckbox/AccordionCheckbox.d.ts +7 -1
  142. package/lib/typescript/src/components/AccountCard/AccountCard.d.ts +7 -1
  143. package/lib/typescript/src/components/AllocationComparisonChart/AllocationComparisonChart.d.ts +7 -1
  144. package/lib/typescript/src/components/AmountInput/AmountInput.d.ts +3 -2
  145. package/lib/typescript/src/components/AreaLineChart/AreaLineChart.d.ts +8 -1
  146. package/lib/typescript/src/components/Badge/Badge.d.ts +32 -2
  147. package/lib/typescript/src/components/BenefitCard/BenefitCard.d.ts +93 -0
  148. package/lib/typescript/src/components/BrandChip/BrandChip.d.ts +7 -1
  149. package/lib/typescript/src/components/Button/Button.d.ts +7 -1
  150. package/lib/typescript/src/components/CardAdvisory/CardAdvisory.d.ts +7 -1
  151. package/lib/typescript/src/components/CardBankAccount/CardBankAccount.d.ts +7 -1
  152. package/lib/typescript/src/components/CardCTA/CardCTA.d.ts +27 -5
  153. package/lib/typescript/src/components/CcCard/CcCard.d.ts +137 -0
  154. package/lib/typescript/src/components/Checkbox/Checkbox.d.ts +3 -2
  155. package/lib/typescript/src/components/CheckboxItem/CheckboxItem.d.ts +2 -2
  156. package/lib/typescript/src/components/CircularProgressBar/CircularProgressBar.d.ts +7 -1
  157. package/lib/typescript/src/components/CircularProgressBarDoted/CircularProgressBarDoted.d.ts +7 -1
  158. package/lib/typescript/src/components/CircularRating/CircularRating.d.ts +7 -1
  159. package/lib/typescript/src/components/ClusterBubble/ClusterBubble.d.ts +7 -1
  160. package/lib/typescript/src/components/CompareTable/CompareTable.d.ts +94 -0
  161. package/lib/typescript/src/components/ComparisonBar/ComparisonBar.d.ts +118 -0
  162. package/lib/typescript/src/components/CoverageBarComparison/CoverageBarComparison.d.ts +7 -1
  163. package/lib/typescript/src/components/DonutChart/DonutChart.d.ts +7 -1
  164. package/lib/typescript/src/components/Dropdown/Dropdown.d.ts +7 -1
  165. package/lib/typescript/src/components/DropdownInput/DropdownInput.d.ts +26 -1
  166. package/lib/typescript/src/components/ExpandableCheckbox/ExpandableCheckbox.d.ts +7 -1
  167. package/lib/typescript/src/components/FormField/FormField.d.ts +2 -2
  168. package/lib/typescript/src/components/HoldingsCard/HoldingsCard.d.ts +7 -1
  169. package/lib/typescript/src/components/InputSearch/InputSearch.d.ts +23 -2
  170. package/lib/typescript/src/components/InstitutionBadge/InstitutionBadge.d.ts +7 -1
  171. package/lib/typescript/src/components/ListGroup/ListGroup.d.ts +7 -1
  172. package/lib/typescript/src/components/ListItem/ListItem.d.ts +7 -1
  173. package/lib/typescript/src/components/MetricLegendItem/MetricLegendItem.d.ts +7 -1
  174. package/lib/typescript/src/components/MonthlyStatusGrid/MonthlyStatusGrid.d.ts +14 -2
  175. package/lib/typescript/src/components/NoteInput/NoteInput.d.ts +19 -2
  176. package/lib/typescript/src/components/PdpCcCard/PdpCcCard.d.ts +84 -0
  177. package/lib/typescript/src/components/PoweredByLabel/PoweredByLabel.d.ts +7 -1
  178. package/lib/typescript/src/components/ProductMerchandisingCard/ProductMerchandisingCard.d.ts +87 -0
  179. package/lib/typescript/src/components/ProductOverview/ProductOverview.d.ts +7 -1
  180. package/lib/typescript/src/components/ProgressBadge/ProgressBadge.d.ts +7 -1
  181. package/lib/typescript/src/components/ProjectionMarker/ProjectionMarker.d.ts +88 -0
  182. package/lib/typescript/src/components/Radio/Radio.d.ts +3 -2
  183. package/lib/typescript/src/components/RadioButton/RadioButton.d.ts +2 -2
  184. package/lib/typescript/src/components/Section/Section.d.ts +7 -1
  185. package/lib/typescript/src/components/Slider/Slider.d.ts +105 -0
  186. package/lib/typescript/src/components/Stack/Stack.d.ts +81 -0
  187. package/lib/typescript/src/components/SummaryTile/SummaryTile.d.ts +7 -1
  188. package/lib/typescript/src/components/Table/Table.d.ts +139 -0
  189. package/lib/typescript/src/components/Text/Text.d.ts +7 -1
  190. package/lib/typescript/src/components/TextInput/TextInput.d.ts +9 -29
  191. package/lib/typescript/src/components/TextSegment/TextSegment.d.ts +106 -0
  192. package/lib/typescript/src/components/ThreadHero/ThreadHero.d.ts +7 -1
  193. package/lib/typescript/src/components/Title/Title.d.ts +7 -1
  194. package/lib/typescript/src/components/Toast/Toast.d.ts +7 -1
  195. package/lib/typescript/src/components/TransactionBubble/TransactionBubble.d.ts +7 -1
  196. package/lib/typescript/src/components/TransactionStatus/TransactionStatus.d.ts +7 -1
  197. package/lib/typescript/src/components/UpiHandle/UpiHandle.d.ts +7 -1
  198. package/lib/typescript/src/components/index.d.ts +14 -3
  199. package/lib/typescript/src/design-tokens/figma-modes.generated.d.ts +22 -2
  200. package/lib/typescript/src/icons/registry.d.ts +1 -1
  201. package/lib/typescript/src/utils/GlassFill/GlassFill.d.ts +84 -0
  202. package/lib/typescript/src/utils/GlassFill/GlassFill.web.d.ts +43 -0
  203. package/lib/typescript/src/utils/react-utils.d.ts +47 -0
  204. package/lib/typescript/src/utils/web-platform-utils.d.ts +36 -0
  205. package/package.json +2 -1
  206. package/src/components/Accordion/Accordion.tsx +9 -2
  207. package/src/components/AccordionCheckbox/AccordionCheckbox.tsx +10 -3
  208. package/src/components/AccountCard/AccountCard.tsx +10 -3
  209. package/src/components/AllocationComparisonChart/AllocationComparisonChart.tsx +14 -4
  210. package/src/components/AmountInput/AmountInput.tsx +7 -5
  211. package/src/components/AreaLineChart/AreaLineChart.tsx +15 -5
  212. package/src/components/Badge/Badge.tsx +78 -8
  213. package/src/components/BenefitCard/BenefitCard.tsx +309 -0
  214. package/src/components/BrandChip/BrandChip.tsx +9 -3
  215. package/src/components/Button/Button.tsx +9 -2
  216. package/src/components/CardAdvisory/CardAdvisory.tsx +9 -2
  217. package/src/components/CardBankAccount/CardBankAccount.tsx +9 -2
  218. package/src/components/CardCTA/CardCTA.tsx +214 -41
  219. package/src/components/CardInsight/CardInsight.tsx +7 -1
  220. package/src/components/CcCard/CcCard.tsx +598 -0
  221. package/src/components/Checkbox/Checkbox.tsx +5 -4
  222. package/src/components/CheckboxItem/CheckboxItem.tsx +5 -4
  223. package/src/components/CircularProgressBar/CircularProgressBar.tsx +14 -4
  224. package/src/components/CircularProgressBarDoted/CircularProgressBarDoted.tsx +10 -3
  225. package/src/components/CircularRating/CircularRating.tsx +9 -2
  226. package/src/components/ClusterBubble/ClusterBubble.tsx +9 -2
  227. package/src/components/CompareTable/CompareTable.tsx +525 -0
  228. package/src/components/ComparisonBar/ComparisonBar.tsx +356 -0
  229. package/src/components/CoverageBarComparison/CoverageBarComparison.tsx +9 -2
  230. package/src/components/DonutChart/DonutChart.tsx +10 -3
  231. package/src/components/Dropdown/Dropdown.tsx +9 -2
  232. package/src/components/DropdownInput/DropdownInput.tsx +64 -5
  233. package/src/components/ExpandableCheckbox/ExpandableCheckbox.tsx +8 -1
  234. package/src/components/FormField/FormField.tsx +52 -6
  235. package/src/components/Gauge/Gauge.tsx +1 -1
  236. package/src/components/HoldingsCard/HoldingsCard.tsx +9 -2
  237. package/src/components/InputSearch/InputSearch.tsx +8 -5
  238. package/src/components/InstitutionBadge/InstitutionBadge.tsx +9 -2
  239. package/src/components/ListGroup/ListGroup.tsx +9 -2
  240. package/src/components/ListItem/ListItem.tsx +10 -3
  241. package/src/components/MediaCard/MediaCard.tsx +2 -2
  242. package/src/components/MetricLegendItem/MetricLegendItem.tsx +9 -2
  243. package/src/components/MonthlyStatusGrid/MonthlyStatusGrid.tsx +17 -2
  244. package/src/components/NoteInput/NoteInput.tsx +8 -6
  245. package/src/components/PdpCcCard/PdpCcCard.tsx +356 -0
  246. package/src/components/PoweredByLabel/PoweredByLabel.tsx +9 -2
  247. package/src/components/ProductMerchandisingCard/ProductMerchandisingCard.tsx +490 -0
  248. package/src/components/ProductOverview/ProductOverview.tsx +10 -3
  249. package/src/components/ProgressBadge/ProgressBadge.tsx +9 -3
  250. package/src/components/ProjectionMarker/ProjectionMarker.tsx +284 -0
  251. package/src/components/Radio/Radio.tsx +5 -4
  252. package/src/components/Section/Section.tsx +10 -3
  253. package/src/components/Slider/Slider.tsx +635 -0
  254. package/src/components/Stack/Stack.tsx +131 -0
  255. package/src/components/SuggestiveSearch/SuggestiveSearch.tsx +10 -1
  256. package/src/components/SummaryTile/SummaryTile.tsx +9 -2
  257. package/src/components/Table/Table.tsx +449 -0
  258. package/src/components/Text/Text.tsx +9 -2
  259. package/src/components/TextInput/TextInput.tsx +22 -12
  260. package/src/components/TextSegment/TextSegment.tsx +173 -0
  261. package/src/components/ThreadHero/ThreadHero.tsx +10 -3
  262. package/src/components/Title/Title.tsx +9 -2
  263. package/src/components/Toast/Toast.tsx +9 -2
  264. package/src/components/TransactionBubble/TransactionBubble.tsx +9 -2
  265. package/src/components/TransactionStatus/TransactionStatus.tsx +9 -2
  266. package/src/components/UpiHandle/UpiHandle.tsx +9 -3
  267. package/src/components/index.ts +33 -3
  268. package/src/design-tokens/Coin Variables-variables-full.json +1 -1
  269. package/src/design-tokens/figma-modes.generated.ts +39 -9
  270. package/src/icons/registry.ts +1 -1
  271. package/src/utils/GlassFill/GlassFill.tsx +305 -0
  272. package/src/utils/GlassFill/GlassFill.web.tsx +148 -0
  273. package/src/utils/react-utils.ts +84 -0
  274. package/src/utils/web-platform-utils.ts +68 -0
  275. package/lib/commonjs/components/MediaCard/GlassFill.js +0 -62
  276. package/lib/commonjs/components/MediaCard/GlassFill.web.js +0 -48
  277. package/lib/module/components/MediaCard/GlassFill.js +0 -57
  278. package/lib/module/components/MediaCard/GlassFill.web.js +0 -43
  279. package/lib/typescript/scripts/extract-component-tokens.d.ts +0 -9
  280. package/lib/typescript/scripts/generate-component-docs.d.ts +0 -9
  281. package/lib/typescript/scripts/generate-icon-registry.d.ts +0 -3
  282. package/lib/typescript/scripts/generate-mode-types.d.ts +0 -2
  283. package/lib/typescript/scripts/retype-modes.d.cts +0 -2
  284. package/lib/typescript/src/components/MediaCard/GlassFill.d.ts +0 -47
  285. package/lib/typescript/src/components/MediaCard/GlassFill.web.d.ts +0 -20
  286. package/src/components/MediaCard/GlassFill.tsx +0 -89
  287. package/src/components/MediaCard/GlassFill.web.tsx +0 -53
@@ -0,0 +1,490 @@
1
+ import React, { useId, useMemo } from 'react'
2
+ import {
3
+ View,
4
+ Text,
5
+ Pressable,
6
+ StyleSheet,
7
+ Platform,
8
+ Image as RNImage,
9
+ type ViewStyle,
10
+ type TextStyle,
11
+ type StyleProp,
12
+ type ImageSourcePropType,
13
+ } from 'react-native'
14
+ import MaskedView from '@react-native-masked-view/masked-view'
15
+ import Svg, { Defs, LinearGradient, Stop, Rect } from 'react-native-svg'
16
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
17
+ import { EMPTY_MODES, resolveTruncation } from '../../utils/react-utils'
18
+ import Avatar from '../Avatar/Avatar'
19
+ import Badge from '../Badge/Badge'
20
+ import Button from '../Button/Button'
21
+ import Image from '../Image/Image'
22
+ import GlassFill from '../../utils/GlassFill/GlassFill'
23
+ import type { Modes } from '../../design-tokens'
24
+
25
+ function normalizeImageSource(
26
+ src: ImageSourcePropType | string | undefined
27
+ ): ImageSourcePropType | undefined {
28
+ if (src == null) return undefined
29
+ return typeof src === 'string' ? { uri: src } : src
30
+ }
31
+
32
+ export interface ProductMerchandisingCardProps {
33
+ /**
34
+ * Background media for the card. Accepts a URL string or any RN
35
+ * `ImageSourcePropType` (same shape as `Avatar`, `MediaCard`, etc.). The
36
+ * image is rendered full-bleed behind the header and glass footer.
37
+ */
38
+ imageSource?: ImageSourcePropType | string
39
+ /** Footer title (bold, white). */
40
+ title?: string
41
+ /** Footer subtitle (muted). */
42
+ subtitle?: string
43
+ /**
44
+ * Header badge label (top-right). The badge is hidden when this is
45
+ * `undefined` and no `badge` override is provided.
46
+ */
47
+ badgeLabel?: string
48
+ /**
49
+ * Full override for the header badge. Takes precedence over `badgeLabel`.
50
+ */
51
+ badge?: React.ReactNode
52
+ /** Show the header avatar (top-left). Defaults to `true`. */
53
+ showAvatar?: boolean
54
+ /** Avatar image source. */
55
+ avatarSource?: ImageSourcePropType | string
56
+ /** Avatar monogram fallback when no image is supplied. */
57
+ avatarMonogram?: string
58
+ /** Full override for the header avatar. Takes precedence over avatar props. */
59
+ avatar?: React.ReactNode
60
+ /**
61
+ * Footer "special badge" label (small frosted pill above the title). The
62
+ * badge is hidden when this is `undefined` and no `specialBadge` override
63
+ * is provided.
64
+ */
65
+ specialBadgeLabel?: string
66
+ /** Optional leading node (icon/image) rendered inside the special badge. */
67
+ specialBadgeIcon?: React.ReactNode
68
+ /** Full override for the special badge. Takes precedence over the props above. */
69
+ specialBadge?: React.ReactNode
70
+ /** CTA button label. Defaults to `"CTA"`. */
71
+ ctaLabel?: string
72
+ /** CTA button press handler. */
73
+ onCtaPress?: () => void
74
+ /** Full override for the CTA. Takes precedence over `ctaLabel`/`onCtaPress`. */
75
+ cta?: React.ReactNode
76
+ /** Press handler for the whole card. When set, the card becomes pressable. */
77
+ onPress?: () => void
78
+ /** Card height in px. Defaults to `223` (Figma spec). */
79
+ height?: number
80
+ /** Modes object for design-token resolution. Cascaded to all children. */
81
+ modes?: Modes
82
+ /** Style overrides for the card container. */
83
+ style?: StyleProp<ViewStyle>
84
+ /** Accessibility label for the card. */
85
+ accessibilityLabel?: string
86
+ /**
87
+ * When `true`, disables text truncation: the trailing ellipsis (`…`) is never
88
+ * shown and any `numberOfLines` clamp is ignored, so the text wraps to as many
89
+ * lines as it needs even when horizontal space is tight.
90
+ */
91
+ disableTruncation?: boolean
92
+ }
93
+
94
+ /**
95
+ * ProductMerchandisingCard — a full-bleed image card (Figma node 5277:317)
96
+ * with a top header (avatar + badge) and a bottom **glass footer** that
97
+ * combines a real native background blur with a transparent→black gradient
98
+ * scrim for legible text over any image.
99
+ *
100
+ * Glass footer implementation (works on iOS, Android and Web):
101
+ * - **iOS / Android:** `<GlassFill>` wraps `@react-native-community/blur`'s
102
+ * `BlurView` — iOS gets a real `UIVisualEffectView` (live OS blur),
103
+ * Android gets the community `RealtimeBlurView` with a tinted scrim
104
+ * fallback. The native-only module is isolated in `GlassFill.tsx`.
105
+ * - **Web:** the platform-extension `GlassFill.web.tsx` renders a translucent
106
+ * `View` with `backdrop-filter: blur()` — Metro picks the right file so the
107
+ * web bundle never imports the native blur module.
108
+ * - The gradient scrim is drawn with `react-native-svg` (one renderer for all
109
+ * platforms) so the fade is identical everywhere.
110
+ *
111
+ * The blur strength is driven by the Figma `blur/minimal` token, mapped to the
112
+ * `GlassFill` 0–100 intensity scale the same way `MediaCard` does.
113
+ */
114
+ function ProductMerchandisingCard({
115
+ imageSource,
116
+ title = 'Title',
117
+ subtitle = 'Subtitle',
118
+ badgeLabel,
119
+ badge,
120
+ showAvatar = true,
121
+ avatarSource,
122
+ avatarMonogram,
123
+ avatar,
124
+ specialBadgeLabel,
125
+ specialBadgeIcon,
126
+ specialBadge,
127
+ ctaLabel = 'CTA',
128
+ onCtaPress,
129
+ cta,
130
+ onPress,
131
+ height = 223,
132
+ modes = EMPTY_MODES,
133
+ style,
134
+ accessibilityLabel,
135
+ disableTruncation,
136
+ }: ProductMerchandisingCardProps) {
137
+ // Unique gradient ids so multiple cards on one (web) document never collide.
138
+ const rawId = useId()
139
+ const safeId = rawId.replace(/[^a-zA-Z0-9_-]/g, '')
140
+ const scrimId = `pmc-footer-scrim-${safeId}`
141
+ const blurMaskId = `pmc-footer-blurmask-${safeId}`
142
+
143
+ const normalizedImageSource = useMemo(() => normalizeImageSource(imageSource), [imageSource])
144
+
145
+ const tokens = useMemo(() => resolveTokens(modes), [modes])
146
+
147
+ const containerStyle: ViewStyle = {
148
+ height,
149
+ borderRadius: tokens.radius,
150
+ overflow: 'hidden',
151
+ position: 'relative',
152
+ flexDirection: 'column',
153
+ justifyContent: 'space-between',
154
+ }
155
+
156
+ // Header avatar defaults to the design's 36px (Avatar Size = M). A
157
+ // consumer-supplied `modes['Avatar Size']` still wins via spread order.
158
+ const avatarModes = useMemo<Modes>(() => ({ 'Avatar Size': 'M', ...modes }), [modes])
159
+
160
+ // The Figma node renders the header badge with the brand "Secondary"
161
+ // appearance at "Medium" emphasis (lilac fill + dark label). These are set
162
+ // as defaults so the card matches the design out of the box; a
163
+ // consumer-supplied `modes` value still wins via spread order.
164
+ const badgeModes = useMemo<Modes>(
165
+ () => ({ AppearanceBrand: 'Secondary', Emphasis: 'Medium', ...modes }),
166
+ [modes]
167
+ )
168
+
169
+ const headerBadge =
170
+ badge ?? (badgeLabel != null ? <Badge label={badgeLabel} modes={badgeModes} /> : null)
171
+
172
+ const headerAvatar = showAvatar
173
+ ? avatar ?? (
174
+ <Avatar
175
+ style={avatarSource ? 'Image' : avatarMonogram ? 'Monogram' : 'Image'}
176
+ imageSource={avatarSource}
177
+ monogram={avatarMonogram}
178
+ modes={avatarModes}
179
+ />
180
+ )
181
+ : null
182
+
183
+ // The footer "special badge" is now the shared <Badge type="glass">. The
184
+ // hardcoded literals that defined its look (warm frosted overlay, gentle
185
+ // 5px blur, 6/2 padding, 4px radius, weight-500 white label) are preserved
186
+ // 1:1 via the glass overrides + `style`/`labelStyle`, and the optional
187
+ // `specialBadgeIcon` maps to Badge's `leading` slot — so every existing
188
+ // instantiation renders byte-for-byte the same as before.
189
+ const footerSpecialBadge =
190
+ specialBadge ??
191
+ (specialBadgeLabel != null ? (
192
+ <Badge
193
+ type="glass"
194
+ label={specialBadgeLabel}
195
+ leading={specialBadgeIcon}
196
+ glassOverlayColor={SPECIAL_BADGE_BG}
197
+ glassIntensity={SPECIAL_BADGE_INTENSITY}
198
+ modes={modes}
199
+ style={styles.specialBadge}
200
+ labelStyle={tokens.specialBadgeText}
201
+ {...(disableTruncation != null ? { disableTruncation } : null)}
202
+ />
203
+ ) : null)
204
+
205
+ // The Figma CTA uses the brand "Secondary" appearance (purple fill, white
206
+ // label) at the small size. Defaults match the design; consumer `modes`
207
+ // win via spread order.
208
+ const ctaModes = useMemo<Modes>(
209
+ () => ({ 'Button / Size': 'S', AppearanceBrand: 'Secondary', ...modes }),
210
+ [modes]
211
+ )
212
+
213
+ const footerCta =
214
+ cta ?? <Button label={ctaLabel} modes={ctaModes} onPress={onCtaPress} />
215
+
216
+ const content = (
217
+ <>
218
+ {imageSource != null ? (
219
+ <Image
220
+ imageSource={imageSource}
221
+ style={StyleSheet.absoluteFillObject as any}
222
+ width="100%"
223
+ height={height}
224
+ resizeMode="cover"
225
+ accessibilityElementsHidden
226
+ importantForAccessibility="no"
227
+ />
228
+ ) : null}
229
+
230
+ <View style={tokens.header} pointerEvents="box-none">
231
+ <View style={styles.avatarContainer}>{headerAvatar}</View>
232
+ {headerBadge}
233
+ </View>
234
+
235
+ <View style={tokens.footer} pointerEvents="box-none">
236
+ {/* Progressive blur — clear at the top of the footer, ramping to
237
+ a soft blur at the bottom. Rather than the unmaintained native
238
+ BlurView (which renders as a flat black tint on Android +
239
+ Fabric and can hide the image on iOS), we reveal a *blurred
240
+ copy of the card's own image* through a vertical gradient
241
+ mask. `Image.blurRadius` is a built-in RN prop with a real
242
+ Gaussian blur on BOTH iOS and Android and needs no native
243
+ module. The blurred copy is pinned to the card's bottom at the
244
+ full card height so it lines up pixel-for-pixel with the
245
+ full-bleed background, and the mask makes the blur swell in
246
+ smoothly toward the bottom (true progressive blur). */}
247
+ {normalizedImageSource != null ? (
248
+ <View style={StyleSheet.absoluteFill} pointerEvents="none">
249
+ <MaskedView
250
+ style={StyleSheet.absoluteFill}
251
+ maskElement={
252
+ <Svg width="100%" height="100%">
253
+ <Defs>
254
+ <LinearGradient id={blurMaskId} x1="0" y1="0" x2="0" y2="1">
255
+ <Stop offset="0" stopColor="#000000" stopOpacity={0} />
256
+ <Stop offset="0.35" stopColor="#000000" stopOpacity={0.5} />
257
+ <Stop offset="0.7" stopColor="#000000" stopOpacity={0.92} />
258
+ <Stop offset="1" stopColor="#000000" stopOpacity={1} />
259
+ </LinearGradient>
260
+ </Defs>
261
+ <Rect x="0" y="0" width="100%" height="100%" fill={`url(#${blurMaskId})`} />
262
+ </Svg>
263
+ }
264
+ >
265
+ <RNImage
266
+ source={normalizedImageSource}
267
+ blurRadius={tokens.imageBlurRadius}
268
+ resizeMode="cover"
269
+ style={{ position: 'absolute', left: 0, right: 0, bottom: 0, width: '100%', height }}
270
+ />
271
+ </MaskedView>
272
+ </View>
273
+ ) : (
274
+ <GlassFill tint="dark" intensity={tokens.blurIntensity} progressive />
275
+ )}
276
+ {/* Transparent -> black gradient scrim for text legibility,
277
+ identical on all platforms. Kept lighter than a solid fill so
278
+ the blurred image stays visible behind the footer text. */}
279
+ <View style={[StyleSheet.absoluteFill, styles.scrim]} pointerEvents="none">
280
+ <Svg width="100%" height="100%">
281
+ <Defs>
282
+ <LinearGradient id={scrimId} x1="0" y1="0" x2="0" y2="1">
283
+ <Stop offset="0.018" stopColor="#000000" stopOpacity={0} />
284
+ <Stop offset="0.974" stopColor="#000000" stopOpacity={1} />
285
+ </LinearGradient>
286
+ </Defs>
287
+ <Rect x="0" y="0" width="100%" height="100%" fill={`url(#${scrimId})`} />
288
+ </Svg>
289
+ </View>
290
+
291
+ {footerSpecialBadge}
292
+
293
+ <View style={styles.footerRow}>
294
+ <View style={tokens.textWrap}>
295
+ <Text style={tokens.title} {...resolveTruncation(disableTruncation, 1)}>
296
+ {title}
297
+ </Text>
298
+ {subtitle != null ? (
299
+ <Text style={tokens.subtitle} {...resolveTruncation(disableTruncation, 1)}>
300
+ {subtitle}
301
+ </Text>
302
+ ) : null}
303
+ </View>
304
+ {footerCta}
305
+ </View>
306
+ </View>
307
+ </>
308
+ )
309
+
310
+ if (onPress) {
311
+ return (
312
+ <Pressable
313
+ style={({ pressed }) => [containerStyle, pressed ? styles.pressed : null, style]}
314
+ accessibilityRole="button"
315
+ accessibilityLabel={accessibilityLabel ?? title}
316
+ onPress={onPress}
317
+ >
318
+ {content}
319
+ </Pressable>
320
+ )
321
+ }
322
+
323
+ return (
324
+ <View
325
+ style={[containerStyle, style]}
326
+ accessibilityLabel={accessibilityLabel}
327
+ >
328
+ {content}
329
+ </View>
330
+ )
331
+ }
332
+
333
+ // ---------------------------------------------------------------------------
334
+ // Tokens / static styles
335
+ // ---------------------------------------------------------------------------
336
+
337
+ // Figma footer backdrop-blur token (`blur/minimal`). The footer uses a
338
+ // *progressive* blur, so this maps the token to the intensity at the BOTTOM of
339
+ // the ramp (the strongest point); the upper part fades to fully clear. Kept
340
+ // intentionally small to match the design's subtle "minimal" blur.
341
+ const BLUR_INTENSITY_FACTOR = 1.0
342
+
343
+ // Special badge ("frosted" pill) — values are literals in the Figma node
344
+ // (no dedicated tokens): bg rgba(255,245,229,0.15), 5px backdrop blur.
345
+ const SPECIAL_BADGE_BG = 'rgba(255,245,229,0.15)'
346
+ const SPECIAL_BADGE_INTENSITY = 17 // ~5px CSS blur / ~2 native blurAmount
347
+
348
+ interface ResolvedTokens {
349
+ radius: number
350
+ blurIntensity: number
351
+ imageBlurRadius: number
352
+ header: ViewStyle
353
+ footer: ViewStyle
354
+ textWrap: ViewStyle
355
+ title: TextStyle
356
+ subtitle: TextStyle
357
+ specialBadgeText: TextStyle
358
+ }
359
+
360
+ function asNum(raw: unknown, fallback: number): number {
361
+ const n = typeof raw === 'number' ? raw : parseFloat(raw as string)
362
+ return Number.isFinite(n) ? n : fallback
363
+ }
364
+
365
+ function asStr(raw: unknown, fallback: string): string {
366
+ return raw != null ? String(raw) : fallback
367
+ }
368
+
369
+ function resolveTokens(modes: Modes): ResolvedTokens {
370
+ // NOTE: token names are passed as string literals DIRECTLY to
371
+ // getVariableByName so the `extract-component-tokens` script can statically
372
+ // collect them for the generated docs. Do not refactor these into a helper
373
+ // that receives the name as a variable.
374
+ const radius = asNum(getVariableByName('productMerchandisingcard/radius', modes), 12)
375
+ const headerPadH = asNum(getVariableByName('productMerchandisingcard/header/padding/horizontal', modes), 12)
376
+ const headerPadV = asNum(getVariableByName('productMerchandisingcard/header/padding/vertical', modes), 12)
377
+ const footerGap = asNum(getVariableByName('productMerchandisingcard/footer/gap', modes), 8)
378
+ const footerPadH = asNum(getVariableByName('productMerchandisingcard/footer/padding/horizontal', modes), 16)
379
+ const footerPadV = asNum(getVariableByName('productMerchandisingcard/footer/padding/vertical', modes), 16)
380
+ const textGap = asNum(getVariableByName('productMerchandisingcard/footer/text/gap', modes), 2)
381
+ const blurRadius = asNum(getVariableByName('blur/minimal', modes), 29)
382
+
383
+ const titleColor = asStr(getVariableByName('productMerchandisingcard/footer/title/font/color', modes), '#ffffff')
384
+ const titleSize = asNum(getVariableByName('productMerchandisingcard/footer/title/fontsize', modes), 14)
385
+ const titleFamily = asStr(getVariableByName('productMerchandisingcard/footer/title/fontfamily', modes), 'JioType Var')
386
+ const titleWeight = asStr(getVariableByName('productMerchandisingcard/footer/title/fontweight', modes), '700')
387
+
388
+ const subtitleColor = asStr(getVariableByName('productMerchandisingcard/footer/subtitle/font/color', modes), '#c5bcb5')
389
+ const subtitleSize = asNum(getVariableByName('productMerchandisingcard/footer/subtitle/fontsize', modes), 12)
390
+ const subtitleFamily = asStr(getVariableByName('productMerchandisingcard/footer/subtitle/fontfamily', modes), 'JioType Var')
391
+ const subtitleWeight = asStr(getVariableByName('productMerchandisingcard/footer/subtitle/fontweight', modes), '400')
392
+
393
+ const sbSize = asNum(getVariableByName('productMerchandisingcard/specialbadge/text/fontsize', modes), 12)
394
+ const sbFamily = asStr(getVariableByName('productMerchandisingcard/specialbadge/text/fontfamily', modes), 'JioType Var')
395
+ const sbWeight = asStr(getVariableByName('productMerchandisingcard/specialbadge/text/fontweight', modes), '500')
396
+
397
+ // `Image.blurRadius` is interpreted differently per platform — iOS applies a
398
+ // strong Gaussian while Android's IterativeBoxBlur is gentler at the same
399
+ // numeric radius — so we tune each platform to land on the same perceived
400
+ // "minimal" frosted strength as the Figma design.
401
+ const imageBlurRadius = Platform.select({
402
+ ios: Math.max(6, Math.round(blurRadius * 0.5)),
403
+ android: Math.max(12, Math.round(blurRadius * 0.95)),
404
+ default: Math.max(8, Math.round(blurRadius * 0.6)),
405
+ }) as number
406
+
407
+ return {
408
+ radius,
409
+ blurIntensity: Math.max(0, Math.min(100, Math.round(blurRadius * BLUR_INTENSITY_FACTOR))),
410
+ imageBlurRadius,
411
+ header: {
412
+ flexDirection: 'row',
413
+ alignItems: 'flex-start',
414
+ justifyContent: 'space-between',
415
+ paddingHorizontal: headerPadH,
416
+ paddingVertical: headerPadV,
417
+ zIndex: 1,
418
+ },
419
+ footer: {
420
+ paddingHorizontal: footerPadH,
421
+ paddingVertical: footerPadV,
422
+ gap: footerGap,
423
+ overflow: 'hidden',
424
+ zIndex: 2,
425
+ },
426
+ textWrap: {
427
+ flex: 1,
428
+ gap: textGap,
429
+ justifyContent: 'center',
430
+ },
431
+ title: {
432
+ color: titleColor,
433
+ fontSize: titleSize,
434
+ fontFamily: titleFamily,
435
+ fontWeight: titleWeight as TextStyle['fontWeight'],
436
+ lineHeight: Math.round(titleSize * 1.2),
437
+ includeFontPadding: false as any,
438
+ },
439
+ subtitle: {
440
+ color: subtitleColor,
441
+ fontSize: subtitleSize,
442
+ fontFamily: subtitleFamily,
443
+ fontWeight: subtitleWeight as TextStyle['fontWeight'],
444
+ lineHeight: Math.round(subtitleSize * 1.2),
445
+ includeFontPadding: false as any,
446
+ },
447
+ specialBadgeText: {
448
+ color: '#ffffff',
449
+ fontSize: sbSize,
450
+ fontFamily: sbFamily,
451
+ fontWeight: sbWeight as TextStyle['fontWeight'],
452
+ lineHeight: Math.round(sbSize * 1.2),
453
+ includeFontPadding: false as any,
454
+ },
455
+ }
456
+ }
457
+
458
+ const styles = StyleSheet.create({
459
+ avatarContainer: {
460
+ flexShrink: 1,
461
+ justifyContent: 'center',
462
+ },
463
+ footerRow: {
464
+ flexDirection: 'row',
465
+ alignItems: 'center',
466
+ justifyContent: 'space-between',
467
+ gap: 8,
468
+ },
469
+ scrim: {
470
+ // The footer node sits at 90% opacity in Figma; applying it to the
471
+ // scrim (not the content) keeps the title/CTA crisp while preserving
472
+ // the intended fade strength.
473
+ opacity: 0.9,
474
+ },
475
+ // Overrides layered on top of <Badge type="glass">. Badge already supplies
476
+ // the row layout + 4px gap (when a leading icon is present), `overflow:
477
+ // 'hidden'`, `alignSelf: 'flex-start'` and `alignItems: 'center'`; these
478
+ // pin the special badge's literal Figma box (6/2 padding, 4px radius)
479
+ // regardless of the badge size tokens resolved by the active modes.
480
+ specialBadge: {
481
+ paddingHorizontal: 6,
482
+ paddingVertical: 2,
483
+ borderRadius: 4,
484
+ },
485
+ pressed: {
486
+ opacity: 0.92,
487
+ },
488
+ })
489
+
490
+ export default ProductMerchandisingCard
@@ -8,7 +8,7 @@ import {
8
8
  type ImageSourcePropType,
9
9
  } from 'react-native'
10
10
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
11
- import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils'
11
+ import { EMPTY_MODES, cloneChildrenWithModes, resolveTruncation } from '../../utils/react-utils'
12
12
  import Image from '../Image/Image'
13
13
  import ProductLabel from '../ProductLabel/ProductLabel'
14
14
  import type { Modes } from '../../design-tokens'
@@ -47,6 +47,12 @@ export type ProductOverviewProps = {
47
47
  * for badges, callouts, etc. Receives the same `modes` as the parent.
48
48
  */
49
49
  children?: React.ReactNode
50
+ /**
51
+ * When `true`, disables text truncation: the trailing ellipsis (`…`) is never
52
+ * shown and any `numberOfLines` clamp is ignored, so the text wraps to as many
53
+ * lines as it needs even when horizontal space is tight.
54
+ */
55
+ disableTruncation?: boolean
50
56
  }
51
57
 
52
58
  const DEFAULT_STATS: ProductOverviewStat[] = [
@@ -65,6 +71,7 @@ const ProductOverview = ({
65
71
  modes = EMPTY_MODES,
66
72
  style,
67
73
  children,
74
+ disableTruncation,
68
75
  }: ProductOverviewProps) => {
69
76
  const padding = (getVariableByName('productOverview/padding', modes) as number | null) ?? 24
70
77
  const gap = (getVariableByName('productOverview/gap', modes) as number | null) ?? 12
@@ -220,10 +227,10 @@ const ProductOverview = ({
220
227
  overflow: 'hidden',
221
228
  }}
222
229
  >
223
- <Text style={statValueStyle} numberOfLines={1}>
230
+ <Text style={statValueStyle} {...resolveTruncation(disableTruncation, 1)}>
224
231
  {stat.value}
225
232
  </Text>
226
- <Text style={statLabelStyle} numberOfLines={1}>
233
+ <Text style={statLabelStyle} {...resolveTruncation(disableTruncation, 1)}>
227
234
  {stat.label}
228
235
  </Text>
229
236
  </View>
@@ -8,7 +8,7 @@ import {
8
8
  } from 'react-native'
9
9
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
10
10
  import Icon from '../../icons/Icon'
11
- import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils'
11
+ import { EMPTY_MODES, cloneChildrenWithModes, resolveTruncation } from '../../utils/react-utils'
12
12
  import type { Modes } from '../../design-tokens'
13
13
 
14
14
  export type ProgressBadgeProps = {
@@ -26,6 +26,12 @@ export type ProgressBadgeProps = {
26
26
  textStyle?: StyleProp<TextStyle>
27
27
  /** Accessibility label for screen readers */
28
28
  accessibilityLabel?: string
29
+ /**
30
+ * When `true`, disables text truncation: the trailing ellipsis (`…`) is never
31
+ * shown and any `numberOfLines` clamp is ignored, so the text wraps to as many
32
+ * lines as it needs even when horizontal space is tight.
33
+ */
34
+ disableTruncation?: boolean
29
35
  } & React.ComponentProps<typeof View>
30
36
 
31
37
  /**
@@ -51,6 +57,7 @@ function ProgressBadge({
51
57
  style,
52
58
  textStyle: textStyleOverride,
53
59
  accessibilityLabel,
60
+ disableTruncation,
54
61
  ...rest
55
62
  }: ProgressBadgeProps) {
56
63
  // Resolve layout tokens
@@ -158,8 +165,7 @@ function ProgressBadge({
158
165
  ) : null}
159
166
  <Text
160
167
  style={[textStyle, textStyleOverride]}
161
- numberOfLines={1}
162
- ellipsizeMode="tail"
168
+ {...resolveTruncation(disableTruncation, 1, 'tail')}
163
169
  accessibilityElementsHidden={true}
164
170
  importantForAccessibility="no"
165
171
  >