jfs-components 0.0.72 → 0.0.74

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 (158) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/lib/commonjs/components/AccordionCheckbox/AccordionCheckbox.js +239 -0
  3. package/lib/commonjs/components/AccountCard/AccountCard.js +247 -0
  4. package/lib/commonjs/components/AppBar/AppBar.js +17 -11
  5. package/lib/commonjs/components/BrandChip/BrandChip.js +149 -0
  6. package/lib/commonjs/components/CardBankAccount/CardBankAccount.js +229 -0
  7. package/lib/commonjs/components/CardInsight/CardInsight.js +166 -0
  8. package/lib/commonjs/components/CheckboxGroup/CheckboxGroup.js +67 -0
  9. package/lib/commonjs/components/CheckboxItem/CheckboxItem.js +140 -0
  10. package/lib/commonjs/components/CircularProgressBar/CircularProgressBar.js +56 -9
  11. package/lib/commonjs/components/CoverageBarComparison/CoverageBarComparison.js +272 -0
  12. package/lib/commonjs/components/CoverageRing/CoverageRing.js +141 -0
  13. package/lib/commonjs/components/DonutChart/DonutChart.js +309 -0
  14. package/lib/commonjs/components/DonutChartSummary/DonutChartSummary.js +155 -0
  15. package/lib/commonjs/components/Dropdown/Dropdown.js +214 -0
  16. package/lib/commonjs/components/DropdownInput/DropdownInput.js +542 -0
  17. package/lib/commonjs/components/FormField/FormField.js +328 -178
  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/LottieIntroBlock/LottieIntroBlock.js +150 -0
  21. package/lib/commonjs/components/MetricLegendItem/MetricLegendItem.js +95 -0
  22. package/lib/commonjs/components/MonthlyStatusGrid/MonthlyStatusGrid.js +286 -0
  23. package/lib/commonjs/components/OTP/OTP.js +381 -37
  24. package/lib/commonjs/components/PageHero/PageHero.js +153 -0
  25. package/lib/commonjs/components/PoweredByLabel/PoweredByLabel.js +135 -0
  26. package/lib/commonjs/components/PoweredByLabel/finvu.png +0 -0
  27. package/lib/commonjs/components/ProductOverview/ProductOverview.js +147 -0
  28. package/lib/commonjs/components/RangeTrack/RangeTrack.js +269 -0
  29. package/lib/commonjs/components/SavingsGoalSummary/SavingsGoalSummary.js +181 -0
  30. package/lib/commonjs/components/SegmentedTrack/SegmentedTrack.js +171 -0
  31. package/lib/commonjs/components/StatGroup/StatGroup.js +128 -0
  32. package/lib/commonjs/components/StatItem/StatItem.js +65 -35
  33. package/lib/commonjs/components/StrengthIndicator/StrengthIndicator.js +157 -0
  34. package/lib/commonjs/components/SummaryTile/SummaryTile.js +150 -0
  35. package/lib/commonjs/components/Text/Text.js +9 -2
  36. package/lib/commonjs/components/Tooltip/Tooltip.js +34 -27
  37. package/lib/commonjs/components/index.js +231 -1
  38. package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
  39. package/lib/commonjs/icons/registry.js +1 -1
  40. package/lib/commonjs/utils/index.js +7 -0
  41. package/lib/commonjs/utils/number-utils.js +57 -0
  42. package/lib/module/components/AccordionCheckbox/AccordionCheckbox.js +233 -0
  43. package/lib/module/components/AccountCard/AccountCard.js +241 -0
  44. package/lib/module/components/AppBar/AppBar.js +17 -11
  45. package/lib/module/components/BrandChip/BrandChip.js +143 -0
  46. package/lib/module/components/CardBankAccount/CardBankAccount.js +223 -0
  47. package/lib/module/components/CardInsight/CardInsight.js +161 -0
  48. package/lib/module/components/CheckboxGroup/CheckboxGroup.js +62 -0
  49. package/lib/module/components/CheckboxItem/CheckboxItem.js +134 -0
  50. package/lib/module/components/CircularProgressBar/CircularProgressBar.js +56 -9
  51. package/lib/module/components/CoverageBarComparison/CoverageBarComparison.js +266 -0
  52. package/lib/module/components/CoverageRing/CoverageRing.js +136 -0
  53. package/lib/module/components/DonutChart/DonutChart.js +303 -0
  54. package/lib/module/components/DonutChartSummary/DonutChartSummary.js +150 -0
  55. package/lib/module/components/Dropdown/Dropdown.js +206 -0
  56. package/lib/module/components/DropdownInput/DropdownInput.js +536 -0
  57. package/lib/module/components/FormField/FormField.js +330 -180
  58. package/lib/module/components/LinearMeter/LinearMeter.js +9 -28
  59. package/lib/module/components/LinearProgress/LinearProgress.js +63 -0
  60. package/lib/module/components/LottieIntroBlock/LottieIntroBlock.js +144 -0
  61. package/lib/module/components/MetricLegendItem/MetricLegendItem.js +90 -0
  62. package/lib/module/components/MonthlyStatusGrid/MonthlyStatusGrid.js +281 -0
  63. package/lib/module/components/OTP/OTP.js +381 -38
  64. package/lib/module/components/PageHero/PageHero.js +147 -0
  65. package/lib/module/components/PoweredByLabel/PoweredByLabel.js +130 -0
  66. package/lib/module/components/PoweredByLabel/finvu.png +0 -0
  67. package/lib/module/components/ProductOverview/ProductOverview.js +142 -0
  68. package/lib/module/components/RangeTrack/RangeTrack.js +263 -0
  69. package/lib/module/components/SavingsGoalSummary/SavingsGoalSummary.js +175 -0
  70. package/lib/module/components/SegmentedTrack/SegmentedTrack.js +166 -0
  71. package/lib/module/components/StatGroup/StatGroup.js +123 -0
  72. package/lib/module/components/StatItem/StatItem.js +66 -36
  73. package/lib/module/components/StrengthIndicator/StrengthIndicator.js +152 -0
  74. package/lib/module/components/SummaryTile/SummaryTile.js +145 -0
  75. package/lib/module/components/Text/Text.js +9 -2
  76. package/lib/module/components/Tooltip/Tooltip.js +34 -27
  77. package/lib/module/components/index.js +28 -2
  78. package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
  79. package/lib/module/icons/registry.js +1 -1
  80. package/lib/module/utils/index.js +2 -1
  81. package/lib/module/utils/number-utils.js +53 -0
  82. package/lib/typescript/src/components/AccordionCheckbox/AccordionCheckbox.d.ts +71 -0
  83. package/lib/typescript/src/components/AccountCard/AccountCard.d.ts +81 -0
  84. package/lib/typescript/src/components/BrandChip/BrandChip.d.ts +43 -0
  85. package/lib/typescript/src/components/CardBankAccount/CardBankAccount.d.ts +86 -0
  86. package/lib/typescript/src/components/CardInsight/CardInsight.d.ts +48 -0
  87. package/lib/typescript/src/components/CheckboxGroup/CheckboxGroup.d.ts +41 -0
  88. package/lib/typescript/src/components/CheckboxItem/CheckboxItem.d.ts +72 -0
  89. package/lib/typescript/src/components/CircularProgressBar/CircularProgressBar.d.ts +11 -1
  90. package/lib/typescript/src/components/CoverageBarComparison/CoverageBarComparison.d.ts +105 -0
  91. package/lib/typescript/src/components/CoverageRing/CoverageRing.d.ts +90 -0
  92. package/lib/typescript/src/components/DonutChart/DonutChart.d.ts +117 -0
  93. package/lib/typescript/src/components/DonutChartSummary/DonutChartSummary.d.ts +103 -0
  94. package/lib/typescript/src/components/Dropdown/Dropdown.d.ts +62 -0
  95. package/lib/typescript/src/components/DropdownInput/DropdownInput.d.ts +107 -0
  96. package/lib/typescript/src/components/FormField/FormField.d.ts +76 -19
  97. package/lib/typescript/src/components/LinearProgress/LinearProgress.d.ts +17 -0
  98. package/lib/typescript/src/components/LottieIntroBlock/LottieIntroBlock.d.ts +58 -0
  99. package/lib/typescript/src/components/MetricLegendItem/MetricLegendItem.d.ts +37 -0
  100. package/lib/typescript/src/components/MonthlyStatusGrid/MonthlyStatusGrid.d.ts +119 -0
  101. package/lib/typescript/src/components/OTP/OTP.d.ts +88 -2
  102. package/lib/typescript/src/components/PageHero/PageHero.d.ts +53 -0
  103. package/lib/typescript/src/components/PoweredByLabel/PoweredByLabel.d.ts +70 -0
  104. package/lib/typescript/src/components/ProductOverview/ProductOverview.d.ts +39 -0
  105. package/lib/typescript/src/components/RangeTrack/RangeTrack.d.ts +173 -0
  106. package/lib/typescript/src/components/SavingsGoalSummary/SavingsGoalSummary.d.ts +95 -0
  107. package/lib/typescript/src/components/SegmentedTrack/SegmentedTrack.d.ts +108 -0
  108. package/lib/typescript/src/components/StatGroup/StatGroup.d.ts +45 -0
  109. package/lib/typescript/src/components/StatItem/StatItem.d.ts +24 -7
  110. package/lib/typescript/src/components/StrengthIndicator/StrengthIndicator.d.ts +58 -0
  111. package/lib/typescript/src/components/SummaryTile/SummaryTile.d.ts +60 -0
  112. package/lib/typescript/src/components/Text/Text.d.ts +12 -2
  113. package/lib/typescript/src/components/Tooltip/Tooltip.d.ts +13 -2
  114. package/lib/typescript/src/components/index.d.ts +29 -3
  115. package/lib/typescript/src/icons/registry.d.ts +1 -1
  116. package/lib/typescript/src/utils/index.d.ts +1 -0
  117. package/lib/typescript/src/utils/number-utils.d.ts +29 -0
  118. package/package.json +1 -3
  119. package/src/components/AccordionCheckbox/AccordionCheckbox.tsx +323 -0
  120. package/src/components/AccountCard/AccountCard.tsx +376 -0
  121. package/src/components/AppBar/AppBar.tsx +25 -14
  122. package/src/components/BrandChip/BrandChip.tsx +235 -0
  123. package/src/components/CardBankAccount/CardBankAccount.tsx +321 -0
  124. package/src/components/CardInsight/CardInsight.tsx +239 -0
  125. package/src/components/CheckboxGroup/CheckboxGroup.tsx +86 -0
  126. package/src/components/CheckboxItem/CheckboxItem.tsx +209 -0
  127. package/src/components/CircularProgressBar/CircularProgressBar.tsx +74 -9
  128. package/src/components/CoverageBarComparison/CoverageBarComparison.tsx +378 -0
  129. package/src/components/CoverageRing/CoverageRing.tsx +225 -0
  130. package/src/components/DonutChart/DonutChart.tsx +503 -0
  131. package/src/components/DonutChartSummary/DonutChartSummary.tsx +256 -0
  132. package/src/components/Dropdown/Dropdown.tsx +331 -0
  133. package/src/components/DropdownInput/DropdownInput.tsx +819 -0
  134. package/src/components/FormField/FormField.tsx +542 -215
  135. package/src/components/LinearMeter/LinearMeter.tsx +9 -39
  136. package/src/components/LinearProgress/LinearProgress.tsx +92 -0
  137. package/src/components/LottieIntroBlock/LottieIntroBlock.tsx +202 -0
  138. package/src/components/MetricLegendItem/MetricLegendItem.tsx +167 -0
  139. package/src/components/MonthlyStatusGrid/MonthlyStatusGrid.tsx +438 -0
  140. package/src/components/OTP/OTP.tsx +476 -29
  141. package/src/components/PageHero/PageHero.tsx +200 -0
  142. package/src/components/PoweredByLabel/PoweredByLabel.tsx +221 -0
  143. package/src/components/PoweredByLabel/finvu.png +0 -0
  144. package/src/components/ProductOverview/ProductOverview.tsx +236 -0
  145. package/src/components/RangeTrack/RangeTrack.tsx +394 -0
  146. package/src/components/SavingsGoalSummary/SavingsGoalSummary.tsx +269 -0
  147. package/src/components/SegmentedTrack/SegmentedTrack.tsx +268 -0
  148. package/src/components/StatGroup/StatGroup.tsx +169 -0
  149. package/src/components/StatItem/StatItem.tsx +117 -40
  150. package/src/components/StrengthIndicator/StrengthIndicator.tsx +205 -0
  151. package/src/components/SummaryTile/SummaryTile.tsx +251 -0
  152. package/src/components/Text/Text.tsx +24 -3
  153. package/src/components/Tooltip/Tooltip.tsx +50 -25
  154. package/src/components/index.ts +47 -3
  155. package/src/design-tokens/Coin Variables-variables-full.json +1 -1
  156. package/src/icons/registry.ts +1 -1
  157. package/src/utils/index.ts +1 -0
  158. package/src/utils/number-utils.ts +60 -0
