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,67 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
10
+ var _reactUtils = require("../../utils/react-utils");
11
+ var _CheckboxItem = _interopRequireDefault(require("../CheckboxItem/CheckboxItem"));
12
+ var _jsxRuntime = require("react/jsx-runtime");
13
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
+ /**
15
+ * CheckboxGroup composes a vertical stack of `CheckboxItem`s. Spacing and
16
+ * padding are driven by the `checkboxGroup/*` design tokens so groups stay
17
+ * visually consistent across screens.
18
+ *
19
+ * The `modes` prop is forwarded recursively to all children — including
20
+ * `CheckboxItem`s and any element rendered inside their `endSlot`.
21
+ *
22
+ * @component
23
+ * @param {CheckboxGroupProps} props
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * <CheckboxGroup modes={{ 'Color Mode': 'Light' }}>
28
+ * <CheckboxItem label="Fixed deposit • 0245" />
29
+ * <CheckboxItem label="Recurring deposit • 1182" />
30
+ * <CheckboxItem label="Mutual fund • Equity" />
31
+ * </CheckboxGroup>
32
+ * ```
33
+ */
34
+ function CheckboxGroup({
35
+ children,
36
+ modes = _reactUtils.EMPTY_MODES,
37
+ style,
38
+ accessibilityLabel
39
+ }) {
40
+ const gap = (0, _figmaVariablesResolver.getVariableByName)('checkboxGroup/gap', modes) ?? 12;
41
+ const paddingHorizontal = (0, _figmaVariablesResolver.getVariableByName)('checkboxGroup/padding/horizontal', modes) ?? 0;
42
+ const paddingVertical = (0, _figmaVariablesResolver.getVariableByName)('checkboxGroup/padding/vertical', modes) ?? 0;
43
+ const containerStyle = {
44
+ width: '100%',
45
+ flexDirection: 'column',
46
+ alignItems: 'stretch',
47
+ gap,
48
+ paddingHorizontal,
49
+ paddingVertical
50
+ };
51
+ const items = children ? (0, _reactUtils.cloneChildrenWithModes)(children, modes) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
52
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_CheckboxItem.default, {
53
+ modes: modes
54
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_CheckboxItem.default, {
55
+ modes: modes
56
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_CheckboxItem.default, {
57
+ modes: modes
58
+ })]
59
+ });
60
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
61
+ style: [containerStyle, style],
62
+ accessibilityRole: "list",
63
+ accessibilityLabel: accessibilityLabel,
64
+ children: items
65
+ });
66
+ }
67
+ var _default = exports.default = CheckboxGroup;
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
10
+ var _reactUtils = require("../../utils/react-utils");
11
+ var _Checkbox = _interopRequireDefault(require("../Checkbox/Checkbox"));
12
+ var _jsxRuntime = require("react/jsx-runtime");
13
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
15
+ /**
16
+ * CheckboxItem composes a `Checkbox`, a label and an optional `endSlot` into a
17
+ * single horizontal pressable row. Pressing anywhere on the row (outside of the
18
+ * `endSlot`) toggles the checkbox, mirroring the typical native form pattern.
19
+ *
20
+ * Mirrors the Figma "Checkbox Item" component and uses the `checkboxItem/*`
21
+ * design tokens for typography and spacing.
22
+ *
23
+ * @component
24
+ * @param {CheckboxItemProps} props
25
+ *
26
+ * @example
27
+ * ```tsx
28
+ * const [checked, setChecked] = useState(false)
29
+ *
30
+ * <CheckboxItem
31
+ * label="Fixed deposit • 0245"
32
+ * checked={checked}
33
+ * onValueChange={setChecked}
34
+ * modes={{ 'Color Mode': 'Light' }}
35
+ * />
36
+ * ```
37
+ */
38
+ function CheckboxItem({
39
+ checked: controlledChecked,
40
+ defaultChecked = false,
41
+ onValueChange,
42
+ disabled = false,
43
+ label = 'Fixed deposit • 0245',
44
+ endSlot,
45
+ endSlotWidth = 80,
46
+ modes = _reactUtils.EMPTY_MODES,
47
+ style,
48
+ labelStyle,
49
+ accessibilityLabel
50
+ }) {
51
+ const isControlled = controlledChecked !== undefined;
52
+ const [internalChecked, setInternalChecked] = (0, _react.useState)(defaultChecked);
53
+ const isChecked = isControlled ? controlledChecked : internalChecked;
54
+ const handleToggle = (0, _react.useCallback)(() => {
55
+ if (disabled) return;
56
+ const next = !isChecked;
57
+ if (!isControlled) {
58
+ setInternalChecked(next);
59
+ }
60
+ onValueChange?.(next);
61
+ }, [disabled, isChecked, isControlled, onValueChange]);
62
+ const gap = (0, _figmaVariablesResolver.getVariableByName)('checkboxItem/gap', modes) ?? 8;
63
+ const paddingHorizontal = (0, _figmaVariablesResolver.getVariableByName)('checkboxItem/padding/horizontal', modes) ?? 0;
64
+ const paddingVertical = (0, _figmaVariablesResolver.getVariableByName)('checkboxItem/padding/vertical', modes) ?? 0;
65
+ const labelColor = (0, _figmaVariablesResolver.getVariableByName)('checkboxItem/foreground', modes) ?? '#1a1c1f';
66
+ const labelFontFamily = (0, _figmaVariablesResolver.getVariableByName)('checkboxItem/label/fontFamily', modes) ?? 'JioType Var';
67
+ const labelFontSize = (0, _figmaVariablesResolver.getVariableByName)('checkboxItem/label/fontSize', modes) ?? 14;
68
+ const labelLineHeight = (0, _figmaVariablesResolver.getVariableByName)('checkboxItem/label/lineHeight', modes) ?? 19;
69
+ const labelFontWeightRaw = (0, _figmaVariablesResolver.getVariableByName)('checkboxItem/label/fontWeight', modes) ?? 400;
70
+ const labelFontWeight = String(labelFontWeightRaw);
71
+ const containerStyle = {
72
+ flexDirection: 'row',
73
+ alignItems: 'center',
74
+ gap,
75
+ paddingHorizontal,
76
+ paddingVertical,
77
+ width: '100%'
78
+ };
79
+ const resolvedLabelStyle = {
80
+ flex: 1,
81
+ minWidth: 0,
82
+ color: labelColor,
83
+ fontFamily: labelFontFamily,
84
+ fontSize: labelFontSize,
85
+ lineHeight: labelLineHeight,
86
+ fontWeight: labelFontWeight
87
+ };
88
+ const a11yLabel = accessibilityLabel ?? (typeof label === 'string' ? label : undefined);
89
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
90
+ style: [containerStyle, style],
91
+ onPress: handleToggle,
92
+ disabled: disabled,
93
+ accessibilityRole: "checkbox",
94
+ accessibilityState: {
95
+ checked: isChecked,
96
+ disabled
97
+ },
98
+ accessibilityLabel: a11yLabel,
99
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Checkbox.default, {
100
+ checked: isChecked,
101
+ disabled: disabled,
102
+ onValueChange: handleToggle,
103
+ modes: modes,
104
+ accessibilityLabel: a11yLabel
105
+ }), label != null && label !== false ? typeof label === 'string' || typeof label === 'number' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
106
+ style: [resolvedLabelStyle, labelStyle],
107
+ selectable: false,
108
+ children: label
109
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
110
+ style: {
111
+ flex: 1,
112
+ minWidth: 0
113
+ },
114
+ children: label
115
+ }) : null, endSlot ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
116
+ style: {
117
+ width: endSlotWidth,
118
+ flexShrink: 0,
119
+ alignItems: 'stretch'
120
+ },
121
+ children: (0, _reactUtils.cloneChildrenWithModes)(endSlot, modes)
122
+ }) : null]
123
+ });
124
+ }
125
+ var _default = exports.default = CheckboxItem;
@@ -43,11 +43,13 @@ function CircularProgressBar({
43
43
  value = 70,
44
44
  state = 'Inactive',
45
45
  valueLabel,
46
+ supportText,
46
47
  modes: propModes = _reactUtils.EMPTY_MODES,
47
48
  style,
48
49
  trackStyle,
49
50
  progressStyle,
50
51
  valueStyle,
52
+ supportTextStyle,
51
53
  accessibilityLabel,
52
54
  ...rest
53
55
  }) {
@@ -58,6 +60,17 @@ function CircularProgressBar({
58
60
  ...globalModes,
59
61
  ...propModes
60
62
  };
63
+ // The Figma `circularProgressBar/track/color` variable aliases to the same
64
+ // chain as `progress/color`, so user-selected Brand modes collapse the
65
+ // track and progress to a single hue. The Figma source of truth always
66
+ // renders the track as a neutral gray, so we force Neutral/Medium when
67
+ // resolving the track color while keeping the user modes for everything
68
+ // else.
69
+ const trackModes = {
70
+ ...modes,
71
+ 'AppearanceBrand': 'Neutral',
72
+ 'Emphasis': 'Medium'
73
+ };
61
74
  const isActive = state === true || state === 'Active';
62
75
  const normalizedValue = clamp(value, 0, 100);
63
76
  const size = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBar/size', modes), 60);
@@ -65,15 +78,18 @@ function CircularProgressBar({
65
78
  const radius = Math.max(0, (size - strokeWidth) / 2);
66
79
  const center = size / 2;
67
80
  const circumference = 2 * Math.PI * radius;
68
- const trackColor = getStrokeColor(trackStyle, (0, _figmaVariablesResolver.getVariableByName)('circularProgressBar/track/color', modes) || '#ebebed');
81
+ const trackColor = getStrokeColor(trackStyle, (0, _figmaVariablesResolver.getVariableByName)('circularProgressBar/track/color', trackModes) || '#ebebed');
69
82
  const progressColor = getStrokeColor(progressStyle, (0, _figmaVariablesResolver.getVariableByName)('circularProgressBar/progress/color', modes) || '#25ab21');
70
83
  const iconColor = (0, _figmaVariablesResolver.getVariableByName)('circularProgressBar/icon/color', modes) || '#666666';
71
84
  const iconSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBar/icon/size', modes), 24);
72
85
  const foreground = (0, _figmaVariablesResolver.getVariableByName)('circularProgressBar/foreground', modes) || '#0d0d0f';
73
- const fontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBar/fontSize', modes), 18);
86
+ const fontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBar/value/fontSize', modes), 18);
74
87
  const fontFamily = (0, _figmaVariablesResolver.getVariableByName)('circularProgressBar/fontFamily', modes) || 'JioType Var';
75
- const lineHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBar/lineHeight', modes), 21);
76
- const fontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('circularProgressBar/fontWeight', modes), '700');
88
+ const lineHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBar/value/lineHeight', modes), 21);
89
+ const fontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('circularProgressBar/value/fontWeight', modes), '700');
90
+ const supportFontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBar/supportText/fontSize', modes), 11);
91
+ const supportLineHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('circularProgressBar/supportText/lineHeight', modes), 13);
92
+ const supportFontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('circularProgressBar/supportText/fontWeight', modes), '500');
77
93
  const computedContainerStyle = {
78
94
  alignItems: 'center',
79
95
  height: size,
@@ -81,13 +97,34 @@ function CircularProgressBar({
81
97
  position: 'relative',
82
98
  width: size
83
99
  };
100
+
101
+ // The text stack (support text + value) is centered inside the ring using
102
+ // an absolutely-positioned column. Keeping the wrapper absolute (rather
103
+ // than the individual texts, as in earlier versions) lets multi-line stacks
104
+ // render correctly without sub-pixel misalignment.
105
+ const textStackStyle = {
106
+ alignItems: 'center',
107
+ justifyContent: 'center',
108
+ left: 0,
109
+ position: 'absolute',
110
+ right: 0,
111
+ top: 0,
112
+ bottom: 0
113
+ };
84
114
  const computedValueStyle = {
85
115
  color: foreground,
86
116
  fontFamily,
87
117
  fontSize,
88
118
  fontWeight,
89
119
  lineHeight,
90
- position: 'absolute',
120
+ textAlign: 'center'
121
+ };
122
+ const computedSupportTextStyle = {
123
+ color: foreground,
124
+ fontFamily,
125
+ fontSize: supportFontSize,
126
+ fontWeight: supportFontWeight,
127
+ lineHeight: supportLineHeight,
91
128
  textAlign: 'center'
92
129
  };
93
130
  const iconStyle = {
@@ -96,7 +133,8 @@ function CircularProgressBar({
96
133
  top: (size - iconSize) / 2
97
134
  };
98
135
  const displayValue = valueLabel ?? String(Math.round(normalizedValue));
99
- const defaultAccessibilityLabel = accessibilityLabel ?? (isActive ? `${displayValue} out of 100` : 'Inactive progress');
136
+ const hasSupportText = typeof supportText === 'string' && supportText.length > 0;
137
+ const defaultAccessibilityLabel = accessibilityLabel ?? (isActive ? hasSupportText ? `${supportText}, ${displayValue} out of 100` : `${displayValue} out of 100` : 'Inactive progress');
100
138
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
101
139
  accessibilityRole: "progressbar",
102
140
  accessibilityLabel: defaultAccessibilityLabel,
@@ -132,9 +170,18 @@ function CircularProgressBar({
132
170
  originX: center,
133
171
  originY: center
134
172
  }) : null]
135
- }), isActive ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
136
- style: [computedValueStyle, valueStyle],
137
- children: displayValue
173
+ }), isActive ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
174
+ style: textStackStyle,
175
+ pointerEvents: "none",
176
+ children: [hasSupportText ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
177
+ style: [computedSupportTextStyle, supportTextStyle],
178
+ numberOfLines: 1,
179
+ children: supportText
180
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
181
+ style: [computedValueStyle, valueStyle],
182
+ numberOfLines: 1,
183
+ children: displayValue
184
+ })]
138
185
  }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_IconMinus.IconMinus, {
139
186
  width: iconSize,
140
187
  height: iconSize,
@@ -0,0 +1,272 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var _reactNativeSvg = _interopRequireWildcard(require("react-native-svg"));
10
+ var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
11
+ var _JFSThemeProvider = require("../../design-tokens/JFSThemeProvider");
12
+ var _reactUtils = require("../../utils/react-utils");
13
+ var _MetricLegendItem = _interopRequireDefault(require("../MetricLegendItem/MetricLegendItem"));
14
+ var _jsxRuntime = require("react/jsx-runtime");
15
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
16
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
+ /**
18
+ * One entry in the {@link CoverageBarComparisonProps.bars} array.
19
+ *
20
+ * Each entry carries **both** the bar's data and its legend label, so the
21
+ * number of bars is intrinsically equal to the number of legend items.
22
+ * There is no separate `legends` prop — that is by design.
23
+ */
24
+
25
+ /**
26
+ * Default per-index `Emphasis / DataViz` modes applied when the caller does
27
+ * not provide its own override. Ascends Low → Medium → High so the natural
28
+ * "Current vs Recommended" two-bar story matches the Figma reference (left
29
+ * = lighter / Low, right = darker / High). Cycles for >3 bars.
30
+ */
31
+ const DEFAULT_EMPHASIS_CYCLE = ['Low', 'Medium', 'High'];
32
+ function defaultEmphasisFor(index, total) {
33
+ if (total <= 1) {
34
+ return 'High';
35
+ }
36
+ if (total === 2) {
37
+ return index === 0 ? 'Low' : 'High';
38
+ }
39
+ return DEFAULT_EMPHASIS_CYCLE[index % DEFAULT_EMPHASIS_CYCLE.length];
40
+ }
41
+ const DEFAULT_BARS = [{
42
+ value: 40,
43
+ label: '₹1L (40%)',
44
+ legend: 'Current coverage'
45
+ }, {
46
+ value: 100,
47
+ label: '₹2.5L (100%)',
48
+ legend: 'Recommended coverage'
49
+ }];
50
+ const toNumber = (value, fallback) => {
51
+ if (typeof value === 'number') {
52
+ return Number.isFinite(value) ? value : fallback;
53
+ }
54
+ if (typeof value === 'string') {
55
+ const parsed = Number(value);
56
+ return Number.isFinite(parsed) ? parsed : fallback;
57
+ }
58
+ return fallback;
59
+ };
60
+ const toFontWeight = (value, fallback) => {
61
+ if (typeof value === 'number') {
62
+ return String(value);
63
+ }
64
+ if (typeof value === 'string') {
65
+ return value;
66
+ }
67
+ return fallback;
68
+ };
69
+ /**
70
+ * Bar shape rendered with `react-native-svg`. The wrapper measures its width
71
+ * via `onLayout` so the SVG can use concrete dimensions (RN SVG does not
72
+ * resolve percentage shape attributes when the parent SVG itself has a
73
+ * percentage `width`).
74
+ */
75
+ function BarShape({
76
+ height,
77
+ color,
78
+ radius
79
+ }) {
80
+ const [width, setWidth] = _react.default.useState(0);
81
+ const handleLayout = _react.default.useCallback(event => {
82
+ const next = event.nativeEvent.layout.width;
83
+ setWidth(prev => prev === next ? prev : next);
84
+ }, []);
85
+ if (height <= 0) {
86
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
87
+ onLayout: handleLayout,
88
+ style: {
89
+ width: '100%',
90
+ height: 0
91
+ }
92
+ });
93
+ }
94
+ const safeRadius = Math.max(0, Math.min(radius, width / 2, height / 2));
95
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
96
+ onLayout: handleLayout,
97
+ style: {
98
+ width: '100%',
99
+ height,
100
+ minWidth: 1
101
+ },
102
+ children: width > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.default, {
103
+ width: width,
104
+ height: height,
105
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Rect, {
106
+ x: 0,
107
+ y: 0,
108
+ width: width,
109
+ height: height,
110
+ rx: safeRadius,
111
+ ry: safeRadius,
112
+ fill: color
113
+ })
114
+ }) : null
115
+ });
116
+ }
117
+
118
+ /**
119
+ * `CoverageBarComparison` renders a small vertical-bar chart that compares
120
+ * 2+ values side by side, with a legend row directly below where each item
121
+ * is intrinsically tied to one bar.
122
+ *
123
+ * Cohesiveness guarantees:
124
+ * - The legend row is **derived** from the same `bars` prop, so the count
125
+ * and order can never desynchronise from the chart.
126
+ * - Each bar's color, its tokenized `Emphasis / DataViz` mode and its
127
+ * legend indicator dot are the same value.
128
+ *
129
+ * Bars are drawn with `react-native-svg` (`<Rect>` with `rx`), and the
130
+ * fonts/spacing/colors are sourced from the Figma `valueBar/*` and
131
+ * `coverageBarComparison/*` tokens.
132
+ *
133
+ * @component
134
+ */
135
+ function CoverageBarComparison({
136
+ bars = DEFAULT_BARS,
137
+ max,
138
+ height = 100,
139
+ legendGap = 12,
140
+ modes: propModes = _reactUtils.EMPTY_MODES,
141
+ style,
142
+ chartStyle,
143
+ legendStyle,
144
+ labelStyle,
145
+ accessibilityLabel
146
+ }) {
147
+ const {
148
+ modes: globalModes
149
+ } = (0, _JFSThemeProvider.useTokens)();
150
+ const modes = _react.default.useMemo(() => ({
151
+ ...globalModes,
152
+ ...propModes
153
+ }), [globalModes, propModes]);
154
+ const wrapGap = toNumber((0, _figmaVariablesResolver.getVariableByName)('coverageBarComparison/wrap/gap', modes), 6);
155
+ const valueBarGap = toNumber((0, _figmaVariablesResolver.getVariableByName)('valueBar/gap', modes), 4);
156
+ const barRadius = toNumber((0, _figmaVariablesResolver.getVariableByName)('valueBar/bar/radius', modes), 10);
157
+ const fontFamily = (0, _figmaVariablesResolver.getVariableByName)('valueBar/fontFamily', modes) ?? 'JioType Var';
158
+ const fontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('valueBar/fontSize', modes), 12);
159
+ const lineHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('valueBar/lineHeight', modes), 16);
160
+ const fontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('valueBar/fontWeight', modes), '700');
161
+ const foreground = (0, _figmaVariablesResolver.getVariableByName)('valueBar/foreground', modes) ?? '#000000';
162
+ const labelHeight = lineHeight;
163
+ const barAreaHeight = Math.max(0, height - labelHeight - valueBarGap);
164
+ const total = bars.length;
165
+ const computedMax = max ?? bars.reduce((acc, bar) => Math.max(acc, bar.value), 0);
166
+ const safeMax = computedMax > 0 ? computedMax : 1;
167
+ const resolvedBars = _react.default.useMemo(() => bars.map((bar, index) => {
168
+ const barModes = {
169
+ ...modes,
170
+ 'Emphasis / DataViz': defaultEmphasisFor(index, total),
171
+ ...(bar.modes || {})
172
+ };
173
+ const ratio = Math.max(0, Math.min(1, bar.value / safeMax));
174
+ const tokenColor = (0, _figmaVariablesResolver.getVariableByName)('valueBar/bar/background', barModes) ?? '#c9b7ff';
175
+ const bgColor = bar.color ?? tokenColor;
176
+ return {
177
+ original: bar,
178
+ index,
179
+ barModes,
180
+ ratio,
181
+ bgColor
182
+ };
183
+ }), [bars, modes, safeMax, total]);
184
+ const computedLabelStyle = {
185
+ color: foreground,
186
+ fontFamily,
187
+ fontSize,
188
+ lineHeight,
189
+ fontWeight,
190
+ textAlign: 'center'
191
+ };
192
+ const defaultAccessibilityLabel = accessibilityLabel ?? `Comparison of ${total} bar${total === 1 ? '' : 's'}: ` + bars.map((bar, i) => {
193
+ const legend = typeof bar.legend === 'string' ? bar.legend : `bar ${i + 1}`;
194
+ return `${legend} ${bar.value}`;
195
+ }).join(', ');
196
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
197
+ accessibilityLabel: defaultAccessibilityLabel,
198
+ style: [{
199
+ width: '100%'
200
+ }, style],
201
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
202
+ accessibilityRole: "image",
203
+ style: [{
204
+ flexDirection: 'row',
205
+ alignItems: 'flex-end',
206
+ height,
207
+ gap: wrapGap,
208
+ width: '100%'
209
+ }, chartStyle],
210
+ children: resolvedBars.map(({
211
+ original,
212
+ index,
213
+ ratio,
214
+ bgColor
215
+ }) => {
216
+ const barHeightPx = Math.max(0, barAreaHeight * ratio);
217
+ const valueBarTotalHeight = labelHeight + valueBarGap + barHeightPx;
218
+ const hasLabel = original.label !== undefined && original.label !== null && original.label !== false;
219
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
220
+ accessibilityLabel: original.accessibilityLabel,
221
+ style: {
222
+ flex: 1,
223
+ flexDirection: 'column',
224
+ alignItems: 'stretch',
225
+ justifyContent: 'flex-end',
226
+ height: valueBarTotalHeight,
227
+ gap: valueBarGap,
228
+ minWidth: 1
229
+ },
230
+ children: [hasLabel ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
231
+ numberOfLines: 1,
232
+ style: [computedLabelStyle, labelStyle],
233
+ children: original.label
234
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(BarShape, {
235
+ height: barHeightPx,
236
+ color: bgColor,
237
+ radius: barRadius
238
+ })]
239
+ }, original.key ?? `bar-${index}`);
240
+ })
241
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
242
+ style: [{
243
+ marginTop: legendGap,
244
+ flexDirection: 'row',
245
+ alignItems: 'center',
246
+ justifyContent: 'space-between',
247
+ width: '100%'
248
+ }, legendStyle],
249
+ children: resolvedBars.map(({
250
+ original,
251
+ index,
252
+ barModes,
253
+ bgColor
254
+ }) => {
255
+ const indicatorOverride = original.color ? bgColor : undefined;
256
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_MetricLegendItem.default, {
257
+ label: original.legend,
258
+ value: original.legendValue,
259
+ modes: barModes,
260
+ ...(indicatorOverride !== undefined ? {
261
+ indicatorColor: indicatorOverride
262
+ } : {}),
263
+ style: {
264
+ flex: 1,
265
+ minWidth: 0
266
+ }
267
+ }, original.key ?? `legend-${index}`);
268
+ })
269
+ })]
270
+ });
271
+ }
272
+ var _default = exports.default = CoverageBarComparison;