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
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import React, { useCallback, useState } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
Text,
|
|
5
|
+
Pressable,
|
|
6
|
+
LayoutAnimation,
|
|
7
|
+
Platform,
|
|
8
|
+
UIManager,
|
|
9
|
+
type StyleProp,
|
|
10
|
+
type ViewStyle,
|
|
11
|
+
type TextStyle,
|
|
12
|
+
} from 'react-native'
|
|
13
|
+
import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
|
|
14
|
+
import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils'
|
|
15
|
+
import Checkbox from '../Checkbox/Checkbox'
|
|
16
|
+
import Divider from '../Divider/Divider'
|
|
17
|
+
import Icon from '../../icons/Icon'
|
|
18
|
+
|
|
19
|
+
if (Platform.OS === 'android' && UIManager.setLayoutAnimationEnabledExperimental) {
|
|
20
|
+
UIManager.setLayoutAnimationEnabledExperimental(true)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type AccordionCheckboxProps = {
|
|
24
|
+
/** Title shown next to the checkbox (e.g. "Axis Bank"). */
|
|
25
|
+
title?: string
|
|
26
|
+
/** Subtitle shown beneath the title (e.g. "3 accounts"). */
|
|
27
|
+
subtitle?: string
|
|
28
|
+
/** Initial expanded state (uncontrolled). Defaults to `false`. */
|
|
29
|
+
defaultExpanded?: boolean
|
|
30
|
+
/** Controlled expanded state. When provided, the component becomes controlled. */
|
|
31
|
+
expanded?: boolean
|
|
32
|
+
/** Callback fired whenever the expanded state changes. */
|
|
33
|
+
onExpandedChange?: (expanded: boolean) => void
|
|
34
|
+
/** Initial checked state of the header checkbox (uncontrolled). */
|
|
35
|
+
defaultChecked?: boolean
|
|
36
|
+
/** Controlled checked state of the header checkbox. */
|
|
37
|
+
checked?: boolean
|
|
38
|
+
/** Callback fired whenever the header checkbox value changes. */
|
|
39
|
+
onCheckedChange?: (checked: boolean) => void
|
|
40
|
+
/** Disables the entire component (header press + checkbox + content). */
|
|
41
|
+
disabled?: boolean
|
|
42
|
+
/**
|
|
43
|
+
* Slot — content rendered below the divider when expanded. Typically a
|
|
44
|
+
* `CheckboxGroup` of child `CheckboxItem`s. The `modes` prop is forwarded
|
|
45
|
+
* recursively to every child.
|
|
46
|
+
*/
|
|
47
|
+
children?: React.ReactNode
|
|
48
|
+
/** Design token modes for theming (e.g. `{ 'Color Mode': 'Light' }`). */
|
|
49
|
+
modes?: Record<string, any>
|
|
50
|
+
/** Override outer container styles. */
|
|
51
|
+
style?: StyleProp<ViewStyle>
|
|
52
|
+
/** Accessibility label for the header press target. Defaults to `title`. */
|
|
53
|
+
accessibilityLabel?: string
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* AccordionCheckbox composes a header (with a `Checkbox`, title, subtitle and
|
|
58
|
+
* chevron) and a collapsible content slot. It mirrors the Figma
|
|
59
|
+
* "Accordion Checkbox" component.
|
|
60
|
+
*
|
|
61
|
+
* Two independent interactions live inside the header:
|
|
62
|
+
* - **Pressing the checkbox** toggles the parent checked state via
|
|
63
|
+
* `onCheckedChange` (typically used for "select all" behaviour).
|
|
64
|
+
* - **Pressing anywhere else on the header** toggles the expanded state via
|
|
65
|
+
* `onExpandedChange`.
|
|
66
|
+
*
|
|
67
|
+
* When expanded, a divider is shown and `children` are rendered with `modes`
|
|
68
|
+
* automatically forwarded through `cloneChildrenWithModes`.
|
|
69
|
+
*
|
|
70
|
+
* @component
|
|
71
|
+
* @param {AccordionCheckboxProps} props
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```tsx
|
|
75
|
+
* <AccordionCheckbox
|
|
76
|
+
* title="Axis Bank"
|
|
77
|
+
* subtitle="3 accounts"
|
|
78
|
+
* defaultExpanded
|
|
79
|
+
* defaultChecked
|
|
80
|
+
* modes={{ 'Color Mode': 'Light' }}
|
|
81
|
+
* >
|
|
82
|
+
* <CheckboxGroup>
|
|
83
|
+
* <CheckboxItem label="Fixed deposit • 0245" />
|
|
84
|
+
* <CheckboxItem label="Recurring deposit • 1182" />
|
|
85
|
+
* <CheckboxItem label="Mutual fund • Equity" />
|
|
86
|
+
* </CheckboxGroup>
|
|
87
|
+
* </AccordionCheckbox>
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
function AccordionCheckbox({
|
|
91
|
+
title = 'Axis Bank',
|
|
92
|
+
subtitle = '3 accounts',
|
|
93
|
+
defaultExpanded = false,
|
|
94
|
+
expanded: controlledExpanded,
|
|
95
|
+
onExpandedChange,
|
|
96
|
+
defaultChecked = false,
|
|
97
|
+
checked: controlledChecked,
|
|
98
|
+
onCheckedChange,
|
|
99
|
+
disabled = false,
|
|
100
|
+
children,
|
|
101
|
+
modes = EMPTY_MODES,
|
|
102
|
+
style,
|
|
103
|
+
accessibilityLabel,
|
|
104
|
+
}: AccordionCheckboxProps) {
|
|
105
|
+
const isExpandedControlled = controlledExpanded !== undefined
|
|
106
|
+
const [internalExpanded, setInternalExpanded] = useState(defaultExpanded)
|
|
107
|
+
const isExpanded = isExpandedControlled ? controlledExpanded : internalExpanded
|
|
108
|
+
|
|
109
|
+
const isCheckedControlled = controlledChecked !== undefined
|
|
110
|
+
const [internalChecked, setInternalChecked] = useState(defaultChecked)
|
|
111
|
+
const isChecked = isCheckedControlled ? controlledChecked : internalChecked
|
|
112
|
+
|
|
113
|
+
const handleToggleExpanded = useCallback(() => {
|
|
114
|
+
if (disabled) return
|
|
115
|
+
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
|
|
116
|
+
const next = !isExpanded
|
|
117
|
+
if (!isExpandedControlled) {
|
|
118
|
+
setInternalExpanded(next)
|
|
119
|
+
}
|
|
120
|
+
onExpandedChange?.(next)
|
|
121
|
+
}, [disabled, isExpanded, isExpandedControlled, onExpandedChange])
|
|
122
|
+
|
|
123
|
+
const handleToggleChecked = useCallback(
|
|
124
|
+
(next: boolean) => {
|
|
125
|
+
if (disabled) return
|
|
126
|
+
if (!isCheckedControlled) {
|
|
127
|
+
setInternalChecked(next)
|
|
128
|
+
}
|
|
129
|
+
onCheckedChange?.(next)
|
|
130
|
+
},
|
|
131
|
+
[disabled, isCheckedControlled, onCheckedChange]
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
const background =
|
|
135
|
+
(getVariableByName('accordionCheckbox/background', modes) as string | null) ?? '#ffffff'
|
|
136
|
+
const radius = (getVariableByName('accordionCheckbox/radius', modes) as number | null) ?? 12
|
|
137
|
+
const paddingHorizontal =
|
|
138
|
+
(getVariableByName('accordionCheckbox/padding/horizontal', modes) as number | null) ?? 12
|
|
139
|
+
const paddingVertical =
|
|
140
|
+
(getVariableByName('accordionCheckbox/padding/vertical', modes) as number | null) ?? 16
|
|
141
|
+
const containerGap =
|
|
142
|
+
(getVariableByName('accordionCheckbox/gap', modes) as number | null) ?? 12
|
|
143
|
+
const borderColor =
|
|
144
|
+
(getVariableByName('accordionCheckbox/border/color', modes) as string | null) ?? '#ebebed'
|
|
145
|
+
const borderSize =
|
|
146
|
+
(getVariableByName('accordionCheckbox/border/size', modes) as number | null) ?? 1
|
|
147
|
+
|
|
148
|
+
const headerGap =
|
|
149
|
+
(getVariableByName('accordionCheckbox/header/gap', modes) as number | null) ?? 12
|
|
150
|
+
const headerPaddingHorizontal =
|
|
151
|
+
(getVariableByName('accordionCheckbox/header/padding/horizontal', modes) as number | null) ?? 0
|
|
152
|
+
const headerPaddingVertical =
|
|
153
|
+
(getVariableByName('accordionCheckbox/header/padding/vertical', modes) as number | null) ?? 0
|
|
154
|
+
const headerWrapGap =
|
|
155
|
+
(getVariableByName('accordionCheckbox/header/wrap/gap', modes) as number | null) ?? 12
|
|
156
|
+
|
|
157
|
+
const textWrapGap =
|
|
158
|
+
(getVariableByName('accordionCheckbox/textWrap/gap', modes) as number | null) ?? 2
|
|
159
|
+
|
|
160
|
+
const titleColor =
|
|
161
|
+
(getVariableByName('accordionCheckbox/title/color', modes) as string | null) ?? '#000000'
|
|
162
|
+
const titleFontSize =
|
|
163
|
+
(getVariableByName('accordionCheckbox/title/fontSize', modes) as number | null) ?? 14
|
|
164
|
+
const titleFontFamily =
|
|
165
|
+
(getVariableByName('accordionCheckbox/title/fontFamily', modes) as string | null) ?? 'JioType Var'
|
|
166
|
+
const titleLineHeight =
|
|
167
|
+
(getVariableByName('accordionCheckbox/title/lineHeight', modes) as number | null) ?? 18
|
|
168
|
+
const titleFontWeightRaw =
|
|
169
|
+
getVariableByName('accordionCheckbox/title/fontWeight', modes) ?? 600
|
|
170
|
+
const titleFontWeight = String(titleFontWeightRaw) as TextStyle['fontWeight']
|
|
171
|
+
|
|
172
|
+
const subtitleColor =
|
|
173
|
+
(getVariableByName('accordionCheckbox/subtitle/color', modes) as string | null) ?? '#23190a'
|
|
174
|
+
const subtitleFontSize =
|
|
175
|
+
(getVariableByName('accordionCheckbox/subtitle/fontSize', modes) as number | null) ?? 12
|
|
176
|
+
const subtitleFontFamily =
|
|
177
|
+
(getVariableByName('accordionCheckbox/subtitle/fontFamily', modes) as string | null) ?? 'JioType Var'
|
|
178
|
+
const subtitleLineHeight =
|
|
179
|
+
(getVariableByName('accordionCheckbox/subtitle/lineHeight', modes) as number | null) ?? 16
|
|
180
|
+
const subtitleFontWeightRaw =
|
|
181
|
+
getVariableByName('accordionCheckbox/subtitle/fontWeight', modes) ?? 500
|
|
182
|
+
const subtitleFontWeight = String(subtitleFontWeightRaw) as TextStyle['fontWeight']
|
|
183
|
+
|
|
184
|
+
const iconColor =
|
|
185
|
+
(getVariableByName('accordionCheckbox/icon/color', modes) as string | null) ?? '#000000'
|
|
186
|
+
const iconSize =
|
|
187
|
+
(getVariableByName('accordionCheckbox/icon/size', modes) as number | null) ?? 24
|
|
188
|
+
|
|
189
|
+
const contentGap =
|
|
190
|
+
(getVariableByName('accordionCheckbox/content/gap', modes) as number | null) ?? 0
|
|
191
|
+
const contentPaddingTop =
|
|
192
|
+
(getVariableByName('accordionCheckbox/content/padding/top', modes) as number | null) ?? 8
|
|
193
|
+
const contentPaddingBottom =
|
|
194
|
+
(getVariableByName('accordionCheckbox/content/padding/bottom', modes) as number | null) ?? 0
|
|
195
|
+
const contentPaddingHorizontal =
|
|
196
|
+
(getVariableByName('accordionCheckbox/content/padding/horizontal', modes) as number | null) ?? 0
|
|
197
|
+
|
|
198
|
+
const containerStyle: ViewStyle = {
|
|
199
|
+
backgroundColor: background,
|
|
200
|
+
borderRadius: radius,
|
|
201
|
+
paddingHorizontal,
|
|
202
|
+
paddingVertical,
|
|
203
|
+
flexDirection: 'column',
|
|
204
|
+
alignItems: 'stretch',
|
|
205
|
+
gap: containerGap,
|
|
206
|
+
overflow: 'hidden',
|
|
207
|
+
...(isExpanded
|
|
208
|
+
? { borderWidth: borderSize, borderColor }
|
|
209
|
+
: null),
|
|
210
|
+
...(disabled ? { opacity: 0.6 } : null),
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const headerStyle: ViewStyle = {
|
|
214
|
+
flexDirection: 'row',
|
|
215
|
+
alignItems: 'center',
|
|
216
|
+
gap: headerGap,
|
|
217
|
+
paddingHorizontal: headerPaddingHorizontal,
|
|
218
|
+
paddingVertical: headerPaddingVertical,
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const wrapStyle: ViewStyle = {
|
|
222
|
+
flex: 1,
|
|
223
|
+
minWidth: 0,
|
|
224
|
+
flexDirection: 'row',
|
|
225
|
+
alignItems: 'center',
|
|
226
|
+
gap: headerWrapGap,
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const textWrapStyle: ViewStyle = {
|
|
230
|
+
flex: 1,
|
|
231
|
+
minWidth: 0,
|
|
232
|
+
flexDirection: 'column',
|
|
233
|
+
alignItems: 'flex-start',
|
|
234
|
+
gap: textWrapGap,
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const titleStyle: TextStyle = {
|
|
238
|
+
color: titleColor,
|
|
239
|
+
fontSize: titleFontSize,
|
|
240
|
+
lineHeight: titleLineHeight,
|
|
241
|
+
fontFamily: titleFontFamily,
|
|
242
|
+
fontWeight: titleFontWeight,
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const subtitleStyle: TextStyle = {
|
|
246
|
+
color: subtitleColor,
|
|
247
|
+
fontSize: subtitleFontSize,
|
|
248
|
+
lineHeight: subtitleLineHeight,
|
|
249
|
+
fontFamily: subtitleFontFamily,
|
|
250
|
+
fontWeight: subtitleFontWeight,
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const contentStyle: ViewStyle = {
|
|
254
|
+
flexDirection: 'column',
|
|
255
|
+
alignItems: 'stretch',
|
|
256
|
+
justifyContent: 'center',
|
|
257
|
+
gap: contentGap,
|
|
258
|
+
paddingTop: contentPaddingTop,
|
|
259
|
+
paddingBottom: contentPaddingBottom,
|
|
260
|
+
paddingHorizontal: contentPaddingHorizontal,
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const a11yLabel = accessibilityLabel ?? title
|
|
264
|
+
|
|
265
|
+
return (
|
|
266
|
+
<View style={[containerStyle, style]}>
|
|
267
|
+
<Pressable
|
|
268
|
+
onPress={handleToggleExpanded}
|
|
269
|
+
disabled={disabled}
|
|
270
|
+
accessibilityRole="button"
|
|
271
|
+
accessibilityState={{ expanded: isExpanded, disabled }}
|
|
272
|
+
accessibilityLabel={a11yLabel}
|
|
273
|
+
accessibilityHint={isExpanded ? 'Collapse' : 'Expand'}
|
|
274
|
+
style={({ pressed }) => [
|
|
275
|
+
headerStyle,
|
|
276
|
+
pressed && !disabled ? { opacity: 0.9 } : null,
|
|
277
|
+
]}
|
|
278
|
+
>
|
|
279
|
+
<View style={wrapStyle}>
|
|
280
|
+
<Checkbox
|
|
281
|
+
checked={isChecked}
|
|
282
|
+
onValueChange={handleToggleChecked}
|
|
283
|
+
disabled={disabled}
|
|
284
|
+
modes={modes}
|
|
285
|
+
accessibilityLabel={
|
|
286
|
+
typeof title === 'string' ? `Select ${title}` : undefined
|
|
287
|
+
}
|
|
288
|
+
/>
|
|
289
|
+
<View style={textWrapStyle}>
|
|
290
|
+
<Text style={titleStyle} numberOfLines={1} selectable={false}>
|
|
291
|
+
{title}
|
|
292
|
+
</Text>
|
|
293
|
+
{subtitle ? (
|
|
294
|
+
<Text style={subtitleStyle} numberOfLines={1} selectable={false}>
|
|
295
|
+
{subtitle}
|
|
296
|
+
</Text>
|
|
297
|
+
) : null}
|
|
298
|
+
</View>
|
|
299
|
+
</View>
|
|
300
|
+
<Icon
|
|
301
|
+
name={isExpanded ? 'ic_chevron_up' : 'ic_chevron_down'}
|
|
302
|
+
size={iconSize}
|
|
303
|
+
color={iconColor}
|
|
304
|
+
accessibilityElementsHidden={true}
|
|
305
|
+
importantForAccessibility="no"
|
|
306
|
+
/>
|
|
307
|
+
</Pressable>
|
|
308
|
+
|
|
309
|
+
{isExpanded ? (
|
|
310
|
+
<>
|
|
311
|
+
<Divider modes={modes} />
|
|
312
|
+
{children ? (
|
|
313
|
+
<View style={contentStyle}>
|
|
314
|
+
{cloneChildrenWithModes(children, modes)}
|
|
315
|
+
</View>
|
|
316
|
+
) : null}
|
|
317
|
+
</>
|
|
318
|
+
) : null}
|
|
319
|
+
</View>
|
|
320
|
+
)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export default AccordionCheckbox
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import React, { useCallback, useMemo, useRef } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
Image as RNImage,
|
|
4
|
+
Platform,
|
|
5
|
+
Pressable,
|
|
6
|
+
Text,
|
|
7
|
+
View,
|
|
8
|
+
type ImageSourcePropType,
|
|
9
|
+
type ImageStyle,
|
|
10
|
+
type PressableStateCallbackType,
|
|
11
|
+
type StyleProp,
|
|
12
|
+
type TextStyle,
|
|
13
|
+
type ViewStyle,
|
|
14
|
+
} from 'react-native'
|
|
15
|
+
import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
|
|
16
|
+
import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils'
|
|
17
|
+
import Icon from '../../icons/Icon'
|
|
18
|
+
|
|
19
|
+
const IS_IOS = Platform.OS === 'ios'
|
|
20
|
+
const PRESS_DELAY = IS_IOS ? 130 : 0
|
|
21
|
+
const DEFAULT_IMAGE_RATIO = 125 / 82
|
|
22
|
+
|
|
23
|
+
const pressedOverlayStyle: ViewStyle = { opacity: 0.7 }
|
|
24
|
+
|
|
25
|
+
// Default modes for the "Add" placeholder icon (`iconButton/*` tokens).
|
|
26
|
+
// Caller-supplied `modes` are merged on top so every key here can be overridden.
|
|
27
|
+
const ADD_ICON_DEFAULT_MODES: Readonly<Record<string, any>> = Object.freeze({
|
|
28
|
+
AppearanceBrand: 'Secondary',
|
|
29
|
+
Emphasis: 'Low',
|
|
30
|
+
"Button / Size": "M",
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
export type AccountCardState = 'connected' | 'add'
|
|
34
|
+
|
|
35
|
+
export type AccountCardProps = {
|
|
36
|
+
/**
|
|
37
|
+
* Visual variant of the card.
|
|
38
|
+
* - `'connected'` (default): renders a card preview image, a `title` and a
|
|
39
|
+
* `subtitle` below it (e.g. account name + masked number).
|
|
40
|
+
* - `'add'`: renders an empty placeholder field with a centred `+` icon
|
|
41
|
+
* and only the `title`. Use this for the "Add new account" affordance
|
|
42
|
+
* that pairs with a list of connected `AccountCard`s.
|
|
43
|
+
*/
|
|
44
|
+
state?: AccountCardState
|
|
45
|
+
/** Title rendered below the image / placeholder. */
|
|
46
|
+
title?: string
|
|
47
|
+
/**
|
|
48
|
+
* Subtitle rendered below the title (e.g. masked account number).
|
|
49
|
+
* Only displayed when `state === 'connected'`.
|
|
50
|
+
*/
|
|
51
|
+
subtitle?: string
|
|
52
|
+
/**
|
|
53
|
+
* Card preview image. Only used when `state === 'connected'` and
|
|
54
|
+
* `cardSlot` is not provided. Accepts a URL string or any
|
|
55
|
+
* `ImageSourcePropType` (e.g. `require('./card.png')`).
|
|
56
|
+
*/
|
|
57
|
+
imageSource?: ImageSourcePropType | string
|
|
58
|
+
/**
|
|
59
|
+
* Aspect ratio (width / height) of the image / placeholder area.
|
|
60
|
+
* Defaults to the Figma reference ratio (`125 / 82` ≈ `1.524`).
|
|
61
|
+
*/
|
|
62
|
+
imageRatio?: number
|
|
63
|
+
/**
|
|
64
|
+
* Override the entire image / placeholder area with a custom node
|
|
65
|
+
* (e.g. a smaller `DebitCard`, a brand logo, a remote image).
|
|
66
|
+
* Receives `modes` automatically through `cloneChildrenWithModes`.
|
|
67
|
+
*/
|
|
68
|
+
cardSlot?: React.ReactNode
|
|
69
|
+
/**
|
|
70
|
+
* Icon name shown inside the "Add" placeholder. Defaults to `'ic_add'`.
|
|
71
|
+
* Only used when `state === 'add'`.
|
|
72
|
+
*/
|
|
73
|
+
addIcon?: string
|
|
74
|
+
/**
|
|
75
|
+
* Press handler. Applied to the whole card so the entire surface is a
|
|
76
|
+
* single touch target — particularly important for the `'add'` state,
|
|
77
|
+
* which behaves like a button.
|
|
78
|
+
*/
|
|
79
|
+
onPress?: () => void
|
|
80
|
+
/** Disable interaction (also dims the card). */
|
|
81
|
+
disabled?: boolean
|
|
82
|
+
/** Design token modes (e.g. `{ 'Color Mode': 'Light' }`). */
|
|
83
|
+
modes?: Record<string, any>
|
|
84
|
+
/** Container style override. */
|
|
85
|
+
style?: StyleProp<ViewStyle>
|
|
86
|
+
/** Accessibility label (defaults to `title`). */
|
|
87
|
+
accessibilityLabel?: string
|
|
88
|
+
/** Accessibility hint forwarded to the underlying `Pressable`. */
|
|
89
|
+
accessibilityHint?: string
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const toNumber = (value: unknown, fallback: number): number => {
|
|
93
|
+
if (typeof value === 'number') return Number.isFinite(value) ? value : fallback
|
|
94
|
+
if (typeof value === 'string') {
|
|
95
|
+
const parsed = Number(value)
|
|
96
|
+
return Number.isFinite(parsed) ? parsed : fallback
|
|
97
|
+
}
|
|
98
|
+
return fallback
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const toFontWeight = (
|
|
102
|
+
value: unknown,
|
|
103
|
+
fallback: TextStyle['fontWeight']
|
|
104
|
+
): TextStyle['fontWeight'] => {
|
|
105
|
+
if (typeof value === 'number') return String(value) as TextStyle['fontWeight']
|
|
106
|
+
if (typeof value === 'string') return value as TextStyle['fontWeight']
|
|
107
|
+
return fallback
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const normalizeImageSource = (
|
|
111
|
+
src: AccountCardProps['imageSource']
|
|
112
|
+
): ImageSourcePropType | undefined => {
|
|
113
|
+
if (src == null) return undefined
|
|
114
|
+
if (typeof src === 'string') return { uri: src }
|
|
115
|
+
return src
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* `AccountCard` — a compact card preview used to represent a linked
|
|
120
|
+
* financial account in lists / grids.
|
|
121
|
+
*
|
|
122
|
+
* Two visual states are supported via the `state` prop:
|
|
123
|
+
*
|
|
124
|
+
* 1. `'connected'` (default): renders a small card-art preview, a bold
|
|
125
|
+
* `title` and a regular-weight `subtitle` (e.g. masked account number).
|
|
126
|
+
* 2. `'add'`: renders a soft-tinted placeholder field with a centred `+`
|
|
127
|
+
* icon and the `title` underneath, intended as the "add new account"
|
|
128
|
+
* entry-point at the end of a list of connected accounts.
|
|
129
|
+
*
|
|
130
|
+
* All values resolve through the `accountCard/*` design tokens with
|
|
131
|
+
* sensible Figma defaults so the card renders correctly out of the box.
|
|
132
|
+
*
|
|
133
|
+
* @component
|
|
134
|
+
* @param {AccountCardProps} props
|
|
135
|
+
*/
|
|
136
|
+
function AccountCard({
|
|
137
|
+
state = 'connected',
|
|
138
|
+
title = 'Personal account',
|
|
139
|
+
subtitle = '**** 5651',
|
|
140
|
+
imageSource,
|
|
141
|
+
imageRatio = DEFAULT_IMAGE_RATIO,
|
|
142
|
+
cardSlot,
|
|
143
|
+
addIcon = 'ic_add',
|
|
144
|
+
onPress,
|
|
145
|
+
disabled = false,
|
|
146
|
+
modes = EMPTY_MODES,
|
|
147
|
+
style,
|
|
148
|
+
accessibilityLabel,
|
|
149
|
+
accessibilityHint,
|
|
150
|
+
}: AccountCardProps) {
|
|
151
|
+
const iconModes = useMemo(
|
|
152
|
+
() =>
|
|
153
|
+
modes === EMPTY_MODES
|
|
154
|
+
? ADD_ICON_DEFAULT_MODES
|
|
155
|
+
: { ...ADD_ICON_DEFAULT_MODES, ...modes },
|
|
156
|
+
[modes],
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
// ---- Tokens ---------------------------------------------------------
|
|
160
|
+
const gap = toNumber(getVariableByName('accountCard/gap', modes), 8)
|
|
161
|
+
const textWrapGap = toNumber(getVariableByName('accountCard/textWrap/gap', modes), 0)
|
|
162
|
+
|
|
163
|
+
const titleColor =
|
|
164
|
+
(getVariableByName('accountCard/title/foreground', modes) as string | null) ?? '#0d0d0f'
|
|
165
|
+
const titleFontFamily =
|
|
166
|
+
(getVariableByName('accountCard/title/fontFamily', modes) as string | null) ?? 'JioType Var'
|
|
167
|
+
const titleFontSize = toNumber(getVariableByName('accountCard/title/fontSize', modes), 12)
|
|
168
|
+
const titleLineHeight = toNumber(getVariableByName('accountCard/title/lineHeight', modes), 16)
|
|
169
|
+
const titleFontWeight = toFontWeight(
|
|
170
|
+
getVariableByName('accountCard/title/fontWeight', modes),
|
|
171
|
+
'700'
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
const subtitleColor =
|
|
175
|
+
(getVariableByName('accountCard/subtitle/foreground', modes) as string | null) ?? '#24262b'
|
|
176
|
+
const subtitleFontFamily =
|
|
177
|
+
(getVariableByName('accountCard/subtitle/fontFamily', modes) as string | null) ??
|
|
178
|
+
'JioType Var'
|
|
179
|
+
const subtitleFontSize = toNumber(
|
|
180
|
+
getVariableByName('accountCard/subtitle/fontSize', modes),
|
|
181
|
+
12
|
|
182
|
+
)
|
|
183
|
+
const subtitleLineHeight = toNumber(
|
|
184
|
+
getVariableByName('accountCard/subtitle/lineHeight', modes),
|
|
185
|
+
16
|
|
186
|
+
)
|
|
187
|
+
const subtitleFontWeight = toFontWeight(
|
|
188
|
+
getVariableByName('accountCard/subtitle/fontWeight', modes),
|
|
189
|
+
'400'
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
const addFieldRadius = toNumber(
|
|
193
|
+
getVariableByName('accountCard/addItemField/radius', modes),
|
|
194
|
+
8
|
|
195
|
+
)
|
|
196
|
+
const addFieldBg =
|
|
197
|
+
(getVariableByName('accountCard/addItemField/bg', modes) as string | null) ?? '#ede8ff'
|
|
198
|
+
|
|
199
|
+
const addIconColor =
|
|
200
|
+
(getVariableByName('iconButton/icon/color', iconModes) as string | null) ?? '#5d00b5'
|
|
201
|
+
const addIconSize = toNumber(getVariableByName('iconButton/icon/size', iconModes), 16)
|
|
202
|
+
|
|
203
|
+
// ---- Styles ---------------------------------------------------------
|
|
204
|
+
const titleStyle: TextStyle = {
|
|
205
|
+
color: titleColor,
|
|
206
|
+
fontFamily: titleFontFamily,
|
|
207
|
+
fontSize: titleFontSize,
|
|
208
|
+
lineHeight: titleLineHeight,
|
|
209
|
+
fontWeight: titleFontWeight,
|
|
210
|
+
width: '100%',
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const subtitleStyle: TextStyle = {
|
|
214
|
+
color: subtitleColor,
|
|
215
|
+
fontFamily: subtitleFontFamily,
|
|
216
|
+
fontSize: subtitleFontSize,
|
|
217
|
+
lineHeight: subtitleLineHeight,
|
|
218
|
+
fontWeight: subtitleFontWeight,
|
|
219
|
+
width: '100%',
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const imageBoxStyle: ViewStyle = {
|
|
223
|
+
width: '100%',
|
|
224
|
+
aspectRatio: imageRatio,
|
|
225
|
+
overflow: 'hidden',
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// RN's `<Image>` accepts `ImageStyle`, which has a narrower `overflow`
|
|
229
|
+
// union than `ViewStyle`. Build the image-only style separately so the
|
|
230
|
+
// shared box dimensions can be reused without a cast.
|
|
231
|
+
const imageStyle: ImageStyle = {
|
|
232
|
+
width: '100%',
|
|
233
|
+
aspectRatio: imageRatio,
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const addFieldStyle: ViewStyle = {
|
|
237
|
+
...imageBoxStyle,
|
|
238
|
+
backgroundColor: addFieldBg,
|
|
239
|
+
borderRadius: addFieldRadius,
|
|
240
|
+
alignItems: 'center',
|
|
241
|
+
justifyContent: 'center',
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ---- Image / placeholder area --------------------------------------
|
|
245
|
+
const renderCardArea = (): React.ReactNode => {
|
|
246
|
+
if (cardSlot !== undefined && cardSlot !== null) {
|
|
247
|
+
const processed = cloneChildrenWithModes(cardSlot, modes)
|
|
248
|
+
return (
|
|
249
|
+
<View style={imageBoxStyle} pointerEvents="box-none">
|
|
250
|
+
{processed.length === 1 ? processed[0] : processed}
|
|
251
|
+
</View>
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (state === 'add') {
|
|
256
|
+
return (
|
|
257
|
+
<View style={addFieldStyle} accessibilityElementsHidden importantForAccessibility="no">
|
|
258
|
+
<Icon name={addIcon} size={addIconSize} color={addIconColor} />
|
|
259
|
+
</View>
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const normalized = normalizeImageSource(imageSource)
|
|
264
|
+
if (normalized) {
|
|
265
|
+
return (
|
|
266
|
+
<RNImage
|
|
267
|
+
source={normalized}
|
|
268
|
+
style={imageStyle}
|
|
269
|
+
resizeMode="cover"
|
|
270
|
+
accessibilityElementsHidden
|
|
271
|
+
importantForAccessibility="no"
|
|
272
|
+
/>
|
|
273
|
+
)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return <View style={imageBoxStyle} />
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// ---- Pressable wiring ----------------------------------------------
|
|
280
|
+
// Keep React state out of the press path. `Pressable`'s style callback
|
|
281
|
+
// applies the pressed visual without a re-render.
|
|
282
|
+
const userHandlersRef = useRef<{
|
|
283
|
+
onPressIn?: (e: any) => void
|
|
284
|
+
onPressOut?: (e: any) => void
|
|
285
|
+
}>({})
|
|
286
|
+
|
|
287
|
+
const handlePressIn = useCallback((e: any) => {
|
|
288
|
+
userHandlersRef.current.onPressIn?.(e)
|
|
289
|
+
}, [])
|
|
290
|
+
const handlePressOut = useCallback((e: any) => {
|
|
291
|
+
userHandlersRef.current.onPressOut?.(e)
|
|
292
|
+
}, [])
|
|
293
|
+
|
|
294
|
+
const containerStyle: ViewStyle = useMemo(
|
|
295
|
+
() => ({
|
|
296
|
+
width: '100%',
|
|
297
|
+
flexDirection: 'column',
|
|
298
|
+
alignItems: 'flex-start',
|
|
299
|
+
gap,
|
|
300
|
+
opacity: disabled ? 0.5 : 1,
|
|
301
|
+
}),
|
|
302
|
+
[gap, disabled]
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
const pressableStyle = useCallback(
|
|
306
|
+
({ pressed }: PressableStateCallbackType): StyleProp<ViewStyle> => [
|
|
307
|
+
containerStyle,
|
|
308
|
+
style,
|
|
309
|
+
pressed && !disabled && onPress ? pressedOverlayStyle : null,
|
|
310
|
+
],
|
|
311
|
+
[containerStyle, style, disabled, onPress]
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
const showSubtitle = state === 'connected' && subtitle != null && subtitle !== ''
|
|
315
|
+
|
|
316
|
+
const a11yRole = onPress ? 'button' : undefined
|
|
317
|
+
const a11yLabel = accessibilityLabel ?? title
|
|
318
|
+
|
|
319
|
+
const content = (
|
|
320
|
+
<>
|
|
321
|
+
{renderCardArea()}
|
|
322
|
+
{(title != null && title !== '') || showSubtitle ? (
|
|
323
|
+
<View
|
|
324
|
+
style={{
|
|
325
|
+
width: '100%',
|
|
326
|
+
flexDirection: 'column',
|
|
327
|
+
alignItems: 'flex-start',
|
|
328
|
+
gap: textWrapGap,
|
|
329
|
+
}}
|
|
330
|
+
>
|
|
331
|
+
{title != null && title !== '' ? (
|
|
332
|
+
<Text style={titleStyle} numberOfLines={1}>
|
|
333
|
+
{title}
|
|
334
|
+
</Text>
|
|
335
|
+
) : null}
|
|
336
|
+
{showSubtitle ? (
|
|
337
|
+
<Text style={subtitleStyle} numberOfLines={1}>
|
|
338
|
+
{subtitle}
|
|
339
|
+
</Text>
|
|
340
|
+
) : null}
|
|
341
|
+
</View>
|
|
342
|
+
) : null}
|
|
343
|
+
</>
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
if (!onPress) {
|
|
347
|
+
return (
|
|
348
|
+
<View
|
|
349
|
+
accessibilityLabel={a11yLabel}
|
|
350
|
+
accessibilityHint={accessibilityHint}
|
|
351
|
+
style={[containerStyle, style]}
|
|
352
|
+
>
|
|
353
|
+
{content}
|
|
354
|
+
</View>
|
|
355
|
+
)
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return (
|
|
359
|
+
<Pressable
|
|
360
|
+
accessibilityRole={a11yRole}
|
|
361
|
+
accessibilityLabel={a11yLabel}
|
|
362
|
+
accessibilityHint={accessibilityHint}
|
|
363
|
+
accessibilityState={{ disabled }}
|
|
364
|
+
onPress={disabled ? undefined : onPress}
|
|
365
|
+
disabled={disabled}
|
|
366
|
+
onPressIn={handlePressIn}
|
|
367
|
+
onPressOut={handlePressOut}
|
|
368
|
+
unstable_pressDelay={PRESS_DELAY}
|
|
369
|
+
style={pressableStyle}
|
|
370
|
+
>
|
|
371
|
+
{content}
|
|
372
|
+
</Pressable>
|
|
373
|
+
)
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
export default React.memo(AccountCard)
|