jfs-components 0.0.69 → 0.0.71

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 (56) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/lib/commonjs/components/CardAdvisory/CardAdvisory.js +203 -0
  3. package/lib/commonjs/components/CardCTA/CardCTA.js +198 -16
  4. package/lib/commonjs/components/CircularProgressBar/CircularProgressBar.js +147 -0
  5. package/lib/commonjs/components/CircularProgressBarDoted/CircularProgressBarDoted.js +258 -0
  6. package/lib/commonjs/components/CircularRating/CircularRating.js +161 -0
  7. package/lib/commonjs/components/Gauge/Gauge.js +223 -0
  8. package/lib/commonjs/components/ListGroup/ListGroup.js +3 -1
  9. package/lib/commonjs/components/MediaCard/GlassFill.js +62 -0
  10. package/lib/commonjs/components/MediaCard/GlassFill.web.js +48 -0
  11. package/lib/commonjs/components/MediaCard/MediaCard.js +28 -31
  12. package/lib/commonjs/components/Nudge/Nudge.js +179 -87
  13. package/lib/commonjs/components/index.js +35 -0
  14. package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
  15. package/lib/commonjs/icons/registry.js +1 -1
  16. package/lib/module/components/CardAdvisory/CardAdvisory.js +197 -0
  17. package/lib/module/components/CardCTA/CardCTA.js +199 -17
  18. package/lib/module/components/CircularProgressBar/CircularProgressBar.js +141 -0
  19. package/lib/module/components/CircularProgressBarDoted/CircularProgressBarDoted.js +253 -0
  20. package/lib/module/components/CircularRating/CircularRating.js +155 -0
  21. package/lib/module/components/Gauge/Gauge.js +217 -0
  22. package/lib/module/components/ListGroup/ListGroup.js +3 -1
  23. package/lib/module/components/MediaCard/GlassFill.js +57 -0
  24. package/lib/module/components/MediaCard/GlassFill.web.js +43 -0
  25. package/lib/module/components/MediaCard/MediaCard.js +29 -32
  26. package/lib/module/components/Nudge/Nudge.js +178 -87
  27. package/lib/module/components/index.js +5 -0
  28. package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
  29. package/lib/module/icons/registry.js +1 -1
  30. package/lib/typescript/src/components/CardAdvisory/CardAdvisory.d.ts +49 -0
  31. package/lib/typescript/src/components/CardCTA/CardCTA.d.ts +16 -1
  32. package/lib/typescript/src/components/CircularProgressBar/CircularProgressBar.d.ts +27 -0
  33. package/lib/typescript/src/components/CircularProgressBarDoted/CircularProgressBarDoted.d.ts +48 -0
  34. package/lib/typescript/src/components/CircularRating/CircularRating.d.ts +49 -0
  35. package/lib/typescript/src/components/Gauge/Gauge.d.ts +53 -0
  36. package/lib/typescript/src/components/MediaCard/GlassFill.d.ts +47 -0
  37. package/lib/typescript/src/components/MediaCard/GlassFill.web.d.ts +20 -0
  38. package/lib/typescript/src/components/MediaCard/MediaCard.d.ts +17 -13
  39. package/lib/typescript/src/components/Nudge/Nudge.d.ts +14 -11
  40. package/lib/typescript/src/components/index.d.ts +6 -1
  41. package/lib/typescript/src/icons/registry.d.ts +1 -1
  42. package/package.json +3 -2
  43. package/src/components/CardAdvisory/CardAdvisory.tsx +283 -0
  44. package/src/components/CardCTA/CardCTA.tsx +236 -13
  45. package/src/components/CircularProgressBar/CircularProgressBar.tsx +190 -0
  46. package/src/components/CircularProgressBarDoted/CircularProgressBarDoted.tsx +357 -0
  47. package/src/components/CircularRating/CircularRating.tsx +241 -0
  48. package/src/components/Gauge/Gauge.tsx +303 -0
  49. package/src/components/ListGroup/ListGroup.tsx +3 -1
  50. package/src/components/MediaCard/GlassFill.tsx +89 -0
  51. package/src/components/MediaCard/GlassFill.web.tsx +53 -0
  52. package/src/components/MediaCard/MediaCard.tsx +29 -48
  53. package/src/components/Nudge/Nudge.tsx +222 -82
  54. package/src/components/index.ts +6 -1
  55. package/src/design-tokens/Coin Variables-variables-full.json +1 -1
  56. package/src/icons/registry.ts +1 -1
