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
@@ -1,8 +1,9 @@
1
1
  import React from 'react'
2
- import { View, Text, type StyleProp, type ViewStyle, type TextStyle, type DimensionValue } from 'react-native'
2
+ import { View, Text, type StyleProp, type ViewStyle, type TextStyle } from 'react-native'
3
3
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
4
4
  import { EMPTY_MODES } from '../../utils/react-utils'
5
5
  import MoneyValue from '../MoneyValue/MoneyValue'
6
+ import LinearProgress from '../LinearProgress/LinearProgress'
6
7
 
7
8
  type LinearMeterLabelProps = {
8
9
  children: React.ReactNode
@@ -57,14 +58,6 @@ const LinearMeter = ({
57
58
  ...rest
58
59
  }: LinearMeterProps) => {
59
60
  const gap = getVariableByName('linearMeter/gap', modes)
60
- // Track tokens
61
- const trackBg = getVariableByName('linearMeter/track/background', modes)
62
- const trackHeight = getVariableByName('linearMeter/track/height', modes)
63
- const trackRadius = getVariableByName('linearMeter/track/radius', modes)
64
-
65
- // Indicator tokens
66
- const indicatorBg = getVariableByName('linearMeter/indicator/background', modes)
67
- const indicatorRadius = getVariableByName('linearMeter/indicator/radius', modes)
68
61
 
69
62
  // Wrap tokens
70
63
  const wrapGap = getVariableByName('linearMeter/wrap/gap', modes)
@@ -94,10 +87,6 @@ const LinearMeter = ({
94
87
 
95
88
  const content = children ? childrenWithModes : defaultContent
96
89
 
97
- // Calculate width percentage
98
- const clampedValue = Math.min(Math.max(value, 0), 1)
99
- const widthPercent = `${clampedValue * 100}%`
100
-
101
90
  return (
102
91
  <View
103
92
  style={[
@@ -110,32 +99,13 @@ const LinearMeter = ({
110
99
  ]}
111
100
  {...rest}
112
101
  >
113
- {/* Track */}
114
- <View
115
- style={[
116
- {
117
- flex: 1,
118
- height: trackHeight,
119
- backgroundColor: trackBg,
120
- borderRadius: trackRadius,
121
- overflow: 'hidden', // Ensure indicator stays inside
122
- },
123
- trackStyle,
124
- ]}
125
- >
126
- {/* Indicator */}
127
- <View
128
- style={[
129
- {
130
- width: widthPercent as DimensionValue,
131
- height: '100%',
132
- backgroundColor: indicatorBg,
133
- borderRadius: indicatorRadius,
134
- },
135
- indicatorStyle,
136
- ]}
137
- />
138
- </View>
102
+ <LinearProgress
103
+ value={value}
104
+ modes={modes}
105
+ style={{ flex: 1 }}
106
+ trackStyle={trackStyle}
107
+ indicatorStyle={indicatorStyle}
108
+ />
139
109
 
140
110
  {/* Right Slot Wrapper */}
141
111
  <View
@@ -0,0 +1,92 @@
1
+ import React from 'react'
2
+ import {
3
+ View,
4
+ type StyleProp,
5
+ type ViewStyle,
6
+ type DimensionValue,
7
+ } from 'react-native'
8
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
9
+ import { EMPTY_MODES } from '../../utils/react-utils'
10
+
11
+ export type LinearProgressProps = {
12
+ /** Progress value between 0 and 1. Values are clamped. */
13
+ value?: number
14
+ /** Design token modes for theming */
15
+ modes?: Record<string, any>
16
+ /** Override container styles (the track wrapper) */
17
+ style?: StyleProp<ViewStyle>
18
+ /** Override the track styles */
19
+ trackStyle?: StyleProp<ViewStyle>
20
+ /** Override the indicator styles */
21
+ indicatorStyle?: StyleProp<ViewStyle>
22
+ } & Omit<React.ComponentProps<typeof View>, 'style'>
23
+
24
+ const LinearProgress = ({
25
+ value = 0,
26
+ modes = EMPTY_MODES,
27
+ style,
28
+ trackStyle,
29
+ indicatorStyle,
30
+ ...rest
31
+ }: LinearProgressProps) => {
32
+ // The track and the progress indicator are intentionally rendered at
33
+ // different emphasis levels by default: the track sits in the
34
+ // background as a low-emphasis surface, while the progress indicator
35
+ // is the high-emphasis foreground. Defaults are placed *before* the
36
+ // user-provided modes spread, so callers can still override
37
+ // `Emphasis / DataViz` (or any other mode) via the `modes` prop.
38
+ const trackModes = { 'Emphasis': 'Low', ...modes }
39
+ const progressModes = { 'Emphasis': 'High', ...modes }
40
+
41
+ const trackHeight =
42
+ (getVariableByName('linearProgress/track/height', trackModes) as number | null) ?? 8
43
+ const trackRadius =
44
+ (getVariableByName('linearProgress/track/radius', trackModes) as number | null) ?? 999
45
+ const trackBg =
46
+ (getVariableByName('linearProgress/track/background', trackModes) as string | null) ??
47
+ '#ede7ff'
48
+
49
+ const indicatorHeight =
50
+ (getVariableByName('linearProgress/indicator/height', progressModes) as number | null) ?? 8
51
+ const indicatorRadius =
52
+ (getVariableByName('linearProgress/indicator/radius', progressModes) as number | null) ?? 999
53
+ const indicatorBg =
54
+ (getVariableByName('linearProgress/indicator/background', progressModes) as string | null) ??
55
+ '#5d00b5'
56
+
57
+ const clampedValue = Math.min(Math.max(value, 0), 1)
58
+ const widthPercent = `${clampedValue * 100}%` as DimensionValue
59
+
60
+ return (
61
+ <View
62
+ style={[
63
+ {
64
+ height: trackHeight,
65
+ backgroundColor: trackBg,
66
+ borderRadius: trackRadius,
67
+ overflow: 'hidden',
68
+ width: '100%',
69
+ },
70
+ style,
71
+ trackStyle,
72
+ ]}
73
+ accessibilityRole="progressbar"
74
+ accessibilityValue={{ min: 0, max: 1, now: clampedValue }}
75
+ {...rest}
76
+ >
77
+ <View
78
+ style={[
79
+ {
80
+ width: widthPercent,
81
+ height: indicatorHeight,
82
+ backgroundColor: indicatorBg,
83
+ borderRadius: indicatorRadius,
84
+ },
85
+ indicatorStyle,
86
+ ]}
87
+ />
88
+ </View>
89
+ )
90
+ }
91
+
92
+ export default LinearProgress
@@ -0,0 +1,202 @@
1
+ import React, { useMemo } from 'react'
2
+ import {
3
+ View,
4
+ Text,
5
+ type StyleProp,
6
+ type ViewStyle,
7
+ type TextStyle,
8
+ } from 'react-native'
9
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
10
+ import { useTokens } from '../../design-tokens/JFSThemeProvider'
11
+ import Button from '../Button/Button'
12
+ import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils'
13
+
14
+ const DEFAULT_MEDIA_SIZE = 117
15
+
16
+ export type LottieIntroBlockProps = {
17
+ /** Headline text shown below the media area. */
18
+ title?: string
19
+ /** Whether to render the supportive paragraph below the title. */
20
+ showSupportText?: boolean
21
+ /** Body/supportive text shown below the title. */
22
+ supportText?: string
23
+ /** Whether to render the action button at the bottom. */
24
+ showButton?: boolean
25
+ /** Label for the default action button. Ignored when `buttonSlot` is provided. */
26
+ buttonLabel?: string
27
+ /** Press handler for the default action button. Ignored when `buttonSlot` is provided. */
28
+ onButtonPress?: () => void
29
+ /**
30
+ * Custom slot for the media area (Lottie animation, illustration, or image).
31
+ * Should render at the design size of 117x117. If omitted, a neutral
32
+ * placeholder of the same size is rendered so the layout stays stable.
33
+ * `modes` are automatically cascaded into this slot.
34
+ */
35
+ media?: React.ReactNode
36
+ /**
37
+ * Optional slot to fully override the action button.
38
+ * When provided, `showButton`, `buttonLabel`, and `onButtonPress` are ignored.
39
+ * `modes` are automatically cascaded into this slot.
40
+ */
41
+ buttonSlot?: React.ReactNode
42
+ /** Mode configuration for design-token theming. */
43
+ modes?: Record<string, any>
44
+ /** Style overrides applied to the outer container. */
45
+ style?: StyleProp<ViewStyle>
46
+ testID?: string
47
+ }
48
+
49
+ /**
50
+ * LottieIntroBlock displays a centered onboarding/intro block composed of a
51
+ * media slot (typically a Lottie animation or illustration) above a title,
52
+ * an optional supportive paragraph, and an optional action button.
53
+ *
54
+ * All visual values are resolved from Figma design tokens via
55
+ * `getVariableByName`. Slots cascade the active `modes` to their children
56
+ * through `cloneChildrenWithModes`.
57
+ *
58
+ * @component
59
+ * @example
60
+ * ```tsx
61
+ * <LottieIntroBlock
62
+ * title="Let's get to know how your financial health is doing"
63
+ * supportText="From assets to taxes, stay on top of everything in one simple view."
64
+ * buttonLabel="Get started"
65
+ * onButtonPress={() => navigate('NextScreen')}
66
+ * media={<MyLottiePlayer source={animationSource} />}
67
+ * />
68
+ * ```
69
+ */
70
+ function LottieIntroBlock({
71
+ title = "Let's get to know how your financial health is doing",
72
+ showSupportText = true,
73
+ supportText = 'From assets to taxes, stay on top of everything in one simple view.',
74
+ showButton = true,
75
+ buttonLabel = 'Button',
76
+ onButtonPress,
77
+ media,
78
+ buttonSlot,
79
+ modes: propModes = EMPTY_MODES,
80
+ style,
81
+ testID,
82
+ }: LottieIntroBlockProps) {
83
+ const { modes: globalModes } = useTokens()
84
+ const modes = useMemo(
85
+ () => ({ ...globalModes, ...propModes }),
86
+ [globalModes, propModes]
87
+ )
88
+
89
+ // Container
90
+ const gap = Number(getVariableByName('lottieIntroBlock/gap', modes)) || 36
91
+ const paddingHorizontal =
92
+ Number(getVariableByName('lottieIntroBlock/padding/horizontal', modes)) || 0
93
+ const paddingVertical =
94
+ Number(getVariableByName('lottieIntroBlock/padding/vertical', modes)) || 16
95
+
96
+ // Text wrap
97
+ const textWrapGap =
98
+ Number(getVariableByName('lottieIntroBlock/textWrap/gap', modes)) || 16
99
+
100
+ // Title
101
+ const titleColor =
102
+ getVariableByName('lottieIntroBlock/title/foreground', modes) || '#0d0d0f'
103
+ const titleFontSize =
104
+ Number(getVariableByName('lottieIntroBlock/title/fontSize', modes)) || 23
105
+ const titleFontFamily =
106
+ getVariableByName('lottieIntroBlock/title/fontFamily', modes) || 'System'
107
+ const titleLineHeight =
108
+ Number(getVariableByName('lottieIntroBlock/title/lineHeight', modes)) || 23
109
+ const titleFontWeight =
110
+ getVariableByName('lottieIntroBlock/title/fontWeight', modes) || 900
111
+
112
+ // Support text
113
+ const supportColor =
114
+ getVariableByName('lottieIntroBlock/supportText/foreground', modes) ||
115
+ '#0d0d0f'
116
+ const supportFontSize =
117
+ Number(getVariableByName('lottieIntroBlock/supportText/fontSize', modes)) ||
118
+ 14
119
+ const supportFontFamily =
120
+ getVariableByName('lottieIntroBlock/supportText/fontFamily', modes) ||
121
+ 'System'
122
+ const supportLineHeight =
123
+ Number(
124
+ getVariableByName('lottieIntroBlock/supportText/lineHeight', modes)
125
+ ) || 18
126
+ const supportFontWeight =
127
+ getVariableByName('lottieIntroBlock/supportText/fontWeight', modes) || 400
128
+
129
+ const containerStyle: ViewStyle = {
130
+ flexDirection: 'column',
131
+ alignItems: 'center',
132
+ paddingHorizontal,
133
+ paddingVertical,
134
+ gap,
135
+ }
136
+
137
+ const textWrapStyle: ViewStyle = {
138
+ flexDirection: 'column',
139
+ alignItems: 'center',
140
+ gap: textWrapGap,
141
+ width: '100%',
142
+ }
143
+
144
+ const titleStyle: TextStyle = {
145
+ color: titleColor,
146
+ fontSize: titleFontSize,
147
+ fontFamily: titleFontFamily,
148
+ lineHeight: titleLineHeight,
149
+ fontWeight: String(titleFontWeight) as TextStyle['fontWeight'],
150
+ textAlign: 'center',
151
+ }
152
+
153
+ const supportTextStyle: TextStyle = {
154
+ color: supportColor,
155
+ fontSize: supportFontSize,
156
+ fontFamily: supportFontFamily,
157
+ lineHeight: supportLineHeight,
158
+ fontWeight: String(supportFontWeight) as TextStyle['fontWeight'],
159
+ textAlign: 'center',
160
+ }
161
+
162
+ const mediaContent = useMemo(() => {
163
+ if (media === undefined || media === null) {
164
+ return (
165
+ <View
166
+ style={{
167
+ width: DEFAULT_MEDIA_SIZE,
168
+ height: DEFAULT_MEDIA_SIZE,
169
+ }}
170
+ accessibilityElementsHidden
171
+ importantForAccessibility="no-hide-descendants"
172
+ />
173
+ )
174
+ }
175
+ return cloneChildrenWithModes(media, modes)
176
+ }, [media, modes])
177
+
178
+ const buttonContent = useMemo(() => {
179
+ if (buttonSlot !== undefined && buttonSlot !== null) {
180
+ return cloneChildrenWithModes(buttonSlot, modes)
181
+ }
182
+ if (!showButton) {
183
+ return null
184
+ }
185
+ return <Button label={buttonLabel} onPress={onButtonPress} modes={modes} />
186
+ }, [buttonSlot, showButton, buttonLabel, onButtonPress, modes])
187
+
188
+ return (
189
+ <View style={[containerStyle, style]} testID={testID}>
190
+ {mediaContent}
191
+ <View style={textWrapStyle}>
192
+ <Text style={titleStyle}>{title}</Text>
193
+ {showSupportText && supportText ? (
194
+ <Text style={supportTextStyle}>{supportText}</Text>
195
+ ) : null}
196
+ {buttonContent}
197
+ </View>
198
+ </View>
199
+ )
200
+ }
201
+
202
+ export default LottieIntroBlock
@@ -0,0 +1,167 @@
1
+ import React from 'react'
2
+ import {
3
+ View,
4
+ Text,
5
+ type StyleProp,
6
+ type ViewStyle,
7
+ type TextStyle,
8
+ } from 'react-native'
9
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
10
+ import { EMPTY_MODES } from '../../utils/react-utils'
11
+
12
+ export type MetricLegendItemProps = {
13
+ /** The label text on the left (after the indicator). */
14
+ label?: React.ReactNode
15
+ /**
16
+ * The value text shown on the right. When `undefined` or `null`, the
17
+ * value slot is hidden — matching the Figma `data` boolean toggle.
18
+ */
19
+ value?: React.ReactNode
20
+ /**
21
+ * Override the indicator dot color. Falls back to the
22
+ * `metricLegendItem/indicator/bg` design token.
23
+ */
24
+ indicatorColor?: string
25
+ /** Design token modes for theming (e.g. `{ 'Color Mode': 'Light' }`). */
26
+ modes?: Record<string, any>
27
+ /** Override container styles. */
28
+ style?: StyleProp<ViewStyle>
29
+ /** Override the indicator (dot) styles. */
30
+ indicatorStyle?: StyleProp<ViewStyle>
31
+ /** Override the label text styles. */
32
+ labelStyle?: StyleProp<TextStyle>
33
+ /** Override the value text styles. */
34
+ valueStyle?: StyleProp<TextStyle>
35
+ }
36
+
37
+ /**
38
+ * MetricLegendItem renders a horizontal row consisting of a small colored
39
+ * indicator dot, a label and an optional value. It is used in chart legends
40
+ * and similar metric callouts.
41
+ *
42
+ * @component
43
+ * @param {MetricLegendItemProps} props
44
+ */
45
+ function MetricLegendItem({
46
+ label = 'Current (4 months)',
47
+ value,
48
+ indicatorColor,
49
+ modes = EMPTY_MODES,
50
+ style,
51
+ indicatorStyle,
52
+ labelStyle,
53
+ valueStyle,
54
+ }: MetricLegendItemProps) {
55
+ const gap = (getVariableByName('metricLegendItem/gap', modes) as number | null) ?? 4
56
+ const textWrapGap =
57
+ (getVariableByName('metricLegendItem/textWrap/gap', modes) as number | null) ?? 4
58
+
59
+ const indicatorSize =
60
+ (getVariableByName('metricLegendItem/indicator/size', modes) as number | null) ?? 8
61
+ const indicatorRadius =
62
+ (getVariableByName('metricLegendItem/indicator/radius', modes) as number | null) ?? 999
63
+ const indicatorBg =
64
+ indicatorColor ??
65
+ (getVariableByName('metricLegendItem/indicator/bg', modes) as string | null) ??
66
+ '#f7ab21'
67
+
68
+ const labelColor =
69
+ (getVariableByName('metricLegendItem/label/color', modes) as string | null) ?? '#000000'
70
+ const labelFontFamily =
71
+ (getVariableByName('metricLegendItem/label/fontFamily', modes) as string | null) ??
72
+ 'JioType Var'
73
+ const labelFontSize =
74
+ (getVariableByName('metricLegendItem/label/fontSize', modes) as number | null) ?? 12
75
+ const labelLineHeight =
76
+ (getVariableByName('metricLegendItem/label/lineHeight', modes) as number | null) ?? 16
77
+ const labelFontWeightRaw =
78
+ getVariableByName('metricLegendItem/label/fontWeight', modes) ?? 400
79
+ const labelFontWeight = String(labelFontWeightRaw) as TextStyle['fontWeight']
80
+
81
+ const valueColor =
82
+ (getVariableByName('metricLegendItem/value/color', modes) as string | null) ?? '#000000'
83
+ const valueFontFamily =
84
+ (getVariableByName('metricLegendItem/value/fontFamily', modes) as string | null) ??
85
+ 'JioType Var'
86
+ const valueFontSize =
87
+ (getVariableByName('metricLegendItem/value/fontSize', modes) as number | null) ?? 12
88
+ const valueLineHeight =
89
+ (getVariableByName('metricLegendItem/value/lineHeight', modes) as number | null) ?? 16
90
+ const valueFontWeightRaw =
91
+ getVariableByName('metricLegendItem/value/fontWeight', modes) ?? 500
92
+ const valueFontWeight = String(valueFontWeightRaw) as TextStyle['fontWeight']
93
+
94
+ const showValue = value !== undefined && value !== null && value !== false
95
+
96
+ return (
97
+ <View
98
+ style={[
99
+ {
100
+ flexDirection: 'row',
101
+ alignItems: 'center',
102
+ gap,
103
+ },
104
+ style,
105
+ ]}
106
+ accessibilityRole="text"
107
+ >
108
+ <View
109
+ style={[
110
+ {
111
+ width: indicatorSize,
112
+ height: indicatorSize,
113
+ borderRadius: indicatorRadius,
114
+ backgroundColor: indicatorBg,
115
+ },
116
+ indicatorStyle,
117
+ ]}
118
+ />
119
+
120
+ <View
121
+ style={{
122
+ flex: 1,
123
+ flexDirection: 'row',
124
+ alignItems: 'center',
125
+ gap: textWrapGap,
126
+ minWidth: 0,
127
+ }}
128
+ >
129
+ <Text
130
+ style={[
131
+ {
132
+ flex: 1,
133
+ color: labelColor,
134
+ fontFamily: labelFontFamily,
135
+ fontSize: labelFontSize,
136
+ lineHeight: labelLineHeight,
137
+ fontWeight: labelFontWeight,
138
+ },
139
+ labelStyle,
140
+ ]}
141
+ >
142
+ {label}
143
+ </Text>
144
+
145
+ {showValue && (
146
+ <Text
147
+ style={[
148
+ {
149
+ color: valueColor,
150
+ fontFamily: valueFontFamily,
151
+ fontSize: valueFontSize,
152
+ lineHeight: valueLineHeight,
153
+ fontWeight: valueFontWeight,
154
+ },
155
+ valueStyle,
156
+ ]}
157
+ numberOfLines={1}
158
+ >
159
+ {value}
160
+ </Text>
161
+ )}
162
+ </View>
163
+ </View>
164
+ )
165
+ }
166
+
167
+ export default MetricLegendItem