jfs-components 0.0.71 → 0.0.73

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 (141) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/lib/commonjs/components/AccordionCheckbox/AccordionCheckbox.js +239 -0
  3. package/lib/commonjs/components/BrandChip/BrandChip.js +149 -0
  4. package/lib/commonjs/components/CardAdvisory/CardAdvisory.js +2 -2
  5. package/lib/commonjs/components/CardBankAccount/CardBankAccount.js +213 -0
  6. package/lib/commonjs/components/CardFinancialCondition/CardFinancialCondition.js +213 -0
  7. package/lib/commonjs/components/CardInsight/CardInsight.js +166 -0
  8. package/lib/commonjs/components/Carousel/Carousel.js +9 -7
  9. package/lib/commonjs/components/CheckboxGroup/CheckboxGroup.js +67 -0
  10. package/lib/commonjs/components/CheckboxItem/CheckboxItem.js +125 -0
  11. package/lib/commonjs/components/CircularProgressBar/CircularProgressBar.js +56 -9
  12. package/lib/commonjs/components/CoverageBarComparison/CoverageBarComparison.js +272 -0
  13. package/lib/commonjs/components/CoverageRing/CoverageRing.js +141 -0
  14. package/lib/commonjs/components/DonutChart/DonutChart.js +309 -0
  15. package/lib/commonjs/components/DonutChartSummary/DonutChartSummary.js +155 -0
  16. package/lib/commonjs/components/HoldingsCard/HoldingsCard.js +2 -2
  17. package/lib/commonjs/components/InstitutionBadge/InstitutionBadge.js +132 -0
  18. package/lib/commonjs/components/LinearMeter/LinearMeter.js +9 -28
  19. package/lib/commonjs/components/LinearProgress/LinearProgress.js +68 -0
  20. package/lib/commonjs/components/MetricLegendItem/MetricLegendItem.js +95 -0
  21. package/lib/commonjs/components/MonthlyStatusGrid/MonthlyStatusGrid.js +286 -0
  22. package/lib/commonjs/components/OTP/OTP.js +381 -37
  23. package/lib/commonjs/components/ProductOverview/ProductOverview.js +147 -0
  24. package/lib/commonjs/components/Radio/Radio.js +194 -0
  25. package/lib/commonjs/components/RadioButton/RadioButton.js +21 -188
  26. package/lib/commonjs/components/RangeTrack/RangeTrack.js +269 -0
  27. package/lib/commonjs/components/SavingsGoalSummary/SavingsGoalSummary.js +181 -0
  28. package/lib/commonjs/components/SegmentedTrack/SegmentedTrack.js +171 -0
  29. package/lib/commonjs/components/StatGroup/StatGroup.js +128 -0
  30. package/lib/commonjs/components/StatItem/StatItem.js +65 -35
  31. package/lib/commonjs/components/StrengthIndicator/StrengthIndicator.js +157 -0
  32. package/lib/commonjs/components/SummaryTile/SummaryTile.js +150 -0
  33. package/lib/commonjs/components/index.js +192 -1
  34. package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
  35. package/lib/commonjs/icons/registry.js +1 -1
  36. package/lib/commonjs/utils/index.js +7 -0
  37. package/lib/commonjs/utils/number-utils.js +57 -0
  38. package/lib/module/components/AccordionCheckbox/AccordionCheckbox.js +233 -0
  39. package/lib/module/components/BrandChip/BrandChip.js +143 -0
  40. package/lib/module/components/CardAdvisory/CardAdvisory.js +2 -2
  41. package/lib/module/components/CardBankAccount/CardBankAccount.js +208 -0
  42. package/lib/module/components/CardFinancialCondition/CardFinancialCondition.js +207 -0
  43. package/lib/module/components/CardInsight/CardInsight.js +161 -0
  44. package/lib/module/components/Carousel/Carousel.js +9 -7
  45. package/lib/module/components/CheckboxGroup/CheckboxGroup.js +62 -0
  46. package/lib/module/components/CheckboxItem/CheckboxItem.js +119 -0
  47. package/lib/module/components/CircularProgressBar/CircularProgressBar.js +56 -9
  48. package/lib/module/components/CoverageBarComparison/CoverageBarComparison.js +266 -0
  49. package/lib/module/components/CoverageRing/CoverageRing.js +136 -0
  50. package/lib/module/components/DonutChart/DonutChart.js +303 -0
  51. package/lib/module/components/DonutChartSummary/DonutChartSummary.js +150 -0
  52. package/lib/module/components/HoldingsCard/HoldingsCard.js +2 -2
  53. package/lib/module/components/InstitutionBadge/InstitutionBadge.js +127 -0
  54. package/lib/module/components/LinearMeter/LinearMeter.js +9 -28
  55. package/lib/module/components/LinearProgress/LinearProgress.js +63 -0
  56. package/lib/module/components/MetricLegendItem/MetricLegendItem.js +90 -0
  57. package/lib/module/components/MonthlyStatusGrid/MonthlyStatusGrid.js +281 -0
  58. package/lib/module/components/OTP/OTP.js +381 -38
  59. package/lib/module/components/ProductOverview/ProductOverview.js +142 -0
  60. package/lib/module/components/Radio/Radio.js +188 -0
  61. package/lib/module/components/RadioButton/RadioButton.js +20 -185
  62. package/lib/module/components/RangeTrack/RangeTrack.js +263 -0
  63. package/lib/module/components/SavingsGoalSummary/SavingsGoalSummary.js +175 -0
  64. package/lib/module/components/SegmentedTrack/SegmentedTrack.js +166 -0
  65. package/lib/module/components/StatGroup/StatGroup.js +123 -0
  66. package/lib/module/components/StatItem/StatItem.js +66 -36
  67. package/lib/module/components/StrengthIndicator/StrengthIndicator.js +152 -0
  68. package/lib/module/components/SummaryTile/SummaryTile.js +145 -0
  69. package/lib/module/components/index.js +28 -1
  70. package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
  71. package/lib/module/icons/registry.js +1 -1
  72. package/lib/module/utils/index.js +2 -1
  73. package/lib/module/utils/number-utils.js +53 -0
  74. package/lib/typescript/src/components/AccordionCheckbox/AccordionCheckbox.d.ts +71 -0
  75. package/lib/typescript/src/components/BrandChip/BrandChip.d.ts +43 -0
  76. package/lib/typescript/src/components/CardBankAccount/CardBankAccount.d.ts +79 -0
  77. package/lib/typescript/src/components/CardFinancialCondition/CardFinancialCondition.d.ts +50 -0
  78. package/lib/typescript/src/components/CardInsight/CardInsight.d.ts +48 -0
  79. package/lib/typescript/src/components/CheckboxGroup/CheckboxGroup.d.ts +41 -0
  80. package/lib/typescript/src/components/CheckboxItem/CheckboxItem.d.ts +56 -0
  81. package/lib/typescript/src/components/CircularProgressBar/CircularProgressBar.d.ts +11 -1
  82. package/lib/typescript/src/components/CoverageBarComparison/CoverageBarComparison.d.ts +105 -0
  83. package/lib/typescript/src/components/CoverageRing/CoverageRing.d.ts +90 -0
  84. package/lib/typescript/src/components/DonutChart/DonutChart.d.ts +117 -0
  85. package/lib/typescript/src/components/DonutChartSummary/DonutChartSummary.d.ts +103 -0
  86. package/lib/typescript/src/components/InstitutionBadge/InstitutionBadge.d.ts +30 -0
  87. package/lib/typescript/src/components/LinearProgress/LinearProgress.d.ts +17 -0
  88. package/lib/typescript/src/components/MetricLegendItem/MetricLegendItem.d.ts +37 -0
  89. package/lib/typescript/src/components/MonthlyStatusGrid/MonthlyStatusGrid.d.ts +119 -0
  90. package/lib/typescript/src/components/OTP/OTP.d.ts +88 -2
  91. package/lib/typescript/src/components/ProductOverview/ProductOverview.d.ts +39 -0
  92. package/lib/typescript/src/components/Radio/Radio.d.ts +30 -0
  93. package/lib/typescript/src/components/RadioButton/RadioButton.d.ts +20 -28
  94. package/lib/typescript/src/components/RangeTrack/RangeTrack.d.ts +173 -0
  95. package/lib/typescript/src/components/SavingsGoalSummary/SavingsGoalSummary.d.ts +95 -0
  96. package/lib/typescript/src/components/SegmentedTrack/SegmentedTrack.d.ts +108 -0
  97. package/lib/typescript/src/components/StatGroup/StatGroup.d.ts +45 -0
  98. package/lib/typescript/src/components/StatItem/StatItem.d.ts +24 -7
  99. package/lib/typescript/src/components/StrengthIndicator/StrengthIndicator.d.ts +58 -0
  100. package/lib/typescript/src/components/SummaryTile/SummaryTile.d.ts +60 -0
  101. package/lib/typescript/src/components/index.d.ts +29 -2
  102. package/lib/typescript/src/icons/registry.d.ts +1 -1
  103. package/lib/typescript/src/utils/index.d.ts +1 -0
  104. package/lib/typescript/src/utils/number-utils.d.ts +29 -0
  105. package/package.json +1 -1
  106. package/src/components/AccordionCheckbox/AccordionCheckbox.tsx +323 -0
  107. package/src/components/BrandChip/BrandChip.tsx +235 -0
  108. package/src/components/CardAdvisory/CardAdvisory.tsx +2 -2
  109. package/src/components/CardBankAccount/CardBankAccount.tsx +295 -0
  110. package/src/components/CardFinancialCondition/CardFinancialCondition.tsx +366 -0
  111. package/src/components/CardInsight/CardInsight.tsx +239 -0
  112. package/src/components/Carousel/Carousel.tsx +14 -6
  113. package/src/components/CheckboxGroup/CheckboxGroup.tsx +86 -0
  114. package/src/components/CheckboxItem/CheckboxItem.tsx +174 -0
  115. package/src/components/CircularProgressBar/CircularProgressBar.tsx +74 -9
  116. package/src/components/CoverageBarComparison/CoverageBarComparison.tsx +378 -0
  117. package/src/components/CoverageRing/CoverageRing.tsx +225 -0
  118. package/src/components/DonutChart/DonutChart.tsx +503 -0
  119. package/src/components/DonutChartSummary/DonutChartSummary.tsx +256 -0
  120. package/src/components/HoldingsCard/HoldingsCard.tsx +2 -2
  121. package/src/components/InstitutionBadge/InstitutionBadge.tsx +216 -0
  122. package/src/components/LinearMeter/LinearMeter.tsx +9 -39
  123. package/src/components/LinearProgress/LinearProgress.tsx +92 -0
  124. package/src/components/MetricLegendItem/MetricLegendItem.tsx +167 -0
  125. package/src/components/MonthlyStatusGrid/MonthlyStatusGrid.tsx +438 -0
  126. package/src/components/OTP/OTP.tsx +476 -29
  127. package/src/components/ProductOverview/ProductOverview.tsx +236 -0
  128. package/src/components/Radio/Radio.tsx +227 -0
  129. package/src/components/RadioButton/RadioButton.tsx +23 -225
  130. package/src/components/RangeTrack/RangeTrack.tsx +394 -0
  131. package/src/components/SavingsGoalSummary/SavingsGoalSummary.tsx +269 -0
  132. package/src/components/SegmentedTrack/SegmentedTrack.tsx +268 -0
  133. package/src/components/StatGroup/StatGroup.tsx +169 -0
  134. package/src/components/StatItem/StatItem.tsx +117 -40
  135. package/src/components/StrengthIndicator/StrengthIndicator.tsx +205 -0
  136. package/src/components/SummaryTile/SummaryTile.tsx +251 -0
  137. package/src/components/index.ts +39 -2
  138. package/src/design-tokens/Coin Variables-variables-full.json +1 -1
  139. package/src/icons/registry.ts +1 -1
  140. package/src/utils/index.ts +1 -0
  141. package/src/utils/number-utils.ts +60 -0
