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,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);
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+
3
+ import React from 'react';
4
+ import { StyleSheet, View, Text } from 'react-native';
5
+ import Svg, { Path } from 'react-native-svg';
6
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
7
+ import { useTokens } from '../../design-tokens/JFSThemeProvider';
8
+ import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils';
9
+ import SupportText from '../SupportText/SupportText';
10
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
11
+ const clamp = (value, min, max) => {
12
+ if (max <= min) {
13
+ return 0;
14
+ }
15
+ return Math.min(1, Math.max(0, (value - min) / (max - min)));
16
+ };
17
+ const toNumber = (value, fallback) => {
18
+ if (typeof value === 'number') {
19
+ return Number.isFinite(value) ? value : fallback;
20
+ }
21
+ if (typeof value === 'string') {
22
+ const parsed = Number(value);
23
+ return Number.isFinite(parsed) ? parsed : fallback;
24
+ }
25
+ return fallback;
26
+ };
27
+ const toFontWeight = (value, fallback) => {
28
+ if (typeof value === 'number') {
29
+ return String(value);
30
+ }
31
+ if (typeof value === 'string') {
32
+ return value;
33
+ }
34
+ return fallback;
35
+ };
36
+ const getStrokeColor = (style, fallback) => {
37
+ const flattened = StyleSheet.flatten(style);
38
+ return typeof flattened.backgroundColor === 'string' ? flattened.backgroundColor : fallback;
39
+ };
40
+ function Gauge({
41
+ value = 84,
42
+ min = 0,
43
+ max = 100,
44
+ valueLabel,
45
+ title = 'Your score is based on strong data',
46
+ caption = 'Add more details for even better accuracy',
47
+ supportText = 'Support Text',
48
+ supportTextStatus = 'Success',
49
+ showTitle = true,
50
+ showCaption = true,
51
+ showSupportText = true,
52
+ modes: propModes = EMPTY_MODES,
53
+ children,
54
+ style,
55
+ arcStyle,
56
+ readoutStyle,
57
+ titleStyle,
58
+ valueStyle,
59
+ captionStyle,
60
+ trackStyle,
61
+ progressStyle,
62
+ accessibilityLabel,
63
+ ...rest
64
+ }) {
65
+ const {
66
+ modes: globalModes
67
+ } = useTokens();
68
+ const modes = {
69
+ ...globalModes,
70
+ ...propModes
71
+ };
72
+ const supportTextModes = {
73
+ ...modes,
74
+ Status: supportTextStatus
75
+ };
76
+ const gap = toNumber(getVariableByName('gauge/gap', modes), 30);
77
+ const padding = toNumber(getVariableByName('gauge/padding', modes), 16);
78
+ const width = toNumber(getVariableByName('gauge/width', modes), 299);
79
+ const arcWidth = toNumber(getVariableByName('gauge/arc/width', modes), 267);
80
+ const arcHeight = arcWidth * (186 / 328);
81
+ const trackSize = toNumber(getVariableByName('gauge/track/size', modes), 244);
82
+ const trackInnerRadius = toNumber(getVariableByName('gauge/track/radius', modes), 99);
83
+ const progressInnerRadius = toNumber(getVariableByName('gauge/progress/radius', modes), 99);
84
+ const innerRadius = Math.min(trackInnerRadius, progressInnerRadius);
85
+ const strokeWidth = Math.max(1, trackSize / 2 - innerRadius);
86
+ const radius = innerRadius + strokeWidth / 2;
87
+ const centerX = arcWidth / 2;
88
+ const centerY = Math.min(arcHeight - strokeWidth / 2, radius + strokeWidth / 2);
89
+ const startX = centerX - radius;
90
+ const endX = centerX + radius;
91
+ const arcPath = `M ${startX} ${centerY} A ${radius} ${radius} 0 0 1 ${endX} ${centerY}`;
92
+ const arcLength = Math.PI * radius;
93
+ const progress = clamp(value, min, max);
94
+ const titleColor = getVariableByName('gauge/title/color', modes) || '#0c0d10';
95
+ const titleFontSize = toNumber(getVariableByName('gauge/title/fontSize', modes), 23);
96
+ const titleLineHeight = toNumber(getVariableByName('gauge/title/lineHeight', modes), 23);
97
+ const titleFontFamily = getVariableByName('gauge/title/fontFamily', modes) || 'JioType Var';
98
+ const titleFontWeight = toFontWeight(getVariableByName('gauge/title/fontWeight', modes), '900');
99
+ const titleHeight = toNumber(getVariableByName('gauge/title/height', modes), 46);
100
+ const readoutGap = toNumber(getVariableByName('gauge/readout/gap', modes), 8);
101
+ const readoutPadding = toNumber(getVariableByName('gauge/readout/padding', modes), 8);
102
+ const valueColor = getVariableByName('gauge/readout/value/color', modes) || '#0c0d10';
103
+ const valueFontSize = toNumber(getVariableByName('gauge/readout/value/fontSize', modes), 36);
104
+ const valueLineHeight = toNumber(getVariableByName('gauge/readout/value/lineHeight', modes), 36);
105
+ const valueFontFamily = getVariableByName('gauge/readout/value/fontFamily', modes) || 'JioType Var';
106
+ const valueFontWeight = toFontWeight(getVariableByName('gauge/readout/value/fontWeight', modes), '800');
107
+ const captionColor = getVariableByName('gauge/caption/color', modes) || '#0c0d10';
108
+ const captionFontSize = toNumber(getVariableByName('gauge/caption/fontSize', modes), 14);
109
+ const captionLineHeight = toNumber(getVariableByName('gauge/caption/lineHeight', modes), 18);
110
+ const captionFontFamily = getVariableByName('gauge/caption/fontFamily', modes) || 'JioType Var';
111
+ const captionFontWeight = toFontWeight(getVariableByName('gauge/caption/fontWeight', modes), '500');
112
+ const trackColor = getStrokeColor(trackStyle, getVariableByName('gauge/track/color', modes) || '#f5f5f6');
113
+ const progressColor = getStrokeColor(progressStyle, getVariableByName('gauge/progress/color', modes) || '#25ab21');
114
+ const containerStyle = {
115
+ alignItems: 'center',
116
+ gap,
117
+ padding,
118
+ width
119
+ };
120
+ const computedTitleStyle = {
121
+ color: titleColor,
122
+ fontFamily: titleFontFamily,
123
+ fontSize: titleFontSize,
124
+ fontWeight: titleFontWeight,
125
+ lineHeight: titleLineHeight,
126
+ minHeight: titleHeight,
127
+ textAlign: 'center',
128
+ width: '100%'
129
+ };
130
+ const computedArcStyle = {
131
+ height: arcHeight,
132
+ overflow: 'hidden',
133
+ position: 'relative',
134
+ width: '100%'
135
+ };
136
+ const computedReadoutStyle = {
137
+ alignItems: 'center',
138
+ gap: readoutGap,
139
+ left: 0,
140
+ padding: readoutPadding,
141
+ position: 'absolute',
142
+ right: 0,
143
+ top: arcHeight * 0.42
144
+ };
145
+ const computedValueStyle = {
146
+ color: valueColor,
147
+ fontFamily: valueFontFamily,
148
+ fontSize: valueFontSize,
149
+ fontWeight: valueFontWeight,
150
+ lineHeight: valueLineHeight,
151
+ textAlign: 'center'
152
+ };
153
+ const computedCaptionStyle = {
154
+ color: captionColor,
155
+ fontFamily: captionFontFamily,
156
+ fontSize: captionFontSize,
157
+ fontWeight: captionFontWeight,
158
+ lineHeight: captionLineHeight,
159
+ textAlign: 'center',
160
+ width: '100%'
161
+ };
162
+ const defaultValueLabel = valueLabel ?? String(Math.round(value));
163
+ const defaultAccessibilityLabel = accessibilityLabel ?? `${title}. ${defaultValueLabel} out of ${max}. ${supportText}. ${caption}`;
164
+ return /*#__PURE__*/_jsxs(View, {
165
+ accessibilityRole: "progressbar",
166
+ accessibilityLabel: defaultAccessibilityLabel,
167
+ accessibilityValue: {
168
+ min,
169
+ max,
170
+ now: value
171
+ },
172
+ style: [containerStyle, style],
173
+ ...rest,
174
+ children: [showTitle ? /*#__PURE__*/_jsx(Text, {
175
+ style: [computedTitleStyle, titleStyle],
176
+ children: title
177
+ }) : null, /*#__PURE__*/_jsxs(View, {
178
+ style: [computedArcStyle, arcStyle],
179
+ children: [/*#__PURE__*/_jsxs(Svg, {
180
+ width: "100%",
181
+ height: arcHeight,
182
+ viewBox: `0 0 ${arcWidth} ${arcHeight}`,
183
+ children: [/*#__PURE__*/_jsx(Path, {
184
+ d: arcPath,
185
+ stroke: trackColor,
186
+ strokeWidth: strokeWidth,
187
+ strokeLinecap: "butt",
188
+ fill: "none"
189
+ }), /*#__PURE__*/_jsx(Path, {
190
+ d: arcPath,
191
+ stroke: progressColor,
192
+ strokeWidth: strokeWidth,
193
+ strokeLinecap: "butt",
194
+ fill: "none",
195
+ strokeDasharray: `${arcLength} ${arcLength}`,
196
+ strokeDashoffset: arcLength * (1 - progress)
197
+ })]
198
+ }), /*#__PURE__*/_jsx(View, {
199
+ style: [computedReadoutStyle, readoutStyle],
200
+ children: children ? cloneChildrenWithModes(children, modes) : /*#__PURE__*/_jsxs(_Fragment, {
201
+ children: [/*#__PURE__*/_jsx(Text, {
202
+ style: [computedValueStyle, valueStyle],
203
+ children: defaultValueLabel
204
+ }), showSupportText ? /*#__PURE__*/_jsx(SupportText, {
205
+ label: supportText,
206
+ status: supportTextStatus,
207
+ modes: supportTextModes
208
+ }) : null]
209
+ })
210
+ })]
211
+ }), showCaption ? /*#__PURE__*/_jsx(Text, {
212
+ style: [computedCaptionStyle, captionStyle],
213
+ children: caption
214
+ }) : null]
215
+ });
216
+ }
217
+ export default Gauge;
@@ -47,7 +47,9 @@ function ListGroup({
47
47
  }) {
48
48
  // Resolve container tokens
49
49
  const backgroundColor = getVariableByName('listGroup/background', modes) || 'rgba(255,255,255,0)';
50
- const borderColor = getVariableByName('listGroup/border/color', modes) || 'rgba(255,255,255,0)';
50
+ // The current exported token aliases a missing Figma variable. Keep the
51
+ // transparent fallback without logging the missing alias on every render.
52
+ const borderColor = 'rgba(255,255,255,0)';
51
53
  const borderWidth = getVariableByName('listGroup/borderWidth', modes) || 0;
52
54
  const gap = getVariableByName('listGroup/gap', modes) || 12;
53
55
 
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+
3
+ import React from 'react';
4
+ import { View, StyleSheet, Platform } from 'react-native';
5
+ import { BlurView } from '@react-native-community/blur';
6
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
+ const DEFAULT_FALLBACK_DARK = '#1414174a';
8
+ const DEFAULT_FALLBACK_LIGHT = '#ffffff66';
9
+
10
+ /**
11
+ * Glass / frosted surface for native (iOS + Android).
12
+ *
13
+ * Why this lives in its own platform-split file:
14
+ * - `@react-native-community/blur` is a native-only module. Importing it on
15
+ * web throws because the JS shim references native components that aren't
16
+ * registered there. By using Metro's platform-extension resolution
17
+ * (`GlassFill.tsx` for native, `GlassFill.web.tsx` for web), we keep the
18
+ * web bundle free of any native-only imports.
19
+ * - Centralizes the `intensity` (0–100) -> `blurAmount` (0–32) mapping so
20
+ * callers can keep the Figma token semantics they already know.
21
+ *
22
+ * On iOS this is a real `UIVisualEffectView` (true OS-level live blur).
23
+ * On Android this uses the community blur view (RealtimeBlurView). On devices
24
+ * where realtime blur is unavailable, `reducedTransparencyFallbackColor` (and
25
+ * the explicit `overlayColor`) ensure the surface still renders as a
26
+ * translucent tinted scrim instead of disappearing.
27
+ */
28
+ function GlassFill({
29
+ tint = 'dark',
30
+ intensity = 50,
31
+ overlayColor,
32
+ style
33
+ }) {
34
+ const blurType = tint === 'light' ? 'light' : 'dark';
35
+ const blurAmount = Math.max(0, Math.min(32, Math.round(intensity * 0.32)));
36
+ const fallbackColor = overlayColor ?? (tint === 'light' ? DEFAULT_FALLBACK_LIGHT : DEFAULT_FALLBACK_DARK);
37
+ return /*#__PURE__*/_jsxs(View, {
38
+ style: [StyleSheet.absoluteFill, style],
39
+ pointerEvents: "none",
40
+ children: [/*#__PURE__*/_jsx(BlurView, {
41
+ style: StyleSheet.absoluteFill,
42
+ blurType: blurType,
43
+ blurAmount: blurAmount,
44
+ reducedTransparencyFallbackColor: fallbackColor
45
+ }), overlayColor != null ? /*#__PURE__*/_jsx(View, {
46
+ style: [StyleSheet.absoluteFill, {
47
+ backgroundColor: overlayColor
48
+ }]
49
+ }) : null, Platform.OS === 'android' ? /*#__PURE__*/_jsx(View, {
50
+ style: [StyleSheet.absoluteFill, {
51
+ backgroundColor: 'rgba(255,255,255,0.03)',
52
+ opacity: 0.6
53
+ }]
54
+ }) : null]
55
+ });
56
+ }
57
+ export default GlassFill;