@@ -21,6 +21,13 @@ Object.defineProperty(exports, "flattenChildren", {
21
21
  return _reactUtils.flattenChildren;
22
22
  }
23
23
  });
24
+ Object.defineProperty(exports, "formatIndianNumber", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _numberUtils.formatIndianNumber;
28
+ }
29
+ });
24
30
  var _reactUtils = require("./react-utils");
25
31
  var _MediaSource = _interopRequireDefault(require("./MediaSource"));
32
+ var _numberUtils = require("./number-utils");
26
33
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.formatIndianNumber = formatIndianNumber;
7
+ /**
8
+ * Format a number using the Indian numeric system.
9
+ *
10
+ * - Below 1 lakh (100,000): standard Indian-locale comma grouping (e.g. `12,400`).
11
+ * - 1 lakh up to (but excluding) 1 crore: shorthand `L` (e.g. `2.4L`).
12
+ * - 1 crore and above: shorthand `Cr` (e.g. `1.2Cr`).
13
+ *
14
+ * Trailing zero decimals are trimmed, so `100000` becomes `1L` rather than `1.0L`.
15
+ * Negative values keep the sign (`-2.4L`). Non-finite inputs (`NaN`, `Infinity`)
16
+ * are returned via `String(value)` so callers can decide how to handle them.
17
+ *
18
+ * @example formatIndianNumber(240000) // "2.4L"
19
+ * @example formatIndianNumber(12400) // "12,400"
20
+ * @example formatIndianNumber(15000000) // "1.5Cr"
21
+ * @example formatIndianNumber(-100000) // "-1L"
22
+ * @example formatIndianNumber(99999) // "99,999"
23
+ *
24
+ * @param value The number to format.
25
+ * @param options Optional formatting overrides.
26
+ * @param options.decimals Maximum number of decimal places used in the
27
+ * shorthand `L` / `Cr` form. Defaults to `1`.
28
+ * @param options.prefix String to prefix the output with — useful for a
29
+ * currency symbol, e.g. `'₹'`. Defaults to `''`.
30
+ */
31
+ function formatIndianNumber(value, options = {}) {
32
+ if (!Number.isFinite(value)) return String(value);
33
+ const {
34
+ decimals = 1,
35
+ prefix = ''
36
+ } = options;
37
+ const sign = value < 0 ? '-' : '';
38
+ const absValue = Math.abs(value);
39
+ const CRORE = 10_000_000;
40
+ const LAKH = 100_000;
41
+ if (absValue >= CRORE) {
42
+ return `${sign}${prefix}${trimTrailingZeros((absValue / CRORE).toFixed(Math.max(0, decimals)))}Cr`;
43
+ }
44
+ if (absValue >= LAKH) {
45
+ return `${sign}${prefix}${trimTrailingZeros((absValue / LAKH).toFixed(Math.max(0, decimals)))}L`;
46
+ }
47
+
48
+ // For sub-lakh values, fall back to the native Indian comma grouping.
49
+ // `toLocaleString` with `en-IN` gives 1,23,456 — exactly what we want.
50
+ return `${prefix}${value.toLocaleString('en-IN', {
51
+ maximumFractionDigits: 0
52
+ })}`;
53
+ }
54
+ function trimTrailingZeros(numericString) {
55
+ if (!numericString.includes('.')) return numericString;
56
+ return numericString.replace(/\.?0+$/, '');
57
+ }
@@ -0,0 +1,233 @@
1
+ "use strict";
2
+
3
+ import React, { useCallback, useState } from 'react';
4
+ import { View, Text, Pressable, LayoutAnimation, Platform, UIManager } from 'react-native';
5
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
6
+ import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils';
7
+ import Checkbox from '../Checkbox/Checkbox';
8
+ import Divider from '../Divider/Divider';
9
+ import Icon from '../../icons/Icon';
10
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
11
+ if (Platform.OS === 'android' && UIManager.setLayoutAnimationEnabledExperimental) {
12
+ UIManager.setLayoutAnimationEnabledExperimental(true);
13
+ }
14
+ /**
15
+ * AccordionCheckbox composes a header (with a `Checkbox`, title, subtitle and
16
+ * chevron) and a collapsible content slot. It mirrors the Figma
17
+ * "Accordion Checkbox" component.
18
+ *
19
+ * Two independent interactions live inside the header:
20
+ * - **Pressing the checkbox** toggles the parent checked state via
21
+ * `onCheckedChange` (typically used for "select all" behaviour).
22
+ * - **Pressing anywhere else on the header** toggles the expanded state via
23
+ * `onExpandedChange`.
24
+ *
25
+ * When expanded, a divider is shown and `children` are rendered with `modes`
26
+ * automatically forwarded through `cloneChildrenWithModes`.
27
+ *
28
+ * @component
29
+ * @param {AccordionCheckboxProps} props
30
+ *
31
+ * @example
32
+ * ```tsx
33
+ * <AccordionCheckbox
34
+ * title="Axis Bank"
35
+ * subtitle="3 accounts"
36
+ * defaultExpanded
37
+ * defaultChecked
38
+ * modes={{ 'Color Mode': 'Light' }}
39
+ * >
40
+ * <CheckboxGroup>
41
+ * <CheckboxItem label="Fixed deposit • 0245" />
42
+ * <CheckboxItem label="Recurring deposit • 1182" />
43
+ * <CheckboxItem label="Mutual fund • Equity" />
44
+ * </CheckboxGroup>
45
+ * </AccordionCheckbox>
46
+ * ```
47
+ */
48
+ function AccordionCheckbox({
49
+ title = 'Axis Bank',
50
+ subtitle = '3 accounts',
51
+ defaultExpanded = false,
52
+ expanded: controlledExpanded,
53
+ onExpandedChange,
54
+ defaultChecked = false,
55
+ checked: controlledChecked,
56
+ onCheckedChange,
57
+ disabled = false,
58
+ children,
59
+ modes = EMPTY_MODES,
60
+ style,
61
+ accessibilityLabel
62
+ }) {
63
+ const isExpandedControlled = controlledExpanded !== undefined;
64
+ const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);
65
+ const isExpanded = isExpandedControlled ? controlledExpanded : internalExpanded;
66
+ const isCheckedControlled = controlledChecked !== undefined;
67
+ const [internalChecked, setInternalChecked] = useState(defaultChecked);
68
+ const isChecked = isCheckedControlled ? controlledChecked : internalChecked;
69
+ const handleToggleExpanded = useCallback(() => {
70
+ if (disabled) return;
71
+ LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
72
+ const next = !isExpanded;
73
+ if (!isExpandedControlled) {
74
+ setInternalExpanded(next);
75
+ }
76
+ onExpandedChange?.(next);
77
+ }, [disabled, isExpanded, isExpandedControlled, onExpandedChange]);
78
+ const handleToggleChecked = useCallback(next => {
79
+ if (disabled) return;
80
+ if (!isCheckedControlled) {
81
+ setInternalChecked(next);
82
+ }
83
+ onCheckedChange?.(next);
84
+ }, [disabled, isCheckedControlled, onCheckedChange]);
85
+ const background = getVariableByName('accordionCheckbox/background', modes) ?? '#ffffff';
86
+ const radius = getVariableByName('accordionCheckbox/radius', modes) ?? 12;
87
+ const paddingHorizontal = getVariableByName('accordionCheckbox/padding/horizontal', modes) ?? 12;
88
+ const paddingVertical = getVariableByName('accordionCheckbox/padding/vertical', modes) ?? 16;
89
+ const containerGap = getVariableByName('accordionCheckbox/gap', modes) ?? 12;
90
+ const borderColor = getVariableByName('accordionCheckbox/border/color', modes) ?? '#ebebed';
91
+ const borderSize = getVariableByName('accordionCheckbox/border/size', modes) ?? 1;
92
+ const headerGap = getVariableByName('accordionCheckbox/header/gap', modes) ?? 12;
93
+ const headerPaddingHorizontal = getVariableByName('accordionCheckbox/header/padding/horizontal', modes) ?? 0;
94
+ const headerPaddingVertical = getVariableByName('accordionCheckbox/header/padding/vertical', modes) ?? 0;
95
+ const headerWrapGap = getVariableByName('accordionCheckbox/header/wrap/gap', modes) ?? 12;
96
+ const textWrapGap = getVariableByName('accordionCheckbox/textWrap/gap', modes) ?? 2;
97
+ const titleColor = getVariableByName('accordionCheckbox/title/color', modes) ?? '#000000';
98
+ const titleFontSize = getVariableByName('accordionCheckbox/title/fontSize', modes) ?? 14;
99
+ const titleFontFamily = getVariableByName('accordionCheckbox/title/fontFamily', modes) ?? 'JioType Var';
100
+ const titleLineHeight = getVariableByName('accordionCheckbox/title/lineHeight', modes) ?? 18;
101
+ const titleFontWeightRaw = getVariableByName('accordionCheckbox/title/fontWeight', modes) ?? 600;
102
+ const titleFontWeight = String(titleFontWeightRaw);
103
+ const subtitleColor = getVariableByName('accordionCheckbox/subtitle/color', modes) ?? '#23190a';
104
+ const subtitleFontSize = getVariableByName('accordionCheckbox/subtitle/fontSize', modes) ?? 12;
105
+ const subtitleFontFamily = getVariableByName('accordionCheckbox/subtitle/fontFamily', modes) ?? 'JioType Var';
106
+ const subtitleLineHeight = getVariableByName('accordionCheckbox/subtitle/lineHeight', modes) ?? 16;
107
+ const subtitleFontWeightRaw = getVariableByName('accordionCheckbox/subtitle/fontWeight', modes) ?? 500;
108
+ const subtitleFontWeight = String(subtitleFontWeightRaw);
109
+ const iconColor = getVariableByName('accordionCheckbox/icon/color', modes) ?? '#000000';
110
+ const iconSize = getVariableByName('accordionCheckbox/icon/size', modes) ?? 24;
111
+ const contentGap = getVariableByName('accordionCheckbox/content/gap', modes) ?? 0;
112
+ const contentPaddingTop = getVariableByName('accordionCheckbox/content/padding/top', modes) ?? 8;
113
+ const contentPaddingBottom = getVariableByName('accordionCheckbox/content/padding/bottom', modes) ?? 0;
114
+ const contentPaddingHorizontal = getVariableByName('accordionCheckbox/content/padding/horizontal', modes) ?? 0;
115
+ const containerStyle = {
116
+ backgroundColor: background,
117
+ borderRadius: radius,
118
+ paddingHorizontal,
119
+ paddingVertical,
120
+ flexDirection: 'column',
121
+ alignItems: 'stretch',
122
+ gap: containerGap,
123
+ overflow: 'hidden',
124
+ ...(isExpanded ? {
125
+ borderWidth: borderSize,
126
+ borderColor
127
+ } : null),
128
+ ...(disabled ? {
129
+ opacity: 0.6
130
+ } : null)
131
+ };
132
+ const headerStyle = {
133
+ flexDirection: 'row',
134
+ alignItems: 'center',
135
+ gap: headerGap,
136
+ paddingHorizontal: headerPaddingHorizontal,
137
+ paddingVertical: headerPaddingVertical
138
+ };
139
+ const wrapStyle = {
140
+ flex: 1,
141
+ minWidth: 0,
142
+ flexDirection: 'row',
143
+ alignItems: 'center',
144
+ gap: headerWrapGap
145
+ };
146
+ const textWrapStyle = {
147
+ flex: 1,
148
+ minWidth: 0,
149
+ flexDirection: 'column',
150
+ alignItems: 'flex-start',
151
+ gap: textWrapGap
152
+ };
153
+ const titleStyle = {
154
+ color: titleColor,
155
+ fontSize: titleFontSize,
156
+ lineHeight: titleLineHeight,
157
+ fontFamily: titleFontFamily,
158
+ fontWeight: titleFontWeight
159
+ };
160
+ const subtitleStyle = {
161
+ color: subtitleColor,
162
+ fontSize: subtitleFontSize,
163
+ lineHeight: subtitleLineHeight,
164
+ fontFamily: subtitleFontFamily,
165
+ fontWeight: subtitleFontWeight
166
+ };
167
+ const contentStyle = {
168
+ flexDirection: 'column',
169
+ alignItems: 'stretch',
170
+ justifyContent: 'center',
171
+ gap: contentGap,
172
+ paddingTop: contentPaddingTop,
173
+ paddingBottom: contentPaddingBottom,
174
+ paddingHorizontal: contentPaddingHorizontal
175
+ };
176
+ const a11yLabel = accessibilityLabel ?? title;
177
+ return /*#__PURE__*/_jsxs(View, {
178
+ style: [containerStyle, style],
179
+ children: [/*#__PURE__*/_jsxs(Pressable, {
180
+ onPress: handleToggleExpanded,
181
+ disabled: disabled,
182
+ accessibilityRole: "button",
183
+ accessibilityState: {
184
+ expanded: isExpanded,
185
+ disabled
186
+ },
187
+ accessibilityLabel: a11yLabel,
188
+ accessibilityHint: isExpanded ? 'Collapse' : 'Expand',
189
+ style: ({
190
+ pressed
191
+ }) => [headerStyle, pressed && !disabled ? {
192
+ opacity: 0.9
193
+ } : null],
194
+ children: [/*#__PURE__*/_jsxs(View, {
195
+ style: wrapStyle,
196
+ children: [/*#__PURE__*/_jsx(Checkbox, {
197
+ checked: isChecked,
198
+ onValueChange: handleToggleChecked,
199
+ disabled: disabled,
200
+ modes: modes,
201
+ accessibilityLabel: typeof title === 'string' ? `Select ${title}` : undefined
202
+ }), /*#__PURE__*/_jsxs(View, {
203
+ style: textWrapStyle,
204
+ children: [/*#__PURE__*/_jsx(Text, {
205
+ style: titleStyle,
206
+ numberOfLines: 1,
207
+ selectable: false,
208
+ children: title
209
+ }), subtitle ? /*#__PURE__*/_jsx(Text, {
210
+ style: subtitleStyle,
211
+ numberOfLines: 1,
212
+ selectable: false,
213
+ children: subtitle
214
+ }) : null]
215
+ })]
216
+ }), /*#__PURE__*/_jsx(Icon, {
217
+ name: isExpanded ? 'ic_chevron_up' : 'ic_chevron_down',
218
+ size: iconSize,
219
+ color: iconColor,
220
+ accessibilityElementsHidden: true,
221
+ importantForAccessibility: "no"
222
+ })]
223
+ }), isExpanded ? /*#__PURE__*/_jsxs(_Fragment, {
224
+ children: [/*#__PURE__*/_jsx(Divider, {
225
+ modes: modes
226
+ }), children ? /*#__PURE__*/_jsx(View, {
227
+ style: contentStyle,
228
+ children: cloneChildrenWithModes(children, modes)
229
+ }) : null]
230
+ }) : null]
231
+ });
232
+ }
233
+ export default AccordionCheckbox;
@@ -0,0 +1,241 @@
1
+ "use strict";
2
+
3
+ import React, { useCallback, useMemo, useRef } from 'react';
4
+ import { Image as RNImage, Platform, Pressable, Text, View } from 'react-native';
5
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
6
+ import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils';
7
+ import Icon from '../../icons/Icon';
8
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
9
+ const IS_IOS = Platform.OS === 'ios';
10
+ const PRESS_DELAY = IS_IOS ? 130 : 0;
11
+ const DEFAULT_IMAGE_RATIO = 125 / 82;
12
+ const pressedOverlayStyle = {
13
+ opacity: 0.7
14
+ };
15
+
16
+ // Default modes for the "Add" placeholder icon (`iconButton/*` tokens).
17
+ // Caller-supplied `modes` are merged on top so every key here can be overridden.
18
+ const ADD_ICON_DEFAULT_MODES = Object.freeze({
19
+ AppearanceBrand: 'Secondary',
20
+ Emphasis: 'Low',
21
+ "Button / Size": "M"
22
+ });
23
+ const toNumber = (value, fallback) => {
24
+ if (typeof value === 'number') return Number.isFinite(value) ? value : fallback;
25
+ if (typeof value === 'string') {
26
+ const parsed = Number(value);
27
+ return Number.isFinite(parsed) ? parsed : fallback;
28
+ }
29
+ return fallback;
30
+ };
31
+ const toFontWeight = (value, fallback) => {
32
+ if (typeof value === 'number') return String(value);
33
+ if (typeof value === 'string') return value;
34
+ return fallback;
35
+ };
36
+ const normalizeImageSource = src => {
37
+ if (src == null) return undefined;
38
+ if (typeof src === 'string') return {
39
+ uri: src
40
+ };
41
+ return src;
42
+ };
43
+
44
+ /**
45
+ * `AccountCard` — a compact card preview used to represent a linked
46
+ * financial account in lists / grids.
47
+ *
48
+ * Two visual states are supported via the `state` prop:
49
+ *
50
+ * 1. `'connected'` (default): renders a small card-art preview, a bold
51
+ * `title` and a regular-weight `subtitle` (e.g. masked account number).
52
+ * 2. `'add'`: renders a soft-tinted placeholder field with a centred `+`
53
+ * icon and the `title` underneath, intended as the "add new account"
54
+ * entry-point at the end of a list of connected accounts.
55
+ *
56
+ * All values resolve through the `accountCard/*` design tokens with
57
+ * sensible Figma defaults so the card renders correctly out of the box.
58
+ *
59
+ * @component
60
+ * @param {AccountCardProps} props
61
+ */
62
+ function AccountCard({
63
+ state = 'connected',
64
+ title = 'Personal account',
65
+ subtitle = '**** 5651',
66
+ imageSource,
67
+ imageRatio = DEFAULT_IMAGE_RATIO,
68
+ cardSlot,
69
+ addIcon = 'ic_add',
70
+ onPress,
71
+ disabled = false,
72
+ modes = EMPTY_MODES,
73
+ style,
74
+ accessibilityLabel,
75
+ accessibilityHint
76
+ }) {
77
+ const iconModes = useMemo(() => modes === EMPTY_MODES ? ADD_ICON_DEFAULT_MODES : {
78
+ ...ADD_ICON_DEFAULT_MODES,
79
+ ...modes
80
+ }, [modes]);
81
+
82
+ // ---- Tokens ---------------------------------------------------------
83
+ const gap = toNumber(getVariableByName('accountCard/gap', modes), 8);
84
+ const textWrapGap = toNumber(getVariableByName('accountCard/textWrap/gap', modes), 0);
85
+ const titleColor = getVariableByName('accountCard/title/foreground', modes) ?? '#0d0d0f';
86
+ const titleFontFamily = getVariableByName('accountCard/title/fontFamily', modes) ?? 'JioType Var';
87
+ const titleFontSize = toNumber(getVariableByName('accountCard/title/fontSize', modes), 12);
88
+ const titleLineHeight = toNumber(getVariableByName('accountCard/title/lineHeight', modes), 16);
89
+ const titleFontWeight = toFontWeight(getVariableByName('accountCard/title/fontWeight', modes), '700');
90
+ const subtitleColor = getVariableByName('accountCard/subtitle/foreground', modes) ?? '#24262b';
91
+ const subtitleFontFamily = getVariableByName('accountCard/subtitle/fontFamily', modes) ?? 'JioType Var';
92
+ const subtitleFontSize = toNumber(getVariableByName('accountCard/subtitle/fontSize', modes), 12);
93
+ const subtitleLineHeight = toNumber(getVariableByName('accountCard/subtitle/lineHeight', modes), 16);
94
+ const subtitleFontWeight = toFontWeight(getVariableByName('accountCard/subtitle/fontWeight', modes), '400');
95
+ const addFieldRadius = toNumber(getVariableByName('accountCard/addItemField/radius', modes), 8);
96
+ const addFieldBg = getVariableByName('accountCard/addItemField/bg', modes) ?? '#ede8ff';
97
+ const addIconColor = getVariableByName('iconButton/icon/color', iconModes) ?? '#5d00b5';
98
+ const addIconSize = toNumber(getVariableByName('iconButton/icon/size', iconModes), 16);
99
+
100
+ // ---- Styles ---------------------------------------------------------
101
+ const titleStyle = {
102
+ color: titleColor,
103
+ fontFamily: titleFontFamily,
104
+ fontSize: titleFontSize,
105
+ lineHeight: titleLineHeight,
106
+ fontWeight: titleFontWeight,
107
+ width: '100%'
108
+ };
109
+ const subtitleStyle = {
110
+ color: subtitleColor,
111
+ fontFamily: subtitleFontFamily,
112
+ fontSize: subtitleFontSize,
113
+ lineHeight: subtitleLineHeight,
114
+ fontWeight: subtitleFontWeight,
115
+ width: '100%'
116
+ };
117
+ const imageBoxStyle = {
118
+ width: '100%',
119
+ aspectRatio: imageRatio,
120
+ overflow: 'hidden'
121
+ };
122
+
123
+ // RN's `<Image>` accepts `ImageStyle`, which has a narrower `overflow`
124
+ // union than `ViewStyle`. Build the image-only style separately so the
125
+ // shared box dimensions can be reused without a cast.
126
+ const imageStyle = {
127
+ width: '100%',
128
+ aspectRatio: imageRatio
129
+ };
130
+ const addFieldStyle = {
131
+ ...imageBoxStyle,
132
+ backgroundColor: addFieldBg,
133
+ borderRadius: addFieldRadius,
134
+ alignItems: 'center',
135
+ justifyContent: 'center'
136
+ };
137
+
138
+ // ---- Image / placeholder area --------------------------------------
139
+ const renderCardArea = () => {
140
+ if (cardSlot !== undefined && cardSlot !== null) {
141
+ const processed = cloneChildrenWithModes(cardSlot, modes);
142
+ return /*#__PURE__*/_jsx(View, {
143
+ style: imageBoxStyle,
144
+ pointerEvents: "box-none",
145
+ children: processed.length === 1 ? processed[0] : processed
146
+ });
147
+ }
148
+ if (state === 'add') {
149
+ return /*#__PURE__*/_jsx(View, {
150
+ style: addFieldStyle,
151
+ accessibilityElementsHidden: true,
152
+ importantForAccessibility: "no",
153
+ children: /*#__PURE__*/_jsx(Icon, {
154
+ name: addIcon,
155
+ size: addIconSize,
156
+ color: addIconColor
157
+ })
158
+ });
159
+ }
160
+ const normalized = normalizeImageSource(imageSource);
161
+ if (normalized) {
162
+ return /*#__PURE__*/_jsx(RNImage, {
163
+ source: normalized,
164
+ style: imageStyle,
165
+ resizeMode: "cover",
166
+ accessibilityElementsHidden: true,
167
+ importantForAccessibility: "no"
168
+ });
169
+ }
170
+ return /*#__PURE__*/_jsx(View, {
171
+ style: imageBoxStyle
172
+ });
173
+ };
174
+
175
+ // ---- Pressable wiring ----------------------------------------------
176
+ // Keep React state out of the press path. `Pressable`'s style callback
177
+ // applies the pressed visual without a re-render.
178
+ const userHandlersRef = useRef({});
179
+ const handlePressIn = useCallback(e => {
180
+ userHandlersRef.current.onPressIn?.(e);
181
+ }, []);
182
+ const handlePressOut = useCallback(e => {
183
+ userHandlersRef.current.onPressOut?.(e);
184
+ }, []);
185
+ const containerStyle = useMemo(() => ({
186
+ width: '100%',
187
+ flexDirection: 'column',
188
+ alignItems: 'flex-start',
189
+ gap,
190
+ opacity: disabled ? 0.5 : 1
191
+ }), [gap, disabled]);
192
+ const pressableStyle = useCallback(({
193
+ pressed
194
+ }) => [containerStyle, style, pressed && !disabled && onPress ? pressedOverlayStyle : null], [containerStyle, style, disabled, onPress]);
195
+ const showSubtitle = state === 'connected' && subtitle != null && subtitle !== '';
196
+ const a11yRole = onPress ? 'button' : undefined;
197
+ const a11yLabel = accessibilityLabel ?? title;
198
+ const content = /*#__PURE__*/_jsxs(_Fragment, {
199
+ children: [renderCardArea(), title != null && title !== '' || showSubtitle ? /*#__PURE__*/_jsxs(View, {
200
+ style: {
201
+ width: '100%',
202
+ flexDirection: 'column',
203
+ alignItems: 'flex-start',
204
+ gap: textWrapGap
205
+ },
206
+ children: [title != null && title !== '' ? /*#__PURE__*/_jsx(Text, {
207
+ style: titleStyle,
208
+ numberOfLines: 1,
209
+ children: title
210
+ }) : null, showSubtitle ? /*#__PURE__*/_jsx(Text, {
211
+ style: subtitleStyle,
212
+ numberOfLines: 1,
213
+ children: subtitle
214
+ }) : null]
215
+ }) : null]
216
+ });
217
+ if (!onPress) {
218
+ return /*#__PURE__*/_jsx(View, {
219
+ accessibilityLabel: a11yLabel,
220
+ accessibilityHint: accessibilityHint,
221
+ style: [containerStyle, style],
222
+ children: content
223
+ });
224
+ }
225
+ return /*#__PURE__*/_jsx(Pressable, {
226
+ accessibilityRole: a11yRole,
227
+ accessibilityLabel: a11yLabel,
228
+ accessibilityHint: accessibilityHint,
229
+ accessibilityState: {
230
+ disabled
231
+ },
232
+ onPress: disabled ? undefined : onPress,
233
+ disabled: disabled,
234
+ onPressIn: handlePressIn,
235
+ onPressOut: handlePressOut,
236
+ unstable_pressDelay: PRESS_DELAY,
237
+ style: pressableStyle,
238
+ children: content
239
+ });
240
+ }
241
+ export default /*#__PURE__*/React.memo(AccountCard);
@@ -42,12 +42,13 @@ export default function AppBar({
42
42
  const containerStyle = {
43
43
  flexDirection: 'row',
44
44
  alignItems: 'center',
45
- justifyContent: 'space-between',
45
+ // No `justifyContent` here: with the inline middle slot using `flex: 1`
46
+ // the three sections lay out naturally (leading | middle | actions).
47
+ // When middleSlot is absent we fall back to `space-between` at the wrapper
48
+ // level so leading & actions still anchor to the edges.
46
49
  paddingHorizontal: paddingHorizontal ?? 16,
47
50
  paddingVertical: paddingVertical ?? (isMain ? 16 : 10),
48
51
  backgroundColor: backgroundColor ?? '#FFFFFF'
49
- // We can set minHeight if we want to enforce consistency, but padding should dictate it mostly.
50
- // Figma shows specific heights implicitly via padding + content.
51
52
  // MainPage: h=68 (16 top/bot padding? 36 height content?)
52
53
  // SubPage: h=52
53
54
  };
@@ -110,8 +111,17 @@ export default function AppBar({
110
111
  style: actionsStyle,
111
112
  children: cloneChildrenWithModes(React.Children.toArray(actionsSlot), modes)
112
113
  }) : null;
114
+
115
+ // When there is no middleSlot we want leading & actions pinned to the
116
+ // outer edges, so we apply `space-between` at the wrapper. With a middle
117
+ // slot present, the middle (flex: 1) absorbs the remaining space, so
118
+ // `space-between` is a no-op.
119
+ const wrapperStyle = {
120
+ ...containerStyle,
121
+ justifyContent: processedMiddle ? 'flex-start' : 'space-between'
122
+ };
113
123
  return /*#__PURE__*/_jsxs(View, {
114
- style: [containerStyle, style],
124
+ style: [wrapperStyle, style],
115
125
  accessibilityRole: "header",
116
126
  accessibilityLabel: undefined,
117
127
  ...(accessibilityHint ? {
@@ -126,15 +136,11 @@ export default function AppBar({
126
136
  children: processedLeading
127
137
  }), processedMiddle && /*#__PURE__*/_jsx(View, {
128
138
  style: {
129
- position: 'absolute',
130
- left: 0,
131
- right: 0,
132
- top: 0,
133
- bottom: 0,
139
+ flex: 1,
140
+ minWidth: 0,
134
141
  alignItems: 'center',
135
142
  justifyContent: 'center',
136
- zIndex: -1 // Behind actions if overlap? Or should be on top?
137
- // Usually middle title shouldn't block actions. `pointerEvents="box-none"` is safer.
143
+ paddingHorizontal: 8
138
144
  },
139
145
  pointerEvents: "box-none",
140
146
  children: processedMiddle