@@ -0,0 +1,86 @@
1
+ import React from 'react'
2
+ import { View, type StyleProp, type ViewStyle } from 'react-native'
3
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
4
+ import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils'
5
+ import CheckboxItem from '../CheckboxItem/CheckboxItem'
6
+
7
+ export type CheckboxGroupProps = {
8
+ /**
9
+ * Slot — a list of `CheckboxItem` (or compatible) elements to render inside
10
+ * the group. The `modes` prop is automatically forwarded to each child.
11
+ *
12
+ * When omitted, three default placeholder `CheckboxItem`s are rendered to
13
+ * mirror the Figma reference for the empty/initial state.
14
+ */
15
+ children?: React.ReactNode
16
+ /** Design token modes for theming (e.g. `{ 'Color Mode': 'Light' }`). */
17
+ modes?: Record<string, any>
18
+ /** Override container styles. */
19
+ style?: StyleProp<ViewStyle>
20
+ /** Accessibility label for the surrounding group. */
21
+ accessibilityLabel?: string
22
+ }
23
+
24
+ /**
25
+ * CheckboxGroup composes a vertical stack of `CheckboxItem`s. Spacing and
26
+ * padding are driven by the `checkboxGroup/*` design tokens so groups stay
27
+ * visually consistent across screens.
28
+ *
29
+ * The `modes` prop is forwarded recursively to all children — including
30
+ * `CheckboxItem`s and any element rendered inside their `endSlot`.
31
+ *
32
+ * @component
33
+ * @param {CheckboxGroupProps} props
34
+ *
35
+ * @example
36
+ * ```tsx
37
+ * <CheckboxGroup modes={{ 'Color Mode': 'Light' }}>
38
+ * <CheckboxItem label="Fixed deposit • 0245" />
39
+ * <CheckboxItem label="Recurring deposit • 1182" />
40
+ * <CheckboxItem label="Mutual fund • Equity" />
41
+ * </CheckboxGroup>
42
+ * ```
43
+ */
44
+ function CheckboxGroup({
45
+ children,
46
+ modes = EMPTY_MODES,
47
+ style,
48
+ accessibilityLabel,
49
+ }: CheckboxGroupProps) {
50
+ const gap = (getVariableByName('checkboxGroup/gap', modes) as number | null) ?? 12
51
+ const paddingHorizontal =
52
+ (getVariableByName('checkboxGroup/padding/horizontal', modes) as number | null) ?? 0
53
+ const paddingVertical =
54
+ (getVariableByName('checkboxGroup/padding/vertical', modes) as number | null) ?? 0
55
+
56
+ const containerStyle: ViewStyle = {
57
+ width: '100%',
58
+ flexDirection: 'column',
59
+ alignItems: 'stretch',
60
+ gap,
61
+ paddingHorizontal,
62
+ paddingVertical,
63
+ }
64
+
65
+ const items = children ? (
66
+ cloneChildrenWithModes(children, modes)
67
+ ) : (
68
+ <>
69
+ <CheckboxItem modes={modes} />
70
+ <CheckboxItem modes={modes} />
71
+ <CheckboxItem modes={modes} />
72
+ </>
73
+ )
74
+
75
+ return (
76
+ <View
77
+ style={[containerStyle, style]}
78
+ accessibilityRole="list"
79
+ accessibilityLabel={accessibilityLabel}
80
+ >
81
+ {items}
82
+ </View>
83
+ )
84
+ }
85
+
86
+ export default CheckboxGroup
@@ -0,0 +1,174 @@
1
+ import React, { useCallback, useState } from 'react'
2
+ import {
3
+ View,
4
+ Text,
5
+ Pressable,
6
+ type StyleProp,
7
+ type ViewStyle,
8
+ type TextStyle,
9
+ } from 'react-native'
10
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
11
+ import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils'
12
+ import Checkbox from '../Checkbox/Checkbox'
13
+
14
+ export type CheckboxItemProps = {
15
+ /** Whether the checkbox is checked (controlled). */
16
+ checked?: boolean
17
+ /** Initial checked state (uncontrolled). */
18
+ defaultChecked?: boolean
19
+ /** Callback fired when the checked state changes. */
20
+ onValueChange?: (checked: boolean) => void
21
+ /** Whether the row is disabled — both the checkbox and row press handler are disabled. */
22
+ disabled?: boolean
23
+ /** The label text rendered next to the checkbox. */
24
+ label?: React.ReactNode
25
+ /**
26
+ * Optional content rendered on the right side (e.g. a `Button`). When provided,
27
+ * it receives the same `modes` as the parent. Wrapped in a fixed-width container
28
+ * matching the Figma `endSlot` design.
29
+ */
30
+ endSlot?: React.ReactNode
31
+ /** Width of the end slot container in pixels. Defaults to 80 to match the Figma reference. */
32
+ endSlotWidth?: number
33
+ /** Design token modes for theming (e.g. `{ 'Color Mode': 'Light' }`). */
34
+ modes?: Record<string, any>
35
+ /** Override container styles. */
36
+ style?: StyleProp<ViewStyle>
37
+ /** Override the label text styles. */
38
+ labelStyle?: StyleProp<TextStyle>
39
+ /** Accessibility label for screen readers. Defaults to the `label` prop when it is a string. */
40
+ accessibilityLabel?: string
41
+ }
42
+
43
+ /**
44
+ * CheckboxItem composes a `Checkbox`, a label and an optional `endSlot` into a
45
+ * single horizontal pressable row. Pressing anywhere on the row (outside of the
46
+ * `endSlot`) toggles the checkbox, mirroring the typical native form pattern.
47
+ *
48
+ * Mirrors the Figma "Checkbox Item" component and uses the `checkboxItem/*`
49
+ * design tokens for typography and spacing.
50
+ *
51
+ * @component
52
+ * @param {CheckboxItemProps} props
53
+ *
54
+ * @example
55
+ * ```tsx
56
+ * const [checked, setChecked] = useState(false)
57
+ *
58
+ * <CheckboxItem
59
+ * label="Fixed deposit • 0245"
60
+ * checked={checked}
61
+ * onValueChange={setChecked}
62
+ * modes={{ 'Color Mode': 'Light' }}
63
+ * />
64
+ * ```
65
+ */
66
+ function CheckboxItem({
67
+ checked: controlledChecked,
68
+ defaultChecked = false,
69
+ onValueChange,
70
+ disabled = false,
71
+ label = 'Fixed deposit • 0245',
72
+ endSlot,
73
+ endSlotWidth = 80,
74
+ modes = EMPTY_MODES,
75
+ style,
76
+ labelStyle,
77
+ accessibilityLabel,
78
+ }: CheckboxItemProps) {
79
+ const isControlled = controlledChecked !== undefined
80
+ const [internalChecked, setInternalChecked] = useState(defaultChecked)
81
+ const isChecked = isControlled ? controlledChecked : internalChecked
82
+
83
+ const handleToggle = useCallback(() => {
84
+ if (disabled) return
85
+ const next = !isChecked
86
+ if (!isControlled) {
87
+ setInternalChecked(next)
88
+ }
89
+ onValueChange?.(next)
90
+ }, [disabled, isChecked, isControlled, onValueChange])
91
+
92
+ const gap = (getVariableByName('checkboxItem/gap', modes) as number | null) ?? 8
93
+ const paddingHorizontal =
94
+ (getVariableByName('checkboxItem/padding/horizontal', modes) as number | null) ?? 0
95
+ const paddingVertical =
96
+ (getVariableByName('checkboxItem/padding/vertical', modes) as number | null) ?? 0
97
+
98
+ const labelColor =
99
+ (getVariableByName('checkboxItem/foreground', modes) as string | null) ?? '#1a1c1f'
100
+ const labelFontFamily =
101
+ (getVariableByName('checkboxItem/label/fontFamily', modes) as string | null) ?? 'JioType Var'
102
+ const labelFontSize =
103
+ (getVariableByName('checkboxItem/label/fontSize', modes) as number | null) ?? 14
104
+ const labelLineHeight =
105
+ (getVariableByName('checkboxItem/label/lineHeight', modes) as number | null) ?? 19
106
+ const labelFontWeightRaw =
107
+ getVariableByName('checkboxItem/label/fontWeight', modes) ?? 400
108
+ const labelFontWeight = String(labelFontWeightRaw) as TextStyle['fontWeight']
109
+
110
+ const containerStyle: ViewStyle = {
111
+ flexDirection: 'row',
112
+ alignItems: 'center',
113
+ gap,
114
+ paddingHorizontal,
115
+ paddingVertical,
116
+ width: '100%',
117
+ }
118
+
119
+ const resolvedLabelStyle: TextStyle = {
120
+ flex: 1,
121
+ minWidth: 0,
122
+ color: labelColor,
123
+ fontFamily: labelFontFamily,
124
+ fontSize: labelFontSize,
125
+ lineHeight: labelLineHeight,
126
+ fontWeight: labelFontWeight,
127
+ }
128
+
129
+ const a11yLabel =
130
+ accessibilityLabel ?? (typeof label === 'string' ? label : undefined)
131
+
132
+ return (
133
+ <Pressable
134
+ style={[containerStyle, style]}
135
+ onPress={handleToggle}
136
+ disabled={disabled}
137
+ accessibilityRole="checkbox"
138
+ accessibilityState={{ checked: isChecked, disabled }}
139
+ accessibilityLabel={a11yLabel}
140
+ >
141
+ <Checkbox
142
+ checked={isChecked}
143
+ disabled={disabled}
144
+ onValueChange={handleToggle}
145
+ modes={modes}
146
+ accessibilityLabel={a11yLabel}
147
+ />
148
+
149
+ {label != null && label !== false ? (
150
+ typeof label === 'string' || typeof label === 'number' ? (
151
+ <Text style={[resolvedLabelStyle, labelStyle]} selectable={false}>
152
+ {label}
153
+ </Text>
154
+ ) : (
155
+ <View style={{ flex: 1, minWidth: 0 }}>{label}</View>
156
+ )
157
+ ) : null}
158
+
159
+ {endSlot ? (
160
+ <View
161
+ style={{
162
+ width: endSlotWidth,
163
+ flexShrink: 0,
164
+ alignItems: 'stretch',
165
+ }}
166
+ >
167
+ {cloneChildrenWithModes(endSlot, modes)}
168
+ </View>
169
+ ) : null}
170
+ </Pressable>
171
+ )
172
+ }
173
+
174
+ export default CheckboxItem
@@ -17,6 +17,14 @@ export type CircularProgressBarProps = CircularProgressBarBaseProps & {
17
17
  state?: CircularProgressBarState | boolean
18
18
  /** Optional formatted value shown in the active state. */
19
19
  valueLabel?: string
20
+ /**
21
+ * Optional small label rendered above the value inside the ring. Useful for
22
+ * sizes that have enough room for both a caption and a value (e.g. the
23
+ * `circularProgressBar Size: M` mode from Figma). When omitted, only the
24
+ * value is shown — keeping the default S-size compatible with existing
25
+ * callers.
26
+ */
27
+ supportText?: string
20
28
  /** Design token modes forwarded to token lookups. */
21
29
  modes?: Record<string, any>
22
30
  /** Container style override. */
@@ -27,6 +35,8 @@ export type CircularProgressBarProps = CircularProgressBarBaseProps & {
27
35
  progressStyle?: StyleProp<ViewStyle>
28
36
  /** Value text style override. */
29
37
  valueStyle?: StyleProp<TextStyle>
38
+ /** Support text style override. */
39
+ supportTextStyle?: StyleProp<TextStyle>
30
40
  /** Accessibility label for the whole progress component. */
31
41
  accessibilityLabel?: string
32
42
  }
@@ -71,16 +81,29 @@ function CircularProgressBar({
71
81
  value = 70,
72
82
  state = 'Inactive',
73
83
  valueLabel,
84
+ supportText,
74
85
  modes: propModes = EMPTY_MODES,
75
86
  style,
76
87
  trackStyle,
77
88
  progressStyle,
78
89
  valueStyle,
90
+ supportTextStyle,
79
91
  accessibilityLabel,
80
92
  ...rest
81
93
  }: CircularProgressBarProps) {
82
94
  const { modes: globalModes } = useTokens()
83
95
  const modes = { ...globalModes, ...propModes }
96
+ // The Figma `circularProgressBar/track/color` variable aliases to the same
97
+ // chain as `progress/color`, so user-selected Brand modes collapse the
98
+ // track and progress to a single hue. The Figma source of truth always
99
+ // renders the track as a neutral gray, so we force Neutral/Medium when
100
+ // resolving the track color while keeping the user modes for everything
101
+ // else.
102
+ const trackModes = {
103
+ ...modes,
104
+ 'AppearanceBrand': 'Neutral',
105
+ 'Emphasis': 'Medium',
106
+ }
84
107
 
85
108
  const isActive = state === true || state === 'Active'
86
109
  const normalizedValue = clamp(value, 0, 100)
@@ -92,7 +115,7 @@ function CircularProgressBar({
92
115
 
93
116
  const trackColor = getStrokeColor(
94
117
  trackStyle,
95
- getVariableByName('circularProgressBar/track/color', modes) as string || '#ebebed'
118
+ getVariableByName('circularProgressBar/track/color', trackModes) as string || '#ebebed'
96
119
  )
97
120
  const progressColor = getStrokeColor(
98
121
  progressStyle,
@@ -102,10 +125,17 @@ function CircularProgressBar({
102
125
  const iconSize = toNumber(getVariableByName('circularProgressBar/icon/size', modes), 24)
103
126
 
104
127
  const foreground = getVariableByName('circularProgressBar/foreground', modes) as string || '#0d0d0f'
105
- const fontSize = toNumber(getVariableByName('circularProgressBar/fontSize', modes), 18)
128
+ const fontSize = toNumber(getVariableByName('circularProgressBar/value/fontSize', modes), 18)
106
129
  const fontFamily = getVariableByName('circularProgressBar/fontFamily', modes) as string || 'JioType Var'
107
- const lineHeight = toNumber(getVariableByName('circularProgressBar/lineHeight', modes), 21)
108
- const fontWeight = toFontWeight(getVariableByName('circularProgressBar/fontWeight', modes), '700')
130
+ const lineHeight = toNumber(getVariableByName('circularProgressBar/value/lineHeight', modes), 21)
131
+ const fontWeight = toFontWeight(getVariableByName('circularProgressBar/value/fontWeight', modes), '700')
132
+
133
+ const supportFontSize = toNumber(getVariableByName('circularProgressBar/supportText/fontSize', modes), 11)
134
+ const supportLineHeight = toNumber(getVariableByName('circularProgressBar/supportText/lineHeight', modes), 13)
135
+ const supportFontWeight = toFontWeight(
136
+ getVariableByName('circularProgressBar/supportText/fontWeight', modes),
137
+ '500'
138
+ )
109
139
 
110
140
  const computedContainerStyle: ViewStyle = {
111
141
  alignItems: 'center',
@@ -115,13 +145,35 @@ function CircularProgressBar({
115
145
  width: size,
116
146
  }
117
147
 
148
+ // The text stack (support text + value) is centered inside the ring using
149
+ // an absolutely-positioned column. Keeping the wrapper absolute (rather
150
+ // than the individual texts, as in earlier versions) lets multi-line stacks
151
+ // render correctly without sub-pixel misalignment.
152
+ const textStackStyle: ViewStyle = {
153
+ alignItems: 'center',
154
+ justifyContent: 'center',
155
+ left: 0,
156
+ position: 'absolute',
157
+ right: 0,
158
+ top: 0,
159
+ bottom: 0,
160
+ }
161
+
118
162
  const computedValueStyle: TextStyle = {
119
163
  color: foreground,
120
164
  fontFamily,
121
165
  fontSize,
122
166
  fontWeight,
123
167
  lineHeight,
124
- position: 'absolute',
168
+ textAlign: 'center',
169
+ }
170
+
171
+ const computedSupportTextStyle: TextStyle = {
172
+ color: foreground,
173
+ fontFamily,
174
+ fontSize: supportFontSize,
175
+ fontWeight: supportFontWeight,
176
+ lineHeight: supportLineHeight,
125
177
  textAlign: 'center',
126
178
  }
127
179
 
@@ -132,8 +184,14 @@ function CircularProgressBar({
132
184
  }
133
185
 
134
186
  const displayValue = valueLabel ?? String(Math.round(normalizedValue))
187
+ const hasSupportText = typeof supportText === 'string' && supportText.length > 0
135
188
  const defaultAccessibilityLabel =
136
- accessibilityLabel ?? (isActive ? `${displayValue} out of 100` : 'Inactive progress')
189
+ accessibilityLabel ??
190
+ (isActive
191
+ ? hasSupportText
192
+ ? `${supportText}, ${displayValue} out of 100`
193
+ : `${displayValue} out of 100`
194
+ : 'Inactive progress')
137
195
 
138
196
  return (
139
197
  <View
@@ -171,9 +229,16 @@ function CircularProgressBar({
171
229
  </Svg>
172
230
 
173
231
  {isActive ? (
174
- <Text style={[computedValueStyle, valueStyle]}>
175
- {displayValue}
176
- </Text>
232
+ <View style={textStackStyle} pointerEvents="none">
233
+ {hasSupportText ? (
234
+ <Text style={[computedSupportTextStyle, supportTextStyle]} numberOfLines={1}>
235
+ {supportText}
236
+ </Text>
237
+ ) : null}
238
+ <Text style={[computedValueStyle, valueStyle]} numberOfLines={1}>
239
+ {displayValue}
240
+ </Text>
241
+ </View>
177
242
  ) : (
178
243
  <IconMinus
179
244
  width={iconSize}