@@ -0,0 +1,190 @@
1
+ import React from 'react'
2
+ import { StyleSheet, Text, View, type StyleProp, type TextStyle, type ViewStyle } from 'react-native'
3
+ import Svg, { Circle } from 'react-native-svg'
4
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
5
+ import { useTokens } from '../../design-tokens/JFSThemeProvider'
6
+ import { EMPTY_MODES } from '../../utils/react-utils'
7
+ import { IconMinus } from '../../icons/components/IconMinus'
8
+
9
+ type CircularProgressBarBaseProps = Omit<React.ComponentProps<typeof View>, 'children' | 'style'>
10
+
11
+ export type CircularProgressBarState = 'Active' | 'Inactive'
12
+
13
+ export type CircularProgressBarProps = CircularProgressBarBaseProps & {
14
+ /** Current progress value. Clamped between 0 and 100. */
15
+ value?: number
16
+ /** Active shows progress and value; inactive shows the track and minus icon. */
17
+ state?: CircularProgressBarState | boolean
18
+ /** Optional formatted value shown in the active state. */
19
+ valueLabel?: string
20
+ /** Design token modes forwarded to token lookups. */
21
+ modes?: Record<string, any>
22
+ /** Container style override. */
23
+ style?: StyleProp<ViewStyle>
24
+ /** Track stroke style override. */
25
+ trackStyle?: StyleProp<ViewStyle>
26
+ /** Progress stroke style override. */
27
+ progressStyle?: StyleProp<ViewStyle>
28
+ /** Value text style override. */
29
+ valueStyle?: StyleProp<TextStyle>
30
+ /** Accessibility label for the whole progress component. */
31
+ accessibilityLabel?: string
32
+ }
33
+
34
+ const STROKE_WIDTH_RATIO = 8 / 60
35
+
36
+ const clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value))
37
+
38
+ const toNumber = (value: unknown, fallback: number) => {
39
+ if (typeof value === 'number') {
40
+ return Number.isFinite(value) ? value : fallback
41
+ }
42
+
43
+ if (typeof value === 'string') {
44
+ const parsed = Number(value)
45
+ return Number.isFinite(parsed) ? parsed : fallback
46
+ }
47
+
48
+ return fallback
49
+ }
50
+
51
+ const toFontWeight = (value: unknown, fallback: TextStyle['fontWeight']) => {
52
+ if (typeof value === 'number') {
53
+ return String(value) as TextStyle['fontWeight']
54
+ }
55
+
56
+ if (typeof value === 'string') {
57
+ return value as TextStyle['fontWeight']
58
+ }
59
+
60
+ return fallback
61
+ }
62
+
63
+ const getStrokeColor = (style: StyleProp<ViewStyle>, fallback: string) => {
64
+ const flattened = StyleSheet.flatten(style)
65
+ return typeof flattened.backgroundColor === 'string'
66
+ ? flattened.backgroundColor
67
+ : fallback
68
+ }
69
+
70
+ function CircularProgressBar({
71
+ value = 70,
72
+ state = 'Inactive',
73
+ valueLabel,
74
+ modes: propModes = EMPTY_MODES,
75
+ style,
76
+ trackStyle,
77
+ progressStyle,
78
+ valueStyle,
79
+ accessibilityLabel,
80
+ ...rest
81
+ }: CircularProgressBarProps) {
82
+ const { modes: globalModes } = useTokens()
83
+ const modes = { ...globalModes, ...propModes }
84
+
85
+ const isActive = state === true || state === 'Active'
86
+ const normalizedValue = clamp(value, 0, 100)
87
+ const size = toNumber(getVariableByName('circularProgressBar/size', modes), 60)
88
+ const strokeWidth = Math.max(1, size * STROKE_WIDTH_RATIO)
89
+ const radius = Math.max(0, (size - strokeWidth) / 2)
90
+ const center = size / 2
91
+ const circumference = 2 * Math.PI * radius
92
+
93
+ const trackColor = getStrokeColor(
94
+ trackStyle,
95
+ getVariableByName('circularProgressBar/track/color', modes) as string || '#ebebed'
96
+ )
97
+ const progressColor = getStrokeColor(
98
+ progressStyle,
99
+ getVariableByName('circularProgressBar/progress/color', modes) as string || '#25ab21'
100
+ )
101
+ const iconColor = getVariableByName('circularProgressBar/icon/color', modes) as string || '#666666'
102
+ const iconSize = toNumber(getVariableByName('circularProgressBar/icon/size', modes), 24)
103
+
104
+ const foreground = getVariableByName('circularProgressBar/foreground', modes) as string || '#0d0d0f'
105
+ const fontSize = toNumber(getVariableByName('circularProgressBar/fontSize', modes), 18)
106
+ 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')
109
+
110
+ const computedContainerStyle: ViewStyle = {
111
+ alignItems: 'center',
112
+ height: size,
113
+ justifyContent: 'center',
114
+ position: 'relative',
115
+ width: size,
116
+ }
117
+
118
+ const computedValueStyle: TextStyle = {
119
+ color: foreground,
120
+ fontFamily,
121
+ fontSize,
122
+ fontWeight,
123
+ lineHeight,
124
+ position: 'absolute',
125
+ textAlign: 'center',
126
+ }
127
+
128
+ const iconStyle: ViewStyle = {
129
+ left: (size - iconSize) / 2,
130
+ position: 'absolute',
131
+ top: (size - iconSize) / 2,
132
+ }
133
+
134
+ const displayValue = valueLabel ?? String(Math.round(normalizedValue))
135
+ const defaultAccessibilityLabel =
136
+ accessibilityLabel ?? (isActive ? `${displayValue} out of 100` : 'Inactive progress')
137
+
138
+ return (
139
+ <View
140
+ accessibilityRole="progressbar"
141
+ accessibilityLabel={defaultAccessibilityLabel}
142
+ accessibilityValue={{ min: 0, max: 100, now: normalizedValue }}
143
+ style={[computedContainerStyle, style]}
144
+ {...rest}
145
+ >
146
+ <Svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
147
+ <Circle
148
+ cx={center}
149
+ cy={center}
150
+ r={radius}
151
+ stroke={trackColor}
152
+ strokeWidth={strokeWidth}
153
+ fill="none"
154
+ />
155
+ {isActive ? (
156
+ <Circle
157
+ cx={center}
158
+ cy={center}
159
+ r={radius}
160
+ stroke={progressColor}
161
+ strokeWidth={strokeWidth}
162
+ strokeLinecap="round"
163
+ fill="none"
164
+ strokeDasharray={`${circumference} ${circumference}`}
165
+ strokeDashoffset={circumference * (1 - normalizedValue / 100)}
166
+ rotation="-90"
167
+ originX={center}
168
+ originY={center}
169
+ />
170
+ ) : null}
171
+ </Svg>
172
+
173
+ {isActive ? (
174
+ <Text style={[computedValueStyle, valueStyle]}>
175
+ {displayValue}
176
+ </Text>
177
+ ) : (
178
+ <IconMinus
179
+ width={iconSize}
180
+ height={iconSize}
181
+ fill={iconColor}
182
+ color={iconColor}
183
+ style={iconStyle}
184
+ />
185
+ )}
186
+ </View>
187
+ )
188
+ }
189
+
190
+ export default CircularProgressBar
@@ -0,0 +1,357 @@
1
+ import React, { useMemo, useState } from 'react'
2
+ import {
3
+ type LayoutChangeEvent,
4
+ Pressable,
5
+ StyleSheet,
6
+ Text,
7
+ View,
8
+ type StyleProp,
9
+ type TextStyle,
10
+ type ViewStyle,
11
+ } from 'react-native'
12
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
13
+ import { useTokens } from '../../design-tokens/JFSThemeProvider'
14
+ import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils'
15
+ import { IconChevronright } from '../../icons/components/IconChevronright'
16
+
17
+ type CircularProgressBarDotedBaseProps = Omit<React.ComponentProps<typeof View>, 'children' | 'style'>
18
+
19
+ export type CircularProgressBarDotedProps = CircularProgressBarDotedBaseProps & {
20
+ /** Progress value. Clamped between 0 and 100. */
21
+ value?: number
22
+ /** Number of dots in the ring. */
23
+ dotCount?: number
24
+ /** Small label above the score. */
25
+ label?: string
26
+ /** Text below the score. */
27
+ tierLabel?: string
28
+ /** Show or hide the chevron after the tier label. */
29
+ showChevron?: boolean
30
+ /** Called when the component is pressed. */
31
+ onPress?: () => void
32
+ /** Called when the tier row is pressed. */
33
+ onTierPress?: () => void
34
+ /** Design token modes forwarded to token lookups and slot children. */
35
+ modes?: Record<string, any>
36
+ /** Slot rendered in the center of the dotted ring. Receives `modes` recursively. */
37
+ children?: React.ReactNode
38
+ /** Container style override. */
39
+ style?: StyleProp<ViewStyle>
40
+ /** Ring wrapper style override. */
41
+ ringStyle?: StyleProp<ViewStyle>
42
+ /** Track dot style override. */
43
+ trackDotStyle?: StyleProp<ViewStyle>
44
+ /** Progress dot style override. */
45
+ progressDotStyle?: StyleProp<ViewStyle>
46
+ /** Center content style override. */
47
+ contentStyle?: StyleProp<ViewStyle>
48
+ /** Score tier stack style override. */
49
+ scoreTierStyle?: StyleProp<ViewStyle>
50
+ /** Score trend row style override. */
51
+ scoreTrendStyle?: StyleProp<ViewStyle>
52
+ /** Label text style override. */
53
+ labelStyle?: StyleProp<TextStyle>
54
+ /** Score text style override. */
55
+ scoreLabelStyle?: StyleProp<TextStyle>
56
+ /** Tier text style override. */
57
+ tierLabelStyle?: StyleProp<TextStyle>
58
+ /** Accessibility label for the whole progress component. */
59
+ accessibilityLabel?: string
60
+ }
61
+
62
+ const DEFAULT_DOT_COUNT = 24
63
+ const START_ANGLE_DEGREES = -90
64
+
65
+ const clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value))
66
+
67
+ const toNumber = (value: unknown, fallback: number) => {
68
+ if (typeof value === 'number') {
69
+ return Number.isFinite(value) ? value : fallback
70
+ }
71
+
72
+ if (typeof value === 'string') {
73
+ const parsed = Number(value)
74
+ return Number.isFinite(parsed) ? parsed : fallback
75
+ }
76
+
77
+ return fallback
78
+ }
79
+
80
+ const toFontWeight = (value: unknown, fallback: TextStyle['fontWeight']) => {
81
+ if (typeof value === 'number') {
82
+ return String(value) as TextStyle['fontWeight']
83
+ }
84
+
85
+ if (typeof value === 'string') {
86
+ return value as TextStyle['fontWeight']
87
+ }
88
+
89
+ return fallback
90
+ }
91
+
92
+ const getBackgroundColor = (style: StyleProp<ViewStyle>, fallback: string) => {
93
+ const flattened = StyleSheet.flatten(style)
94
+ return typeof flattened.backgroundColor === 'string'
95
+ ? flattened.backgroundColor
96
+ : fallback
97
+ }
98
+
99
+ function CircularProgressBarDoted({
100
+ value = 72,
101
+ dotCount = DEFAULT_DOT_COUNT,
102
+ label = 'Rating',
103
+ tierLabel = 'Doing great',
104
+ showChevron = true,
105
+ onPress,
106
+ onTierPress,
107
+ modes: propModes = EMPTY_MODES,
108
+ children,
109
+ style,
110
+ ringStyle,
111
+ trackDotStyle,
112
+ progressDotStyle,
113
+ contentStyle,
114
+ scoreTierStyle,
115
+ scoreTrendStyle,
116
+ labelStyle,
117
+ scoreLabelStyle,
118
+ tierLabelStyle,
119
+ accessibilityLabel,
120
+ onLayout,
121
+ ...rest
122
+ }: CircularProgressBarDotedProps) {
123
+ const { modes: globalModes } = useTokens()
124
+ const modes = { ...globalModes, ...propModes }
125
+ const [layoutSize, setLayoutSize] = useState(0)
126
+
127
+ const normalizedValue = clamp(value, 0, 100)
128
+ const resolvedDotCount = Math.max(1, Math.floor(dotCount))
129
+ const activeDots = normalizedValue <= 0
130
+ ? 0
131
+ : Math.ceil((normalizedValue / 100) * resolvedDotCount)
132
+
133
+ const dotShadowSize = toNumber(getVariableByName('circularProgressBarDoted/dot/shadow/size', modes), 6)
134
+ const baseDotSize = toNumber(getVariableByName('circularProgressBarDoted/dot/size', modes), 6)
135
+ const dotSize = baseDotSize + dotShadowSize
136
+ const outerDotSize = dotSize
137
+ const ringSize = layoutSize
138
+ const ringRadius = Math.max(0, (ringSize - outerDotSize) / 2)
139
+
140
+ const trackDotColor = getBackgroundColor(
141
+ trackDotStyle,
142
+ getVariableByName('circularProgressBarDoted/trackDot/bg', modes) as string || '#ebebed'
143
+ )
144
+ const progressDotColor = getBackgroundColor(
145
+ progressDotStyle,
146
+ getVariableByName('circularProgressBarDoted/progressDot/bg', modes) as string || '#25ab21'
147
+ )
148
+
149
+ const contentGap = toNumber(getVariableByName('circularProgressBarDoted/gap', modes), 12)
150
+ const scoreTierGap = toNumber(getVariableByName('circularProgressBarDoted/scoreTier/gap', modes), 6)
151
+ const scoreTierWidth = toNumber(getVariableByName('circularProgressBarDoted/scoreTier/width', modes), 116)
152
+ const scoreTrendGap = toNumber(getVariableByName('circularProgressBarDoted/scoreTrend/gap', modes), 2)
153
+ const scoreTrendHeight = toNumber(getVariableByName('circularProgressBarDoted/scoreTrend/height', modes), 24)
154
+
155
+ const typographyFontFamily = getVariableByName('Typography/Font Family', modes) as string || 'JioType Var'
156
+ const labelColor = getVariableByName('circularProgressBarDoted/label/color', modes) as string || '#080d1a'
157
+ const labelFontSize = toNumber(getVariableByName('Typography/Size/Body/XS', modes), 12)
158
+ const labelFontWeight = toFontWeight(getVariableByName('Typography/Font Weight/Body Low (Regular)', modes), '400')
159
+
160
+ const scoreColor = getVariableByName('circularProgressBarDoted/scoreLabel/color', modes) as string || '#080d1a'
161
+ const scoreFontSize = toNumber(getVariableByName('circularProgressBarDoted/scoreLabel/fontSize', modes), 56)
162
+ const scoreFontFamily = getVariableByName('circularProgressBarDoted/scoreLabel/fontFamily', modes) as string || 'JioType Var'
163
+ const scoreLineHeight = toNumber(getVariableByName('circularProgressBarDoted/scoreLabel/lineHeight', modes), 56)
164
+ const scoreFontWeight = toFontWeight(getVariableByName('circularProgressBarDoted/scoreLabel/fontWeight', modes), '900')
165
+
166
+ const tierColor = getVariableByName('circularProgressBarDoted/tierLabel/color', modes) as string || '#080d1a'
167
+ const tierFontSize = toNumber(getVariableByName('Typography/Size/Body/M', modes), 16)
168
+ const tierFontWeight = toFontWeight(getVariableByName('Typography/Font Weight/Body High', modes), '700')
169
+ const iconColor = getVariableByName('circularProgressBarDoted/icon/color', modes) as string || '#303338'
170
+ const iconSize = toNumber(getVariableByName('circularProgressBarDoted/icon/size', modes), 24)
171
+
172
+ const dots = useMemo(
173
+ () => Array.from({ length: resolvedDotCount }, (_, index) => {
174
+ const angle = ((360 / resolvedDotCount) * index + START_ANGLE_DEGREES) * (Math.PI / 180)
175
+ const center = ringSize / 2
176
+
177
+ return {
178
+ isActive: index < activeDots,
179
+ left: center + ringRadius * Math.cos(angle) - outerDotSize / 2,
180
+ top: center + ringRadius * Math.sin(angle) - outerDotSize / 2,
181
+ }
182
+ }),
183
+ [activeDots, outerDotSize, resolvedDotCount, ringRadius, ringSize]
184
+ )
185
+
186
+ const containerStyle: ViewStyle = {
187
+ alignItems: 'center',
188
+ alignSelf: 'stretch',
189
+ height: '100%',
190
+ justifyContent: 'center',
191
+ position: 'relative',
192
+ width: '100%',
193
+ }
194
+
195
+ const computedRingStyle: ViewStyle = {
196
+ height: ringSize,
197
+ position: 'absolute',
198
+ width: ringSize,
199
+ }
200
+
201
+ const dotOuterStyle: ViewStyle = {
202
+ alignItems: 'center',
203
+ height: outerDotSize,
204
+ justifyContent: 'center',
205
+ position: 'absolute',
206
+ width: outerDotSize,
207
+ }
208
+
209
+ const dotInnerStyle: ViewStyle = {
210
+ borderRadius: dotSize / 2,
211
+ height: dotSize,
212
+ width: dotSize,
213
+ }
214
+
215
+ const computedContentStyle: ViewStyle = {
216
+ alignItems: 'center',
217
+ gap: contentGap,
218
+ justifyContent: 'center',
219
+ minWidth: scoreTierWidth,
220
+ }
221
+
222
+ const computedScoreTierStyle: ViewStyle = {
223
+ alignItems: 'center',
224
+ gap: scoreTierGap,
225
+ justifyContent: 'center',
226
+ width: '100%',
227
+ }
228
+
229
+ const computedScoreTrendStyle: ViewStyle = {
230
+ alignItems: 'center',
231
+ flexDirection: 'row',
232
+ gap: scoreTrendGap,
233
+ height: scoreTrendHeight,
234
+ justifyContent: 'center',
235
+ minWidth: scoreTierWidth,
236
+ }
237
+
238
+ const computedLabelStyle: TextStyle = {
239
+ color: labelColor,
240
+ fontFamily: typographyFontFamily,
241
+ fontSize: labelFontSize,
242
+ fontWeight: labelFontWeight,
243
+ lineHeight: labelFontSize * 1.3,
244
+ textAlign: 'center',
245
+ }
246
+
247
+ const computedScoreLabelStyle: TextStyle = {
248
+ color: scoreColor,
249
+ fontFamily: scoreFontFamily,
250
+ fontSize: scoreFontSize,
251
+ fontWeight: scoreFontWeight,
252
+ lineHeight: scoreLineHeight,
253
+ textAlign: 'center',
254
+ }
255
+
256
+ const computedTierLabelStyle: TextStyle = {
257
+ color: tierColor,
258
+ fontFamily: typographyFontFamily,
259
+ fontSize: tierFontSize,
260
+ fontWeight: tierFontWeight,
261
+ lineHeight: tierFontSize * 1.3,
262
+ textAlign: 'center',
263
+ }
264
+
265
+ const resolvedScoreLabel = String(Math.round(normalizedValue))
266
+ const defaultAccessibilityLabel =
267
+ accessibilityLabel ?? `${label}. ${resolvedScoreLabel} out of 100. ${tierLabel}`
268
+
269
+ const handleLayout = (event: LayoutChangeEvent) => {
270
+ onLayout?.(event)
271
+
272
+ const { width, height } = event.nativeEvent.layout
273
+ const nextSize = Math.max(0, Math.min(width, height))
274
+ setLayoutSize((currentSize) => currentSize === nextSize ? currentSize : nextSize)
275
+ }
276
+
277
+ const trendContent = (
278
+ <>
279
+ <Text numberOfLines={1} style={[computedTierLabelStyle, tierLabelStyle]}>
280
+ {tierLabel}
281
+ </Text>
282
+ {showChevron ? (
283
+ <IconChevronright
284
+ width={iconSize}
285
+ height={iconSize}
286
+ fill={iconColor}
287
+ color={iconColor}
288
+ />
289
+ ) : null}
290
+ </>
291
+ )
292
+
293
+ return (
294
+ <Pressable
295
+ accessibilityRole="progressbar"
296
+ accessibilityLabel={defaultAccessibilityLabel}
297
+ accessibilityValue={{ min: 0, max: 100, now: normalizedValue }}
298
+ disabled={!onPress}
299
+ onLayout={handleLayout}
300
+ onPress={onPress}
301
+ style={[containerStyle, style]}
302
+ {...rest}
303
+ >
304
+ <View pointerEvents="none" style={[computedRingStyle, ringStyle]}>
305
+ {dots.map((dot, index) => (
306
+ <View
307
+ key={index}
308
+ style={[
309
+ dotOuterStyle,
310
+ { left: dot.left, top: dot.top },
311
+ ]}
312
+ >
313
+ <View
314
+ style={[
315
+ dotInnerStyle,
316
+ { backgroundColor: dot.isActive ? progressDotColor : trackDotColor },
317
+ dot.isActive ? progressDotStyle : trackDotStyle,
318
+ ]}
319
+ />
320
+ </View>
321
+ ))}
322
+ </View>
323
+
324
+ <View style={[computedContentStyle, contentStyle]}>
325
+ {children ? (
326
+ cloneChildrenWithModes(children, modes)
327
+ ) : (
328
+ <>
329
+ <View style={[computedScoreTierStyle, scoreTierStyle]}>
330
+ <Text style={[computedLabelStyle, labelStyle]}>
331
+ {label}
332
+ </Text>
333
+ <Text style={[computedScoreLabelStyle, scoreLabelStyle]}>
334
+ {resolvedScoreLabel}
335
+ </Text>
336
+ </View>
337
+ {onTierPress ? (
338
+ <Pressable
339
+ accessibilityRole="button"
340
+ onPress={onTierPress}
341
+ style={[computedScoreTrendStyle, scoreTrendStyle]}
342
+ >
343
+ {trendContent}
344
+ </Pressable>
345
+ ) : (
346
+ <View style={[computedScoreTrendStyle, scoreTrendStyle]}>
347
+ {trendContent}
348
+ </View>
349
+ )}
350
+ </>
351
+ )}
352
+ </View>
353
+ </Pressable>
354
+ )
355
+ }
356
+
357
+ export default CircularProgressBarDoted