jfs-components 0.0.70 → 0.0.72

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 (66) hide show
  1. package/CHANGELOG.md +49 -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/CardFinancialCondition/CardFinancialCondition.js +213 -0
  5. package/lib/commonjs/components/Carousel/Carousel.js +9 -7
  6. package/lib/commonjs/components/CircularProgressBar/CircularProgressBar.js +147 -0
  7. package/lib/commonjs/components/CircularProgressBarDoted/CircularProgressBarDoted.js +258 -0
  8. package/lib/commonjs/components/CircularRating/CircularRating.js +161 -0
  9. package/lib/commonjs/components/Gauge/Gauge.js +223 -0
  10. package/lib/commonjs/components/HoldingsCard/HoldingsCard.js +2 -2
  11. package/lib/commonjs/components/InstitutionBadge/InstitutionBadge.js +132 -0
  12. package/lib/commonjs/components/ListGroup/ListGroup.js +3 -1
  13. package/lib/commonjs/components/Nudge/Nudge.js +179 -87
  14. package/lib/commonjs/components/Radio/Radio.js +194 -0
  15. package/lib/commonjs/components/RadioButton/RadioButton.js +21 -188
  16. package/lib/commonjs/components/index.js +56 -0
  17. package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
  18. package/lib/commonjs/icons/registry.js +1 -1
  19. package/lib/module/components/CardAdvisory/CardAdvisory.js +197 -0
  20. package/lib/module/components/CardCTA/CardCTA.js +199 -17
  21. package/lib/module/components/CardFinancialCondition/CardFinancialCondition.js +207 -0
  22. package/lib/module/components/Carousel/Carousel.js +9 -7
  23. package/lib/module/components/CircularProgressBar/CircularProgressBar.js +141 -0
  24. package/lib/module/components/CircularProgressBarDoted/CircularProgressBarDoted.js +253 -0
  25. package/lib/module/components/CircularRating/CircularRating.js +155 -0
  26. package/lib/module/components/Gauge/Gauge.js +217 -0
  27. package/lib/module/components/HoldingsCard/HoldingsCard.js +2 -2
  28. package/lib/module/components/InstitutionBadge/InstitutionBadge.js +127 -0
  29. package/lib/module/components/ListGroup/ListGroup.js +3 -1
  30. package/lib/module/components/Nudge/Nudge.js +178 -87
  31. package/lib/module/components/Radio/Radio.js +188 -0
  32. package/lib/module/components/RadioButton/RadioButton.js +20 -185
  33. package/lib/module/components/index.js +12 -0
  34. package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
  35. package/lib/module/icons/registry.js +1 -1
  36. package/lib/typescript/src/components/CardAdvisory/CardAdvisory.d.ts +49 -0
  37. package/lib/typescript/src/components/CardCTA/CardCTA.d.ts +16 -1
  38. package/lib/typescript/src/components/CardFinancialCondition/CardFinancialCondition.d.ts +50 -0
  39. package/lib/typescript/src/components/CircularProgressBar/CircularProgressBar.d.ts +27 -0
  40. package/lib/typescript/src/components/CircularProgressBarDoted/CircularProgressBarDoted.d.ts +48 -0
  41. package/lib/typescript/src/components/CircularRating/CircularRating.d.ts +49 -0
  42. package/lib/typescript/src/components/Gauge/Gauge.d.ts +53 -0
  43. package/lib/typescript/src/components/InstitutionBadge/InstitutionBadge.d.ts +30 -0
  44. package/lib/typescript/src/components/Nudge/Nudge.d.ts +14 -11
  45. package/lib/typescript/src/components/Radio/Radio.d.ts +30 -0
  46. package/lib/typescript/src/components/RadioButton/RadioButton.d.ts +20 -28
  47. package/lib/typescript/src/components/index.d.ts +13 -1
  48. package/lib/typescript/src/icons/registry.d.ts +1 -1
  49. package/package.json +1 -1
  50. package/src/components/CardAdvisory/CardAdvisory.tsx +283 -0
  51. package/src/components/CardCTA/CardCTA.tsx +236 -13
  52. package/src/components/CardFinancialCondition/CardFinancialCondition.tsx +366 -0
  53. package/src/components/Carousel/Carousel.tsx +14 -6
  54. package/src/components/CircularProgressBar/CircularProgressBar.tsx +190 -0
  55. package/src/components/CircularProgressBarDoted/CircularProgressBarDoted.tsx +357 -0
  56. package/src/components/CircularRating/CircularRating.tsx +241 -0
  57. package/src/components/Gauge/Gauge.tsx +303 -0
  58. package/src/components/HoldingsCard/HoldingsCard.tsx +2 -2
  59. package/src/components/InstitutionBadge/InstitutionBadge.tsx +216 -0
  60. package/src/components/ListGroup/ListGroup.tsx +3 -1
  61. package/src/components/Nudge/Nudge.tsx +222 -82
  62. package/src/components/Radio/Radio.tsx +227 -0
  63. package/src/components/RadioButton/RadioButton.tsx +23 -225
  64. package/src/components/index.ts +13 -1
  65. package/src/design-tokens/Coin Variables-variables-full.json +1 -1
  66. package/src/icons/registry.ts +1 -1
