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.
- package/CHANGELOG.md +28 -0
- package/lib/commonjs/components/AccordionCheckbox/AccordionCheckbox.js +239 -0
- package/lib/commonjs/components/AccountCard/AccountCard.js +247 -0
- package/lib/commonjs/components/AppBar/AppBar.js +17 -11
- package/lib/commonjs/components/BrandChip/BrandChip.js +149 -0
- package/lib/commonjs/components/CardBankAccount/CardBankAccount.js +229 -0
- package/lib/commonjs/components/CardInsight/CardInsight.js +166 -0
- package/lib/commonjs/components/CheckboxGroup/CheckboxGroup.js +67 -0
- package/lib/commonjs/components/CheckboxItem/CheckboxItem.js +140 -0
- package/lib/commonjs/components/CircularProgressBar/CircularProgressBar.js +56 -9
- package/lib/commonjs/components/CoverageBarComparison/CoverageBarComparison.js +272 -0
- package/lib/commonjs/components/CoverageRing/CoverageRing.js +141 -0
- package/lib/commonjs/components/DonutChart/DonutChart.js +309 -0
- package/lib/commonjs/components/DonutChartSummary/DonutChartSummary.js +155 -0
- package/lib/commonjs/components/Dropdown/Dropdown.js +214 -0
- package/lib/commonjs/components/DropdownInput/DropdownInput.js +542 -0
- package/lib/commonjs/components/FormField/FormField.js +328 -178
- package/lib/commonjs/components/LinearMeter/LinearMeter.js +9 -28
- package/lib/commonjs/components/LinearProgress/LinearProgress.js +68 -0
- package/lib/commonjs/components/LottieIntroBlock/LottieIntroBlock.js +150 -0
- package/lib/commonjs/components/MetricLegendItem/MetricLegendItem.js +95 -0
- package/lib/commonjs/components/MonthlyStatusGrid/MonthlyStatusGrid.js +286 -0
- package/lib/commonjs/components/OTP/OTP.js +381 -37
- package/lib/commonjs/components/PageHero/PageHero.js +153 -0
- package/lib/commonjs/components/PoweredByLabel/PoweredByLabel.js +135 -0
- package/lib/commonjs/components/PoweredByLabel/finvu.png +0 -0
- package/lib/commonjs/components/ProductOverview/ProductOverview.js +147 -0
- package/lib/commonjs/components/RangeTrack/RangeTrack.js +269 -0
- package/lib/commonjs/components/SavingsGoalSummary/SavingsGoalSummary.js +181 -0
- package/lib/commonjs/components/SegmentedTrack/SegmentedTrack.js +171 -0
- package/lib/commonjs/components/StatGroup/StatGroup.js +128 -0
- package/lib/commonjs/components/StatItem/StatItem.js +65 -35
- package/lib/commonjs/components/StrengthIndicator/StrengthIndicator.js +157 -0
- package/lib/commonjs/components/SummaryTile/SummaryTile.js +150 -0
- package/lib/commonjs/components/Text/Text.js +9 -2
- package/lib/commonjs/components/Tooltip/Tooltip.js +34 -27
- package/lib/commonjs/components/index.js +231 -1
- package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
- package/lib/commonjs/icons/registry.js +1 -1
- package/lib/commonjs/utils/index.js +7 -0
- package/lib/commonjs/utils/number-utils.js +57 -0
- package/lib/module/components/AccordionCheckbox/AccordionCheckbox.js +233 -0
- package/lib/module/components/AccountCard/AccountCard.js +241 -0
- package/lib/module/components/AppBar/AppBar.js +17 -11
- package/lib/module/components/BrandChip/BrandChip.js +143 -0
- package/lib/module/components/CardBankAccount/CardBankAccount.js +223 -0
- package/lib/module/components/CardInsight/CardInsight.js +161 -0
- package/lib/module/components/CheckboxGroup/CheckboxGroup.js +62 -0
- package/lib/module/components/CheckboxItem/CheckboxItem.js +134 -0
- package/lib/module/components/CircularProgressBar/CircularProgressBar.js +56 -9
- package/lib/module/components/CoverageBarComparison/CoverageBarComparison.js +266 -0
- package/lib/module/components/CoverageRing/CoverageRing.js +136 -0
- package/lib/module/components/DonutChart/DonutChart.js +303 -0
- package/lib/module/components/DonutChartSummary/DonutChartSummary.js +150 -0
- package/lib/module/components/Dropdown/Dropdown.js +206 -0
- package/lib/module/components/DropdownInput/DropdownInput.js +536 -0
- package/lib/module/components/FormField/FormField.js +330 -180
- package/lib/module/components/LinearMeter/LinearMeter.js +9 -28
- package/lib/module/components/LinearProgress/LinearProgress.js +63 -0
- package/lib/module/components/LottieIntroBlock/LottieIntroBlock.js +144 -0
- package/lib/module/components/MetricLegendItem/MetricLegendItem.js +90 -0
- package/lib/module/components/MonthlyStatusGrid/MonthlyStatusGrid.js +281 -0
- package/lib/module/components/OTP/OTP.js +381 -38
- package/lib/module/components/PageHero/PageHero.js +147 -0
- package/lib/module/components/PoweredByLabel/PoweredByLabel.js +130 -0
- package/lib/module/components/PoweredByLabel/finvu.png +0 -0
- package/lib/module/components/ProductOverview/ProductOverview.js +142 -0
- package/lib/module/components/RangeTrack/RangeTrack.js +263 -0
- package/lib/module/components/SavingsGoalSummary/SavingsGoalSummary.js +175 -0
- package/lib/module/components/SegmentedTrack/SegmentedTrack.js +166 -0
- package/lib/module/components/StatGroup/StatGroup.js +123 -0
- package/lib/module/components/StatItem/StatItem.js +66 -36
- package/lib/module/components/StrengthIndicator/StrengthIndicator.js +152 -0
- package/lib/module/components/SummaryTile/SummaryTile.js +145 -0
- package/lib/module/components/Text/Text.js +9 -2
- package/lib/module/components/Tooltip/Tooltip.js +34 -27
- package/lib/module/components/index.js +28 -2
- package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
- package/lib/module/icons/registry.js +1 -1
- package/lib/module/utils/index.js +2 -1
- package/lib/module/utils/number-utils.js +53 -0
- package/lib/typescript/src/components/AccordionCheckbox/AccordionCheckbox.d.ts +71 -0
- package/lib/typescript/src/components/AccountCard/AccountCard.d.ts +81 -0
- package/lib/typescript/src/components/BrandChip/BrandChip.d.ts +43 -0
- package/lib/typescript/src/components/CardBankAccount/CardBankAccount.d.ts +86 -0
- package/lib/typescript/src/components/CardInsight/CardInsight.d.ts +48 -0
- package/lib/typescript/src/components/CheckboxGroup/CheckboxGroup.d.ts +41 -0
- package/lib/typescript/src/components/CheckboxItem/CheckboxItem.d.ts +72 -0
- package/lib/typescript/src/components/CircularProgressBar/CircularProgressBar.d.ts +11 -1
- package/lib/typescript/src/components/CoverageBarComparison/CoverageBarComparison.d.ts +105 -0
- package/lib/typescript/src/components/CoverageRing/CoverageRing.d.ts +90 -0
- package/lib/typescript/src/components/DonutChart/DonutChart.d.ts +117 -0
- package/lib/typescript/src/components/DonutChartSummary/DonutChartSummary.d.ts +103 -0
- package/lib/typescript/src/components/Dropdown/Dropdown.d.ts +62 -0
- package/lib/typescript/src/components/DropdownInput/DropdownInput.d.ts +107 -0
- package/lib/typescript/src/components/FormField/FormField.d.ts +76 -19
- package/lib/typescript/src/components/LinearProgress/LinearProgress.d.ts +17 -0
- package/lib/typescript/src/components/LottieIntroBlock/LottieIntroBlock.d.ts +58 -0
- package/lib/typescript/src/components/MetricLegendItem/MetricLegendItem.d.ts +37 -0
- package/lib/typescript/src/components/MonthlyStatusGrid/MonthlyStatusGrid.d.ts +119 -0
- package/lib/typescript/src/components/OTP/OTP.d.ts +88 -2
- package/lib/typescript/src/components/PageHero/PageHero.d.ts +53 -0
- package/lib/typescript/src/components/PoweredByLabel/PoweredByLabel.d.ts +70 -0
- package/lib/typescript/src/components/ProductOverview/ProductOverview.d.ts +39 -0
- package/lib/typescript/src/components/RangeTrack/RangeTrack.d.ts +173 -0
- package/lib/typescript/src/components/SavingsGoalSummary/SavingsGoalSummary.d.ts +95 -0
- package/lib/typescript/src/components/SegmentedTrack/SegmentedTrack.d.ts +108 -0
- package/lib/typescript/src/components/StatGroup/StatGroup.d.ts +45 -0
- package/lib/typescript/src/components/StatItem/StatItem.d.ts +24 -7
- package/lib/typescript/src/components/StrengthIndicator/StrengthIndicator.d.ts +58 -0
- package/lib/typescript/src/components/SummaryTile/SummaryTile.d.ts +60 -0
- package/lib/typescript/src/components/Text/Text.d.ts +12 -2
- package/lib/typescript/src/components/Tooltip/Tooltip.d.ts +13 -2
- package/lib/typescript/src/components/index.d.ts +29 -3
- package/lib/typescript/src/icons/registry.d.ts +1 -1
- package/lib/typescript/src/utils/index.d.ts +1 -0
- package/lib/typescript/src/utils/number-utils.d.ts +29 -0
- package/package.json +1 -3
- package/src/components/AccordionCheckbox/AccordionCheckbox.tsx +323 -0
- package/src/components/AccountCard/AccountCard.tsx +376 -0
- package/src/components/AppBar/AppBar.tsx +25 -14
- package/src/components/BrandChip/BrandChip.tsx +235 -0
- package/src/components/CardBankAccount/CardBankAccount.tsx +321 -0
- package/src/components/CardInsight/CardInsight.tsx +239 -0
- package/src/components/CheckboxGroup/CheckboxGroup.tsx +86 -0
- package/src/components/CheckboxItem/CheckboxItem.tsx +209 -0
- package/src/components/CircularProgressBar/CircularProgressBar.tsx +74 -9
- package/src/components/CoverageBarComparison/CoverageBarComparison.tsx +378 -0
- package/src/components/CoverageRing/CoverageRing.tsx +225 -0
- package/src/components/DonutChart/DonutChart.tsx +503 -0
- package/src/components/DonutChartSummary/DonutChartSummary.tsx +256 -0
- package/src/components/Dropdown/Dropdown.tsx +331 -0
- package/src/components/DropdownInput/DropdownInput.tsx +819 -0
- package/src/components/FormField/FormField.tsx +542 -215
- package/src/components/LinearMeter/LinearMeter.tsx +9 -39
- package/src/components/LinearProgress/LinearProgress.tsx +92 -0
- package/src/components/LottieIntroBlock/LottieIntroBlock.tsx +202 -0
- package/src/components/MetricLegendItem/MetricLegendItem.tsx +167 -0
- package/src/components/MonthlyStatusGrid/MonthlyStatusGrid.tsx +438 -0
- package/src/components/OTP/OTP.tsx +476 -29
- package/src/components/PageHero/PageHero.tsx +200 -0
- package/src/components/PoweredByLabel/PoweredByLabel.tsx +221 -0
- package/src/components/PoweredByLabel/finvu.png +0 -0
- package/src/components/ProductOverview/ProductOverview.tsx +236 -0
- package/src/components/RangeTrack/RangeTrack.tsx +394 -0
- package/src/components/SavingsGoalSummary/SavingsGoalSummary.tsx +269 -0
- package/src/components/SegmentedTrack/SegmentedTrack.tsx +268 -0
- package/src/components/StatGroup/StatGroup.tsx +169 -0
- package/src/components/StatItem/StatItem.tsx +117 -40
- package/src/components/StrengthIndicator/StrengthIndicator.tsx +205 -0
- package/src/components/SummaryTile/SummaryTile.tsx +251 -0
- package/src/components/Text/Text.tsx +24 -3
- package/src/components/Tooltip/Tooltip.tsx +50 -25
- package/src/components/index.ts +47 -3
- package/src/design-tokens/Coin Variables-variables-full.json +1 -1
- package/src/icons/registry.ts +1 -1
- package/src/utils/index.ts +1 -0
- 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
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|