@@ -43,6 +43,8 @@ export function Carousel({
43
43
  const gap = gapProp ?? tokenGap;
44
44
  const containerPaddingH = parseFloat(getVariableByName('carousel/padding/horizontal', modes) || '0');
45
45
  const containerPaddingV = parseFloat(getVariableByName('carousel/padding/vertical', modes) || '0');
46
+ // Outer container max height per Figma (`carousel/maxHeight`).
47
+ const maxHeight = parseFloat(getVariableByName('carousel/maxHeight', modes) || '280');
46
48
  // Spacing between the cards row and the pagination dots uses `carousel/gap`.
47
49
  const paginationOffset = gap;
48
50
 
@@ -154,7 +156,8 @@ export function Carousel({
154
156
 
155
157
  // ---- Render ----
156
158
  const outerStyle = {
157
- paddingVertical: containerPaddingV
159
+ paddingVertical: containerPaddingV,
160
+ maxHeight
158
161
  };
159
162
  const contentContainerStyle = {
160
163
  paddingHorizontal: containerPaddingH * 2,
@@ -262,13 +265,12 @@ export function Pagination({
262
265
  const modes = propModes || ctxModes || {};
263
266
 
264
267
  // Token resolution for dots — matches Figma tokens
265
- // (carousel/pagination/gap, carousel/pagination/indicator/{activecolor,inactivecolor,radius}).
266
- // Dot dimensions are fixed per Figma spec: inactive 6x6, active 16x6.
267
- const dotSize = 6;
268
- const dotActiveWidth = 16;
268
+ // (carousel/pagination/gap, carousel/pagination/indicator/{activeColor,inactiveColor,radius,size,activeWidth}).
269
+ const dotSize = parseFloat(getVariableByName('carousel/pagination/indicator/size', modes) || '6');
270
+ const dotActiveWidth = parseFloat(getVariableByName('carousel/pagination/indicator/activeWidth', modes) || '16');
269
271
  const dotGap = parseFloat(getVariableByName('carousel/pagination/gap', modes) || '4');
270
- const dotColor = getVariableByName('carousel/pagination/indicator/inactivecolor', modes) || 'rgba(0,0,0,0.3)';
271
- const dotActiveColor = getVariableByName('carousel/pagination/indicator/activecolor', modes) || '#170d0a';
272
+ const dotColor = getVariableByName('carousel/pagination/indicator/inactiveColor', modes) || 'rgba(0,0,0,0.3)';
273
+ const dotActiveColor = getVariableByName('carousel/pagination/indicator/activeColor', modes) || '#170d0a';
272
274
  const dotRadius = parseFloat(getVariableByName('carousel/pagination/indicator/radius', modes) || '9999');
273
275
  const containerStyle = {
274
276
  flexDirection: 'row',
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+
3
+ import React from 'react';
4
+ import { StyleSheet, Text, View } from 'react-native';
5
+ import Svg, { Circle } from 'react-native-svg';
6
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
7
+ import { useTokens } from '../../design-tokens/JFSThemeProvider';
8
+ import { EMPTY_MODES } from '../../utils/react-utils';
9
+ import { IconMinus } from '../../icons/components/IconMinus';
10
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
+ const STROKE_WIDTH_RATIO = 8 / 60;
12
+ const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
13
+ const toNumber = (value, fallback) => {
14
+ if (typeof value === 'number') {
15
+ return Number.isFinite(value) ? value : fallback;
16
+ }
17
+ if (typeof value === 'string') {
18
+ const parsed = Number(value);
19
+ return Number.isFinite(parsed) ? parsed : fallback;
20
+ }
21
+ return fallback;
22
+ };
23
+ const toFontWeight = (value, fallback) => {
24
+ if (typeof value === 'number') {
25
+ return String(value);
26
+ }
27
+ if (typeof value === 'string') {
28
+ return value;
29
+ }
30
+ return fallback;
31
+ };
32
+ const getStrokeColor = (style, fallback) => {
33
+ const flattened = StyleSheet.flatten(style);
34
+ return typeof flattened.backgroundColor === 'string' ? flattened.backgroundColor : fallback;
35
+ };
36
+ function CircularProgressBar({
37
+ value = 70,
38
+ state = 'Inactive',
39
+ valueLabel,
40
+ modes: propModes = EMPTY_MODES,
41
+ style,
42
+ trackStyle,
43
+ progressStyle,
44
+ valueStyle,
45
+ accessibilityLabel,
46
+ ...rest
47
+ }) {
48
+ const {
49
+ modes: globalModes
50
+ } = useTokens();
51
+ const modes = {
52
+ ...globalModes,
53
+ ...propModes
54
+ };
55
+ const isActive = state === true || state === 'Active';
56
+ const normalizedValue = clamp(value, 0, 100);
57
+ const size = toNumber(getVariableByName('circularProgressBar/size', modes), 60);
58
+ const strokeWidth = Math.max(1, size * STROKE_WIDTH_RATIO);
59
+ const radius = Math.max(0, (size - strokeWidth) / 2);
60
+ const center = size / 2;
61
+ const circumference = 2 * Math.PI * radius;
62
+ const trackColor = getStrokeColor(trackStyle, getVariableByName('circularProgressBar/track/color', modes) || '#ebebed');
63
+ const progressColor = getStrokeColor(progressStyle, getVariableByName('circularProgressBar/progress/color', modes) || '#25ab21');
64
+ const iconColor = getVariableByName('circularProgressBar/icon/color', modes) || '#666666';
65
+ const iconSize = toNumber(getVariableByName('circularProgressBar/icon/size', modes), 24);
66
+ const foreground = getVariableByName('circularProgressBar/foreground', modes) || '#0d0d0f';
67
+ const fontSize = toNumber(getVariableByName('circularProgressBar/fontSize', modes), 18);
68
+ const fontFamily = getVariableByName('circularProgressBar/fontFamily', modes) || 'JioType Var';
69
+ const lineHeight = toNumber(getVariableByName('circularProgressBar/lineHeight', modes), 21);
70
+ const fontWeight = toFontWeight(getVariableByName('circularProgressBar/fontWeight', modes), '700');
71
+ const computedContainerStyle = {
72
+ alignItems: 'center',
73
+ height: size,
74
+ justifyContent: 'center',
75
+ position: 'relative',
76
+ width: size
77
+ };
78
+ const computedValueStyle = {
79
+ color: foreground,
80
+ fontFamily,
81
+ fontSize,
82
+ fontWeight,
83
+ lineHeight,
84
+ position: 'absolute',
85
+ textAlign: 'center'
86
+ };
87
+ const iconStyle = {
88
+ left: (size - iconSize) / 2,
89
+ position: 'absolute',
90
+ top: (size - iconSize) / 2
91
+ };
92
+ const displayValue = valueLabel ?? String(Math.round(normalizedValue));
93
+ const defaultAccessibilityLabel = accessibilityLabel ?? (isActive ? `${displayValue} out of 100` : 'Inactive progress');
94
+ return /*#__PURE__*/_jsxs(View, {
95
+ accessibilityRole: "progressbar",
96
+ accessibilityLabel: defaultAccessibilityLabel,
97
+ accessibilityValue: {
98
+ min: 0,
99
+ max: 100,
100
+ now: normalizedValue
101
+ },
102
+ style: [computedContainerStyle, style],
103
+ ...rest,
104
+ children: [/*#__PURE__*/_jsxs(Svg, {
105
+ width: size,
106
+ height: size,
107
+ viewBox: `0 0 ${size} ${size}`,
108
+ children: [/*#__PURE__*/_jsx(Circle, {
109
+ cx: center,
110
+ cy: center,
111
+ r: radius,
112
+ stroke: trackColor,
113
+ strokeWidth: strokeWidth,
114
+ fill: "none"
115
+ }), isActive ? /*#__PURE__*/_jsx(Circle, {
116
+ cx: center,
117
+ cy: center,
118
+ r: radius,
119
+ stroke: progressColor,
120
+ strokeWidth: strokeWidth,
121
+ strokeLinecap: "round",
122
+ fill: "none",
123
+ strokeDasharray: `${circumference} ${circumference}`,
124
+ strokeDashoffset: circumference * (1 - normalizedValue / 100),
125
+ rotation: "-90",
126
+ originX: center,
127
+ originY: center
128
+ }) : null]
129
+ }), isActive ? /*#__PURE__*/_jsx(Text, {
130
+ style: [computedValueStyle, valueStyle],
131
+ children: displayValue
132
+ }) : /*#__PURE__*/_jsx(IconMinus, {
133
+ width: iconSize,
134
+ height: iconSize,
135
+ fill: iconColor,
136
+ color: iconColor,
137
+ style: iconStyle
138
+ })]
139
+ });
140
+ }
141
+ export default CircularProgressBar;
@@ -0,0 +1,253 @@
1
+ "use strict";
2
+
3
+ import React, { useMemo, useState } from 'react';
4
+ import { Pressable, StyleSheet, Text, View } from 'react-native';
5
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
6
+ import { useTokens } from '../../design-tokens/JFSThemeProvider';
7
+ import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils';
8
+ import { IconChevronright } from '../../icons/components/IconChevronright';
9
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
10
+ const DEFAULT_DOT_COUNT = 24;
11
+ const START_ANGLE_DEGREES = -90;
12
+ const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
13
+ const toNumber = (value, fallback) => {
14
+ if (typeof value === 'number') {
15
+ return Number.isFinite(value) ? value : fallback;
16
+ }
17
+ if (typeof value === 'string') {
18
+ const parsed = Number(value);
19
+ return Number.isFinite(parsed) ? parsed : fallback;
20
+ }
21
+ return fallback;
22
+ };
23
+ const toFontWeight = (value, fallback) => {
24
+ if (typeof value === 'number') {
25
+ return String(value);
26
+ }
27
+ if (typeof value === 'string') {
28
+ return value;
29
+ }
30
+ return fallback;
31
+ };
32
+ const getBackgroundColor = (style, fallback) => {
33
+ const flattened = StyleSheet.flatten(style);
34
+ return typeof flattened.backgroundColor === 'string' ? flattened.backgroundColor : fallback;
35
+ };
36
+ function CircularProgressBarDoted({
37
+ value = 72,
38
+ dotCount = DEFAULT_DOT_COUNT,
39
+ label = 'Rating',
40
+ tierLabel = 'Doing great',
41
+ showChevron = true,
42
+ onPress,
43
+ onTierPress,
44
+ modes: propModes = EMPTY_MODES,
45
+ children,
46
+ style,
47
+ ringStyle,
48
+ trackDotStyle,
49
+ progressDotStyle,
50
+ contentStyle,
51
+ scoreTierStyle,
52
+ scoreTrendStyle,
53
+ labelStyle,
54
+ scoreLabelStyle,
55
+ tierLabelStyle,
56
+ accessibilityLabel,
57
+ onLayout,
58
+ ...rest
59
+ }) {
60
+ const {
61
+ modes: globalModes
62
+ } = useTokens();
63
+ const modes = {
64
+ ...globalModes,
65
+ ...propModes
66
+ };
67
+ const [layoutSize, setLayoutSize] = useState(0);
68
+ const normalizedValue = clamp(value, 0, 100);
69
+ const resolvedDotCount = Math.max(1, Math.floor(dotCount));
70
+ const activeDots = normalizedValue <= 0 ? 0 : Math.ceil(normalizedValue / 100 * resolvedDotCount);
71
+ const dotShadowSize = toNumber(getVariableByName('circularProgressBarDoted/dot/shadow/size', modes), 6);
72
+ const baseDotSize = toNumber(getVariableByName('circularProgressBarDoted/dot/size', modes), 6);
73
+ const dotSize = baseDotSize + dotShadowSize;
74
+ const outerDotSize = dotSize;
75
+ const ringSize = layoutSize;
76
+ const ringRadius = Math.max(0, (ringSize - outerDotSize) / 2);
77
+ const trackDotColor = getBackgroundColor(trackDotStyle, getVariableByName('circularProgressBarDoted/trackDot/bg', modes) || '#ebebed');
78
+ const progressDotColor = getBackgroundColor(progressDotStyle, getVariableByName('circularProgressBarDoted/progressDot/bg', modes) || '#25ab21');
79
+ const contentGap = toNumber(getVariableByName('circularProgressBarDoted/gap', modes), 12);
80
+ const scoreTierGap = toNumber(getVariableByName('circularProgressBarDoted/scoreTier/gap', modes), 6);
81
+ const scoreTierWidth = toNumber(getVariableByName('circularProgressBarDoted/scoreTier/width', modes), 116);
82
+ const scoreTrendGap = toNumber(getVariableByName('circularProgressBarDoted/scoreTrend/gap', modes), 2);
83
+ const scoreTrendHeight = toNumber(getVariableByName('circularProgressBarDoted/scoreTrend/height', modes), 24);
84
+ const typographyFontFamily = getVariableByName('Typography/Font Family', modes) || 'JioType Var';
85
+ const labelColor = getVariableByName('circularProgressBarDoted/label/color', modes) || '#080d1a';
86
+ const labelFontSize = toNumber(getVariableByName('Typography/Size/Body/XS', modes), 12);
87
+ const labelFontWeight = toFontWeight(getVariableByName('Typography/Font Weight/Body Low (Regular)', modes), '400');
88
+ const scoreColor = getVariableByName('circularProgressBarDoted/scoreLabel/color', modes) || '#080d1a';
89
+ const scoreFontSize = toNumber(getVariableByName('circularProgressBarDoted/scoreLabel/fontSize', modes), 56);
90
+ const scoreFontFamily = getVariableByName('circularProgressBarDoted/scoreLabel/fontFamily', modes) || 'JioType Var';
91
+ const scoreLineHeight = toNumber(getVariableByName('circularProgressBarDoted/scoreLabel/lineHeight', modes), 56);
92
+ const scoreFontWeight = toFontWeight(getVariableByName('circularProgressBarDoted/scoreLabel/fontWeight', modes), '900');
93
+ const tierColor = getVariableByName('circularProgressBarDoted/tierLabel/color', modes) || '#080d1a';
94
+ const tierFontSize = toNumber(getVariableByName('Typography/Size/Body/M', modes), 16);
95
+ const tierFontWeight = toFontWeight(getVariableByName('Typography/Font Weight/Body High', modes), '700');
96
+ const iconColor = getVariableByName('circularProgressBarDoted/icon/color', modes) || '#303338';
97
+ const iconSize = toNumber(getVariableByName('circularProgressBarDoted/icon/size', modes), 24);
98
+ const dots = useMemo(() => Array.from({
99
+ length: resolvedDotCount
100
+ }, (_, index) => {
101
+ const angle = (360 / resolvedDotCount * index + START_ANGLE_DEGREES) * (Math.PI / 180);
102
+ const center = ringSize / 2;
103
+ return {
104
+ isActive: index < activeDots,
105
+ left: center + ringRadius * Math.cos(angle) - outerDotSize / 2,
106
+ top: center + ringRadius * Math.sin(angle) - outerDotSize / 2
107
+ };
108
+ }), [activeDots, outerDotSize, resolvedDotCount, ringRadius, ringSize]);
109
+ const containerStyle = {
110
+ alignItems: 'center',
111
+ alignSelf: 'stretch',
112
+ height: '100%',
113
+ justifyContent: 'center',
114
+ position: 'relative',
115
+ width: '100%'
116
+ };
117
+ const computedRingStyle = {
118
+ height: ringSize,
119
+ position: 'absolute',
120
+ width: ringSize
121
+ };
122
+ const dotOuterStyle = {
123
+ alignItems: 'center',
124
+ height: outerDotSize,
125
+ justifyContent: 'center',
126
+ position: 'absolute',
127
+ width: outerDotSize
128
+ };
129
+ const dotInnerStyle = {
130
+ borderRadius: dotSize / 2,
131
+ height: dotSize,
132
+ width: dotSize
133
+ };
134
+ const computedContentStyle = {
135
+ alignItems: 'center',
136
+ gap: contentGap,
137
+ justifyContent: 'center',
138
+ minWidth: scoreTierWidth
139
+ };
140
+ const computedScoreTierStyle = {
141
+ alignItems: 'center',
142
+ gap: scoreTierGap,
143
+ justifyContent: 'center',
144
+ width: '100%'
145
+ };
146
+ const computedScoreTrendStyle = {
147
+ alignItems: 'center',
148
+ flexDirection: 'row',
149
+ gap: scoreTrendGap,
150
+ height: scoreTrendHeight,
151
+ justifyContent: 'center',
152
+ minWidth: scoreTierWidth
153
+ };
154
+ const computedLabelStyle = {
155
+ color: labelColor,
156
+ fontFamily: typographyFontFamily,
157
+ fontSize: labelFontSize,
158
+ fontWeight: labelFontWeight,
159
+ lineHeight: labelFontSize * 1.3,
160
+ textAlign: 'center'
161
+ };
162
+ const computedScoreLabelStyle = {
163
+ color: scoreColor,
164
+ fontFamily: scoreFontFamily,
165
+ fontSize: scoreFontSize,
166
+ fontWeight: scoreFontWeight,
167
+ lineHeight: scoreLineHeight,
168
+ textAlign: 'center'
169
+ };
170
+ const computedTierLabelStyle = {
171
+ color: tierColor,
172
+ fontFamily: typographyFontFamily,
173
+ fontSize: tierFontSize,
174
+ fontWeight: tierFontWeight,
175
+ lineHeight: tierFontSize * 1.3,
176
+ textAlign: 'center'
177
+ };
178
+ const resolvedScoreLabel = String(Math.round(normalizedValue));
179
+ const defaultAccessibilityLabel = accessibilityLabel ?? `${label}. ${resolvedScoreLabel} out of 100. ${tierLabel}`;
180
+ const handleLayout = event => {
181
+ onLayout?.(event);
182
+ const {
183
+ width,
184
+ height
185
+ } = event.nativeEvent.layout;
186
+ const nextSize = Math.max(0, Math.min(width, height));
187
+ setLayoutSize(currentSize => currentSize === nextSize ? currentSize : nextSize);
188
+ };
189
+ const trendContent = /*#__PURE__*/_jsxs(_Fragment, {
190
+ children: [/*#__PURE__*/_jsx(Text, {
191
+ numberOfLines: 1,
192
+ style: [computedTierLabelStyle, tierLabelStyle],
193
+ children: tierLabel
194
+ }), showChevron ? /*#__PURE__*/_jsx(IconChevronright, {
195
+ width: iconSize,
196
+ height: iconSize,
197
+ fill: iconColor,
198
+ color: iconColor
199
+ }) : null]
200
+ });
201
+ return /*#__PURE__*/_jsxs(Pressable, {
202
+ accessibilityRole: "progressbar",
203
+ accessibilityLabel: defaultAccessibilityLabel,
204
+ accessibilityValue: {
205
+ min: 0,
206
+ max: 100,
207
+ now: normalizedValue
208
+ },
209
+ disabled: !onPress,
210
+ onLayout: handleLayout,
211
+ onPress: onPress,
212
+ style: [containerStyle, style],
213
+ ...rest,
214
+ children: [/*#__PURE__*/_jsx(View, {
215
+ pointerEvents: "none",
216
+ style: [computedRingStyle, ringStyle],
217
+ children: dots.map((dot, index) => /*#__PURE__*/_jsx(View, {
218
+ style: [dotOuterStyle, {
219
+ left: dot.left,
220
+ top: dot.top
221
+ }],
222
+ children: /*#__PURE__*/_jsx(View, {
223
+ style: [dotInnerStyle, {
224
+ backgroundColor: dot.isActive ? progressDotColor : trackDotColor
225
+ }, dot.isActive ? progressDotStyle : trackDotStyle]
226
+ })
227
+ }, index))
228
+ }), /*#__PURE__*/_jsx(View, {
229
+ style: [computedContentStyle, contentStyle],
230
+ children: children ? cloneChildrenWithModes(children, modes) : /*#__PURE__*/_jsxs(_Fragment, {
231
+ children: [/*#__PURE__*/_jsxs(View, {
232
+ style: [computedScoreTierStyle, scoreTierStyle],
233
+ children: [/*#__PURE__*/_jsx(Text, {
234
+ style: [computedLabelStyle, labelStyle],
235
+ children: label
236
+ }), /*#__PURE__*/_jsx(Text, {
237
+ style: [computedScoreLabelStyle, scoreLabelStyle],
238
+ children: resolvedScoreLabel
239
+ })]
240
+ }), onTierPress ? /*#__PURE__*/_jsx(Pressable, {
241
+ accessibilityRole: "button",
242
+ onPress: onTierPress,
243
+ style: [computedScoreTrendStyle, scoreTrendStyle],
244
+ children: trendContent
245
+ }) : /*#__PURE__*/_jsx(View, {
246
+ style: [computedScoreTrendStyle, scoreTrendStyle],
247
+ children: trendContent
248
+ })]
249
+ })
250
+ })]
251
+ });
252
+ }
253
+ export default CircularProgressBarDoted;
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+
3
+ import React, { useMemo } from 'react';
4
+ import { Text, View } from 'react-native';
5
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
6
+ import { useTokens } from '../../design-tokens/JFSThemeProvider';
7
+ import Icon from '../../icons/Icon';
8
+ import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils';
9
+ import CircularProgressBarDoted from '../CircularProgressBarDoted/CircularProgressBarDoted';
10
+ import Nudge from '../Nudge/Nudge';
11
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
12
+ const toNumber = (value, fallback) => {
13
+ if (typeof value === 'number') {
14
+ return Number.isFinite(value) ? value : fallback;
15
+ }
16
+ if (typeof value === 'string') {
17
+ const parsed = Number(value);
18
+ return Number.isFinite(parsed) ? parsed : fallback;
19
+ }
20
+ return fallback;
21
+ };
22
+ const toFontWeight = (value, fallback) => {
23
+ if (typeof value === 'number') {
24
+ return String(value);
25
+ }
26
+ if (typeof value === 'string') {
27
+ return value;
28
+ }
29
+ return fallback;
30
+ };
31
+ function resolveCircularRatingTokens(modes) {
32
+ const gap = toNumber(getVariableByName('circularRating/gap', modes), 32);
33
+ const padding = toNumber(getVariableByName('circularRating/padding', modes), 10);
34
+ const footerGap = toNumber(getVariableByName('circularRating/footer/gap', modes), 4);
35
+ const footerHeight = toNumber(getVariableByName('circularRating/footer/height', modes), 16);
36
+ const footerTextColor = getVariableByName('circularRating/footer/text/color', modes) || '#0d0d0f';
37
+ const footerTextFontSize = toNumber(getVariableByName('circularRating/footer/text/fontSize', modes), 12);
38
+ const footerTextFontFamily = getVariableByName('circularRating/footer/text/fontFamily', modes) || 'JioType Var';
39
+ const footerTextLineHeight = toNumber(getVariableByName('circularRating/footer/text/lineHeight', modes), 16);
40
+ const footerTextFontWeight = toFontWeight(getVariableByName('circularRating/footer/text/fontWeight', modes), '400');
41
+ return {
42
+ containerStyle: {
43
+ alignItems: 'flex-start',
44
+ gap,
45
+ justifyContent: 'center',
46
+ padding
47
+ },
48
+ ratingStyle: {
49
+ height: 320,
50
+ width: 320
51
+ },
52
+ footerStyle: {
53
+ alignItems: 'center',
54
+ flexDirection: 'row',
55
+ gap: footerGap,
56
+ height: footerHeight,
57
+ justifyContent: 'center',
58
+ width: '100%'
59
+ },
60
+ footerTextStyle: {
61
+ color: footerTextColor,
62
+ fontFamily: footerTextFontFamily,
63
+ fontSize: footerTextFontSize,
64
+ fontWeight: footerTextFontWeight,
65
+ lineHeight: footerTextLineHeight,
66
+ textAlign: 'center'
67
+ },
68
+ footerIconColor: getVariableByName('circularRating/footer/icon/color', modes) || '#1a1c1f',
69
+ footerIconSize: toNumber(getVariableByName('circularRating/footer/icon/size', modes), 16)
70
+ };
71
+ }
72
+ function CircularRating({
73
+ value = 72,
74
+ dotCount = 24,
75
+ label = 'Rating',
76
+ tierLabel = 'Doing great',
77
+ footerText = 'Updated on 1 March',
78
+ showFooterIcon = true,
79
+ showNudge = true,
80
+ nudgeBody = 'Split this transaction into installments',
81
+ nudgeButtonLabel = 'Button',
82
+ onPressNudgeButton,
83
+ onTierPress,
84
+ footerSlot,
85
+ nudgeSlot,
86
+ modes: propModes = EMPTY_MODES,
87
+ style,
88
+ ratingStyle,
89
+ footerStyle,
90
+ footerTextStyle,
91
+ nudgeStyle,
92
+ accessibilityLabel,
93
+ ...rest
94
+ }) {
95
+ const {
96
+ modes: globalModes
97
+ } = useTokens();
98
+ const modes = useMemo(() => globalModes === EMPTY_MODES && propModes === EMPTY_MODES ? EMPTY_MODES : {
99
+ ...globalModes,
100
+ ...propModes
101
+ }, [globalModes, propModes]);
102
+ const tokens = useMemo(() => resolveCircularRatingTokens(modes), [modes]);
103
+ const processedFooterSlot = useMemo(() => {
104
+ if (!footerSlot) return null;
105
+ const processed = cloneChildrenWithModes(React.Children.toArray(footerSlot), modes);
106
+ return processed.length === 1 ? processed[0] : processed;
107
+ }, [footerSlot, modes]);
108
+ const processedNudgeSlot = useMemo(() => {
109
+ if (!nudgeSlot) return null;
110
+ const processed = cloneChildrenWithModes(React.Children.toArray(nudgeSlot), modes);
111
+ return processed.length === 1 ? processed[0] : processed;
112
+ }, [nudgeSlot, modes]);
113
+ const defaultAccessibilityLabel = accessibilityLabel ?? `${label}. ${Math.round(value)} out of 100. ${tierLabel}. ${footerText}`;
114
+ return /*#__PURE__*/_jsxs(View, {
115
+ accessibilityLabel: defaultAccessibilityLabel,
116
+ style: [tokens.containerStyle, style],
117
+ ...rest,
118
+ children: [/*#__PURE__*/_jsx(View, {
119
+ style: [tokens.ratingStyle, ratingStyle],
120
+ children: /*#__PURE__*/_jsx(CircularProgressBarDoted, {
121
+ value: value,
122
+ dotCount: dotCount,
123
+ label: label,
124
+ tierLabel: tierLabel,
125
+ onTierPress: onTierPress,
126
+ modes: modes
127
+ })
128
+ }), /*#__PURE__*/_jsx(View, {
129
+ style: [tokens.footerStyle, footerStyle],
130
+ children: processedFooterSlot || /*#__PURE__*/_jsxs(_Fragment, {
131
+ children: [/*#__PURE__*/_jsx(Text, {
132
+ numberOfLines: 1,
133
+ style: [tokens.footerTextStyle, footerTextStyle],
134
+ children: footerText
135
+ }), showFooterIcon ? /*#__PURE__*/_jsx(Icon, {
136
+ name: "ic_info",
137
+ size: tokens.footerIconSize,
138
+ color: tokens.footerIconColor,
139
+ accessibilityElementsHidden: true,
140
+ importantForAccessibility: "no"
141
+ }) : null]
142
+ })
143
+ }), showNudge ? processedNudgeSlot || /*#__PURE__*/_jsx(Nudge, {
144
+ type: "inline-compact",
145
+ body: nudgeBody,
146
+ buttonLabel: nudgeButtonLabel,
147
+ onPressButton: onPressNudgeButton,
148
+ modes: modes,
149
+ style: [{
150
+ width: 312
151
+ }, nudgeStyle]
152
+ }) : null]
153
+ });
154
+ }
155
+ export default /*#__PURE__*/React.memo(CircularRating);