jfs-components 0.0.44 → 0.0.47
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/lib/commonjs/components/AmountInput/AmountInput.js +82 -0
- package/lib/commonjs/components/AmountInput/index.js +13 -0
- package/lib/commonjs/components/Button/Button.js +31 -28
- package/lib/commonjs/components/CardProviderInfo/CardProviderInfo.js +76 -0
- package/lib/commonjs/components/ChipSelect/ChipSelect.js +1 -2
- package/lib/commonjs/components/Drawer/demo.xml +18 -0
- package/lib/commonjs/components/EmptyState/EmptyState.js +2 -1
- package/lib/commonjs/components/FormField/FormField.js +1 -0
- package/lib/commonjs/components/NoteInput/NoteInput.js +1 -2
- package/lib/commonjs/components/Nudge/Nudge.js +143 -0
- package/lib/commonjs/components/OTP/OTP.js +242 -0
- package/lib/commonjs/components/PaymentFeedback/PaymentFeedback.js +148 -0
- package/lib/commonjs/components/PortfolioHero/PortfolioHero.js +78 -0
- package/lib/commonjs/components/ProductLabel/ProductLabel.js +50 -0
- package/lib/commonjs/components/ProgressBadge/ProgressBadge.js +130 -0
- package/lib/commonjs/components/ProgressBadge/index.js +25 -0
- package/lib/commonjs/components/SegmentedControl/SegmentedControl.js +131 -0
- package/lib/commonjs/components/StatItem/StatItem.js +61 -0
- package/lib/commonjs/components/SupportText/SupportTextIcon.js +2 -3
- package/lib/commonjs/components/SwappableAmount/SwappableAmount.js +71 -0
- package/lib/commonjs/components/Text/Text.js +44 -0
- package/lib/commonjs/components/{PageTitle/PageTitle.js → Title/Title.js} +21 -20
- package/lib/commonjs/components/Toggle/Toggle.js +102 -0
- package/lib/commonjs/components/UpiHandle/UpiHandle.js +5 -2
- package/lib/commonjs/components/index.js +115 -3
- package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -0
- package/lib/commonjs/design-tokens/figma-variables-resolver.js +1 -1
- package/lib/commonjs/icons/registry.js +1 -1
- package/lib/commonjs/index.js +12 -0
- package/lib/commonjs/utils/index.js +18 -0
- package/lib/module/components/AmountInput/AmountInput.js +77 -0
- package/lib/module/components/AmountInput/index.js +3 -0
- package/lib/module/components/Button/Button.js +31 -28
- package/lib/module/components/CardProviderInfo/CardProviderInfo.js +71 -0
- package/lib/module/components/ChipSelect/ChipSelect.js +1 -2
- package/lib/module/components/Drawer/demo.xml +18 -0
- package/lib/module/components/EmptyState/EmptyState.js +2 -1
- package/lib/module/components/FormField/FormField.js +1 -0
- package/lib/module/components/NoteInput/NoteInput.js +1 -2
- package/lib/module/components/Nudge/Nudge.js +138 -0
- package/lib/module/components/OTP/OTP.js +236 -0
- package/lib/module/components/PaymentFeedback/PaymentFeedback.js +142 -0
- package/lib/module/components/PortfolioHero/PortfolioHero.js +73 -0
- package/lib/module/components/ProductLabel/ProductLabel.js +45 -0
- package/lib/module/components/ProgressBadge/ProgressBadge.js +125 -0
- package/lib/module/components/ProgressBadge/index.js +4 -0
- package/lib/module/components/SegmentedControl/SegmentedControl.js +126 -0
- package/lib/module/components/StatItem/StatItem.js +56 -0
- package/lib/module/components/SupportText/SupportTextIcon.js +2 -3
- package/lib/module/components/SwappableAmount/SwappableAmount.js +66 -0
- package/lib/module/components/Text/Text.js +39 -0
- package/lib/module/components/{PageTitle/PageTitle.js → Title/Title.js} +21 -20
- package/lib/module/components/Toggle/Toggle.js +97 -0
- package/lib/module/components/UpiHandle/UpiHandle.js +5 -2
- package/lib/module/components/index.js +18 -2
- package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -0
- package/lib/module/design-tokens/figma-variables-resolver.js +1 -1
- package/lib/module/icons/registry.js +1 -1
- package/lib/module/index.js +2 -1
- package/lib/module/utils/index.js +3 -0
- package/lib/typescript/src/components/AmountInput/AmountInput.d.ts +23 -0
- package/lib/typescript/src/components/AmountInput/index.d.ts +3 -0
- package/lib/typescript/src/components/CardProviderInfo/CardProviderInfo.d.ts +24 -0
- package/lib/typescript/src/components/ChipSelect/ChipSelect.d.ts +1 -6
- package/lib/typescript/src/components/EmptyState/EmptyState.d.ts +6 -1
- package/lib/typescript/src/components/LinearMeter/LinearMeter.d.ts +1 -1
- package/lib/typescript/src/components/Nudge/Nudge.d.ts +31 -0
- package/lib/typescript/src/components/OTP/OTP.d.ts +36 -0
- package/lib/typescript/src/components/PaymentFeedback/PaymentFeedback.d.ts +23 -0
- package/lib/typescript/src/components/PortfolioHero/PortfolioHero.d.ts +21 -0
- package/lib/typescript/src/components/ProductLabel/ProductLabel.d.ts +14 -0
- package/lib/typescript/src/components/ProgressBadge/ProgressBadge.d.ts +36 -0
- package/lib/typescript/src/components/ProgressBadge/index.d.ts +3 -0
- package/lib/typescript/src/components/RechargeCard/RechargeCard.d.ts +1 -2
- package/lib/typescript/src/components/SegmentedControl/SegmentedControl.d.ts +49 -0
- package/lib/typescript/src/components/StatItem/StatItem.d.ts +21 -0
- package/lib/typescript/src/components/SupportText/SupportText.d.ts +1 -1
- package/lib/typescript/src/components/SupportText/SupportTextIcon.d.ts +1 -1
- package/lib/typescript/src/components/SwappableAmount/SwappableAmount.d.ts +22 -0
- package/lib/typescript/src/components/Text/Text.d.ts +16 -0
- package/lib/typescript/src/components/Title/Title.d.ts +16 -0
- package/lib/typescript/src/components/Toggle/Toggle.d.ts +29 -0
- package/lib/typescript/src/components/UpiHandle/UpiHandle.d.ts +3 -1
- package/lib/typescript/src/components/index.d.ts +22 -5
- package/lib/typescript/src/icons/registry.d.ts +1 -1
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/utils/index.d.ts +2 -0
- package/package.json +2 -2
- package/src/components/AmountInput/AmountInput.tsx +81 -0
- package/src/components/AmountInput/index.ts +2 -0
- package/src/components/Button/Button.tsx +27 -20
- package/src/components/CardProviderInfo/CardProviderInfo.tsx +81 -0
- package/src/components/ChipSelect/ChipSelect.tsx +1 -8
- package/src/components/Drawer/demo.xml +18 -0
- package/src/components/EmptyState/EmptyState.tsx +7 -1
- package/src/components/FormField/FormField.tsx +1 -0
- package/src/components/LinearMeter/LinearMeter.tsx +1 -1
- package/src/components/NoteInput/NoteInput.tsx +1 -1
- package/src/components/Nudge/Nudge.tsx +150 -0
- package/src/components/OTP/OTP.tsx +275 -0
- package/src/components/PaymentFeedback/PaymentFeedback.tsx +168 -0
- package/src/components/PortfolioHero/PortfolioHero.tsx +91 -0
- package/src/components/ProductLabel/ProductLabel.tsx +58 -0
- package/src/components/ProgressBadge/ProgressBadge.tsx +172 -0
- package/src/components/ProgressBadge/index.ts +2 -0
- package/src/components/RechargeCard/RechargeCard.tsx +1 -1
- package/src/components/SegmentedControl/SegmentedControl.tsx +168 -0
- package/src/components/StatItem/StatItem.tsx +71 -0
- package/src/components/SupportText/SupportText.tsx +1 -1
- package/src/components/SupportText/SupportTextIcon.tsx +4 -3
- package/src/components/SwappableAmount/SwappableAmount.tsx +92 -0
- package/src/components/Text/Text.tsx +57 -0
- package/src/components/{PageTitle/PageTitle.tsx → Title/Title.tsx} +25 -19
- package/src/components/Toggle/Toggle.tsx +122 -0
- package/src/components/UpiHandle/UpiHandle.tsx +6 -2
- package/src/components/index.ts +22 -5
- package/src/design-tokens/Coin Variables-variables-full.json +1 -0
- package/src/design-tokens/figma-variables-resolver.ts +1 -1
- package/src/icons/registry.ts +1 -1
- package/src/index.ts +1 -0
- package/src/utils/index.ts +1 -0
- package/lib/commonjs/design-tokens/JFS Variables-variables-full.json +0 -1
- package/lib/module/design-tokens/JFS Variables-variables-full.json +0 -1
- package/lib/typescript/src/components/PageTitle/PageTitle.d.ts +0 -29
- package/src/design-tokens/JFS Variables-variables-full.json +0 -1
|
@@ -0,0 +1,172 @@
|
|
|
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 Icon from '../../icons/Icon'
|
|
11
|
+
import { cloneChildrenWithModes } from '../../utils/react-utils'
|
|
12
|
+
|
|
13
|
+
export type ProgressBadgeProps = {
|
|
14
|
+
/** The text displayed in the badge (e.g. "Live price...") */
|
|
15
|
+
taskName?: string
|
|
16
|
+
/** The icon name to display to the left of the text */
|
|
17
|
+
iconName?: string
|
|
18
|
+
/** The progress value between 0 and 100 */
|
|
19
|
+
value?: number
|
|
20
|
+
/** Modes object passed to `getVariableByName` for design token resolution */
|
|
21
|
+
modes?: Record<string, any>
|
|
22
|
+
/** Optional container style overrides */
|
|
23
|
+
style?: StyleProp<ViewStyle>
|
|
24
|
+
/** Optional text style overrides */
|
|
25
|
+
textStyle?: StyleProp<TextStyle>
|
|
26
|
+
/** Accessibility label for screen readers */
|
|
27
|
+
accessibilityLabel?: string
|
|
28
|
+
} & React.ComponentProps<typeof View>
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* ProgressBadge component that displays an icon, text, and an internal progress bar.
|
|
32
|
+
*
|
|
33
|
+
* All visual attributes resolve from Figma tokens via `getVariableByName` using the provided `modes`.
|
|
34
|
+
*
|
|
35
|
+
* @component
|
|
36
|
+
* @param {Object} props
|
|
37
|
+
* @param {string} [props.taskName="Live price: [price] (00:43)"] - The text displayed.
|
|
38
|
+
* @param {string} [props.iconName="ic_live"] - Icon name from the registry.
|
|
39
|
+
* @param {number} [props.value=0] - The progress value between 0 and 100.
|
|
40
|
+
* @param {Object} [props.modes={}] - Modes object passed to `getVariableByName` for design tokens.
|
|
41
|
+
* @param {Object} [props.style] - Optional container style overrides.
|
|
42
|
+
* @param {Object} [props.textStyle] - Optional text style overrides.
|
|
43
|
+
* @param {string} [props.accessibilityLabel] - Accessibility label.
|
|
44
|
+
*/
|
|
45
|
+
function ProgressBadge({
|
|
46
|
+
taskName = 'Live price: [price] (00:43)',
|
|
47
|
+
iconName = 'ic_live',
|
|
48
|
+
value = 0,
|
|
49
|
+
modes = {},
|
|
50
|
+
style,
|
|
51
|
+
textStyle: textStyleOverride,
|
|
52
|
+
accessibilityLabel,
|
|
53
|
+
...rest
|
|
54
|
+
}: ProgressBadgeProps) {
|
|
55
|
+
// Resolve layout tokens
|
|
56
|
+
const backgroundColor =
|
|
57
|
+
getVariableByName('progressBadge/background', modes) || '#ffffff'
|
|
58
|
+
const progressColor =
|
|
59
|
+
getVariableByName('progressBadge/progress/color', modes) || '#ebebed'
|
|
60
|
+
const gap = getVariableByName('progressBadge/gap', modes) ?? 12
|
|
61
|
+
const paddingHorizontal =
|
|
62
|
+
getVariableByName('progressBadge/padding/horizontal', modes) ?? 16
|
|
63
|
+
const paddingVertical =
|
|
64
|
+
getVariableByName('progressBadge/padding/vertical', modes) ?? 6
|
|
65
|
+
const borderRadius = getVariableByName('progressBadge/radius', modes) ?? 999
|
|
66
|
+
const descriptionGap =
|
|
67
|
+
getVariableByName('progressBadge/description/gap', modes) ?? 8
|
|
68
|
+
|
|
69
|
+
// Resolve typography tokens
|
|
70
|
+
const fontFamily =
|
|
71
|
+
getVariableByName('progressBadge/fontFamily', modes) || 'JioType_Var:Medium'
|
|
72
|
+
const fontWeightRaw = getVariableByName('progressBadge/fontWeight', modes) ?? 500
|
|
73
|
+
const fontWeight =
|
|
74
|
+
typeof fontWeightRaw === 'number'
|
|
75
|
+
? fontWeightRaw.toString()
|
|
76
|
+
: fontWeightRaw
|
|
77
|
+
const fontSize = getVariableByName('progressBadge/fontSize', modes) ?? 14
|
|
78
|
+
const lineHeight = getVariableByName('progressBadge/lineHeight', modes) ?? 17
|
|
79
|
+
const textColor =
|
|
80
|
+
getVariableByName('progressBadge/foreground', modes) || '#000000'
|
|
81
|
+
|
|
82
|
+
// Resolve icon tokens
|
|
83
|
+
const iconColor =
|
|
84
|
+
getVariableByName('progressBadge/icon/color', modes) || '#f50030'
|
|
85
|
+
const iconSize = getVariableByName('progressBadge/icon/size', modes) ?? 18
|
|
86
|
+
|
|
87
|
+
const containerStyle: ViewStyle = {
|
|
88
|
+
backgroundColor,
|
|
89
|
+
flexDirection: 'row',
|
|
90
|
+
alignItems: 'center',
|
|
91
|
+
gap,
|
|
92
|
+
paddingHorizontal,
|
|
93
|
+
paddingVertical,
|
|
94
|
+
borderRadius,
|
|
95
|
+
overflow: 'hidden',
|
|
96
|
+
position: 'relative',
|
|
97
|
+
flexWrap: 'wrap',
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const descriptionContainerStyle: ViewStyle = {
|
|
101
|
+
flexDirection: 'row',
|
|
102
|
+
alignItems: 'center',
|
|
103
|
+
justifyContent: 'center',
|
|
104
|
+
gap: descriptionGap,
|
|
105
|
+
flex: 1,
|
|
106
|
+
paddingVertical: 0,
|
|
107
|
+
minHeight: 1,
|
|
108
|
+
minWidth: 1,
|
|
109
|
+
position: 'relative',
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const textStyle: TextStyle = {
|
|
113
|
+
fontFamily,
|
|
114
|
+
fontWeight,
|
|
115
|
+
fontSize,
|
|
116
|
+
lineHeight,
|
|
117
|
+
color: textColor,
|
|
118
|
+
textAlign: 'center',
|
|
119
|
+
overflow: 'hidden',
|
|
120
|
+
flexShrink: 0,
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Ensure value is between 0 and 100
|
|
124
|
+
const clampedValue = Math.max(0, Math.min(100, value))
|
|
125
|
+
|
|
126
|
+
const progressStyle: ViewStyle = {
|
|
127
|
+
position: 'absolute',
|
|
128
|
+
left: 0,
|
|
129
|
+
top: 0,
|
|
130
|
+
bottom: 0,
|
|
131
|
+
width: `${clampedValue}%`,
|
|
132
|
+
backgroundColor: progressColor,
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const defaultAccessibilityLabel = accessibilityLabel || taskName
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<View
|
|
139
|
+
style={[containerStyle, style]}
|
|
140
|
+
accessibilityRole="text"
|
|
141
|
+
accessibilityLabel={defaultAccessibilityLabel}
|
|
142
|
+
{...rest}
|
|
143
|
+
>
|
|
144
|
+
{/* Background Progress Bar */}
|
|
145
|
+
<View style={progressStyle} pointerEvents="none" />
|
|
146
|
+
|
|
147
|
+
{/* Description Header */}
|
|
148
|
+
<View style={descriptionContainerStyle}>
|
|
149
|
+
{iconName ? (
|
|
150
|
+
<Icon
|
|
151
|
+
name={iconName}
|
|
152
|
+
size={iconSize}
|
|
153
|
+
color={iconColor}
|
|
154
|
+
accessibilityElementsHidden={true}
|
|
155
|
+
importantForAccessibility="no"
|
|
156
|
+
/>
|
|
157
|
+
) : null}
|
|
158
|
+
<Text
|
|
159
|
+
style={[textStyle, textStyleOverride]}
|
|
160
|
+
numberOfLines={1}
|
|
161
|
+
ellipsizeMode="tail"
|
|
162
|
+
accessibilityElementsHidden={true}
|
|
163
|
+
importantForAccessibility="no"
|
|
164
|
+
>
|
|
165
|
+
{taskName}
|
|
166
|
+
</Text>
|
|
167
|
+
</View>
|
|
168
|
+
</View>
|
|
169
|
+
)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export default ProgressBadge
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import React, { useState, useCallback } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
Pressable,
|
|
5
|
+
Text,
|
|
6
|
+
type StyleProp,
|
|
7
|
+
type ViewStyle,
|
|
8
|
+
type TextStyle,
|
|
9
|
+
} from 'react-native'
|
|
10
|
+
import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
|
|
11
|
+
|
|
12
|
+
export type SegmentedControlItem = {
|
|
13
|
+
key: React.Key
|
|
14
|
+
label: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type SegmentedControlProps = {
|
|
18
|
+
/** The items to display as segments */
|
|
19
|
+
items: SegmentedControlItem[]
|
|
20
|
+
/** The currently selected key (controlled) */
|
|
21
|
+
selectedKey?: React.Key
|
|
22
|
+
/** The initially selected key (uncontrolled). Defaults to the first item's key. */
|
|
23
|
+
defaultSelectedKey?: React.Key
|
|
24
|
+
/** Callback fired when the selected segment changes */
|
|
25
|
+
onSelectionChange?: (key: React.Key) => void
|
|
26
|
+
/** Design token modes for theming */
|
|
27
|
+
modes?: Record<string, any>
|
|
28
|
+
/** Override container styles */
|
|
29
|
+
style?: StyleProp<ViewStyle>
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function SegmentedControlSegment({
|
|
33
|
+
label,
|
|
34
|
+
active,
|
|
35
|
+
onPress,
|
|
36
|
+
modes = {},
|
|
37
|
+
}: {
|
|
38
|
+
label: string
|
|
39
|
+
active: boolean
|
|
40
|
+
onPress: () => void
|
|
41
|
+
modes: Record<string, any>
|
|
42
|
+
}) {
|
|
43
|
+
const resolvedModes = {
|
|
44
|
+
...modes,
|
|
45
|
+
'SegmentedControl/Segment': active ? 'Active' : 'Idle',
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const paddingHorizontal = (getVariableByName('segment/padding/horizontal', resolvedModes) ?? 16) as number
|
|
49
|
+
const paddingVertical = (getVariableByName('segment/padding/vertical', resolvedModes) ?? 12) as number
|
|
50
|
+
const radius = (getVariableByName('segment/radius', resolvedModes) ?? 20) as number
|
|
51
|
+
const background = (getVariableByName('segment/background', resolvedModes) ?? (active ? '#5d00b5' : 'transparent')) as string
|
|
52
|
+
const foreground = (getVariableByName('segment/foreground', resolvedModes) ?? (active ? '#ffffff' : '#0c0d10')) as string
|
|
53
|
+
const fontSize = (getVariableByName('segment/fontSize', resolvedModes) ?? 16) as number
|
|
54
|
+
const fontFamily = (getVariableByName('segment/fontFamily', resolvedModes) ?? 'JioType Var') as string
|
|
55
|
+
const lineHeight = (getVariableByName('segment/lineHeight', resolvedModes) ?? 19) as number
|
|
56
|
+
const fontWeight = (getVariableByName('segment/fontWeight', resolvedModes) ?? '500') as string
|
|
57
|
+
|
|
58
|
+
const segmentStyle: ViewStyle = {
|
|
59
|
+
flex: 1,
|
|
60
|
+
alignItems: 'center',
|
|
61
|
+
justifyContent: 'center',
|
|
62
|
+
paddingHorizontal,
|
|
63
|
+
paddingVertical,
|
|
64
|
+
borderRadius: radius,
|
|
65
|
+
backgroundColor: background,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const textStyle: TextStyle = {
|
|
69
|
+
color: foreground,
|
|
70
|
+
fontFamily,
|
|
71
|
+
fontSize,
|
|
72
|
+
lineHeight,
|
|
73
|
+
fontWeight: fontWeight as TextStyle['fontWeight'],
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<Pressable
|
|
78
|
+
style={({ pressed }) => [segmentStyle, pressed && { opacity: 0.8 }]}
|
|
79
|
+
onPress={onPress}
|
|
80
|
+
accessibilityRole="tab"
|
|
81
|
+
accessibilityState={{ selected: active }}
|
|
82
|
+
accessibilityLabel={label}
|
|
83
|
+
>
|
|
84
|
+
<Text style={textStyle}>{label}</Text>
|
|
85
|
+
</Pressable>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* SegmentedControl component backed by Figma design tokens.
|
|
91
|
+
*
|
|
92
|
+
* Provides a horizontal row of mutually exclusive segments.
|
|
93
|
+
* Supports controlled (`selectedKey` + `onSelectionChange`) and
|
|
94
|
+
* uncontrolled (`defaultSelectedKey`) usage patterns.
|
|
95
|
+
*
|
|
96
|
+
* @component
|
|
97
|
+
* @param {SegmentedControlProps} props
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```tsx
|
|
101
|
+
* const [selected, setSelected] = useState<React.Key>('daily');
|
|
102
|
+
*
|
|
103
|
+
* <SegmentedControl
|
|
104
|
+
* items={[
|
|
105
|
+
* { key: 'daily', label: 'Daily' },
|
|
106
|
+
* { key: 'weekly', label: 'Weekly' },
|
|
107
|
+
* { key: 'monthly', label: 'Monthly' },
|
|
108
|
+
* ]}
|
|
109
|
+
* selectedKey={selected}
|
|
110
|
+
* onSelectionChange={setSelected}
|
|
111
|
+
* modes={{ 'Color Mode': 'Light' }}
|
|
112
|
+
* />
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
function SegmentedControl({
|
|
116
|
+
items,
|
|
117
|
+
selectedKey: controlledSelectedKey,
|
|
118
|
+
defaultSelectedKey,
|
|
119
|
+
onSelectionChange,
|
|
120
|
+
modes = {},
|
|
121
|
+
style,
|
|
122
|
+
}: SegmentedControlProps) {
|
|
123
|
+
const isControlled = controlledSelectedKey !== undefined
|
|
124
|
+
const [internalSelectedKey, setInternalSelectedKey] = useState<React.Key | undefined>(
|
|
125
|
+
defaultSelectedKey ?? items[0]?.key
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
const currentSelectedKey = isControlled ? controlledSelectedKey : internalSelectedKey
|
|
129
|
+
|
|
130
|
+
const handlePress = useCallback(
|
|
131
|
+
(key: React.Key) => {
|
|
132
|
+
if (!isControlled) {
|
|
133
|
+
setInternalSelectedKey(key)
|
|
134
|
+
}
|
|
135
|
+
onSelectionChange?.(key)
|
|
136
|
+
},
|
|
137
|
+
[isControlled, onSelectionChange]
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
const gap = (getVariableByName('segmentedControl/gap', modes) ?? 8) as number
|
|
141
|
+
const background = (getVariableByName('segmentedControl/background', modes) ?? '#f6f3ff') as string
|
|
142
|
+
const radius = (getVariableByName('segmentedControl/radius', modes) ?? 24) as number
|
|
143
|
+
|
|
144
|
+
const containerStyle: ViewStyle = {
|
|
145
|
+
flexDirection: 'row',
|
|
146
|
+
alignItems: 'center',
|
|
147
|
+
backgroundColor: background,
|
|
148
|
+
borderRadius: radius,
|
|
149
|
+
gap,
|
|
150
|
+
overflow: 'hidden',
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<View style={[containerStyle, style]} accessibilityRole="tablist">
|
|
155
|
+
{items.map((item) => (
|
|
156
|
+
<SegmentedControlSegment
|
|
157
|
+
key={String(item.key)}
|
|
158
|
+
label={item.label}
|
|
159
|
+
active={item.key === currentSelectedKey}
|
|
160
|
+
onPress={() => handlePress(item.key)}
|
|
161
|
+
modes={modes}
|
|
162
|
+
/>
|
|
163
|
+
))}
|
|
164
|
+
</View>
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export default SegmentedControl
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { View, Text, type StyleProp, type ViewStyle } from 'react-native'
|
|
3
|
+
import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
|
|
4
|
+
|
|
5
|
+
export type StatItemProps = {
|
|
6
|
+
/** The small descriptive label above the value. */
|
|
7
|
+
label?: string
|
|
8
|
+
/** The large prominent value to display. */
|
|
9
|
+
value?: string
|
|
10
|
+
/** Design token modes for theming. */
|
|
11
|
+
modes?: Record<string, any>
|
|
12
|
+
/** Override container styles. */
|
|
13
|
+
style?: StyleProp<ViewStyle>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* StatItem displays a label/value pair with the value in a large, bold style.
|
|
18
|
+
* Useful for metrics, product stats, or KPI callouts.
|
|
19
|
+
*
|
|
20
|
+
* @component
|
|
21
|
+
* @param {StatItemProps} props
|
|
22
|
+
*/
|
|
23
|
+
function StatItem({
|
|
24
|
+
label = 'Purity verified by NABL',
|
|
25
|
+
value = '99.99%',
|
|
26
|
+
modes = {},
|
|
27
|
+
style,
|
|
28
|
+
}: StatItemProps) {
|
|
29
|
+
const gap = getVariableByName('statItem/gap', modes) ?? 2
|
|
30
|
+
|
|
31
|
+
const labelForeground = getVariableByName('statItem/label/foreground', modes) ?? '#1a1c1f'
|
|
32
|
+
const labelFontFamily = getVariableByName('statItem/label/fontFamily', modes) ?? 'JioType Var'
|
|
33
|
+
const labelFontSize = getVariableByName('statItem/label/fontSize', modes) ?? 12
|
|
34
|
+
const labelFontWeight = getVariableByName('statItem/label/fontWeight', modes) ?? '500'
|
|
35
|
+
const labelLineHeight = getVariableByName('statItem/label/lineHeight', modes) ?? 16
|
|
36
|
+
|
|
37
|
+
const valueForeground = getVariableByName('statItem/value/foreground', modes) ?? '#0d0d0f'
|
|
38
|
+
const valueFontFamily = getVariableByName('statItem/value/fontFamily', modes) ?? 'JioType Var'
|
|
39
|
+
const valueFontSize = getVariableByName('statItem/value/fontSize', modes) ?? 26
|
|
40
|
+
const valueFontWeight = getVariableByName('statItem/value/fontWeight', modes) ?? '900'
|
|
41
|
+
const valueLineHeight = getVariableByName('statItem/value/lineHeight', modes) ?? 26
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<View style={[{ gap: gap as number }, style]}>
|
|
45
|
+
<Text
|
|
46
|
+
style={{
|
|
47
|
+
color: labelForeground as string,
|
|
48
|
+
fontFamily: labelFontFamily as string,
|
|
49
|
+
fontSize: labelFontSize as number,
|
|
50
|
+
fontWeight: String(labelFontWeight) as any,
|
|
51
|
+
lineHeight: labelLineHeight as number,
|
|
52
|
+
}}
|
|
53
|
+
>
|
|
54
|
+
{label}
|
|
55
|
+
</Text>
|
|
56
|
+
<Text
|
|
57
|
+
style={{
|
|
58
|
+
color: valueForeground as string,
|
|
59
|
+
fontFamily: valueFontFamily as string,
|
|
60
|
+
fontSize: valueFontSize as number,
|
|
61
|
+
fontWeight: String(valueFontWeight) as any,
|
|
62
|
+
lineHeight: valueLineHeight as number,
|
|
63
|
+
}}
|
|
64
|
+
>
|
|
65
|
+
{value}
|
|
66
|
+
</Text>
|
|
67
|
+
</View>
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export default StatItem
|
|
@@ -3,7 +3,7 @@ import { View, type ViewStyle } from 'react-native';
|
|
|
3
3
|
import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
|
|
4
4
|
import Icon from '../../icons/Icon';
|
|
5
5
|
|
|
6
|
-
export type SupportTextStatus = 'Neutral' | 'Warning' | 'Error' | 'Success';
|
|
6
|
+
export type SupportTextStatus = 'Neutral' | 'Warning' | 'Error' | 'Success' | 'Loading';
|
|
7
7
|
|
|
8
8
|
export type SupportTextIconProps = {
|
|
9
9
|
status?: SupportTextStatus;
|
|
@@ -13,9 +13,10 @@ export type SupportTextIconProps = {
|
|
|
13
13
|
|
|
14
14
|
const STATUS_ICON_MAP: Record<SupportTextStatus, string> = {
|
|
15
15
|
Neutral: 'ic_info',
|
|
16
|
-
Warning: 'ic_warning',
|
|
17
|
-
Error: 'ic_warning',
|
|
16
|
+
Warning: 'ic_warning',
|
|
17
|
+
Error: 'ic_warning',
|
|
18
18
|
Success: 'ic_status_successful',
|
|
19
|
+
Loading: 'ic_time',
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
function SupportTextIcon({
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { View, Text, type ViewStyle, type TextStyle } from 'react-native'
|
|
3
|
+
import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
|
|
4
|
+
import Button from '../Button/Button'
|
|
5
|
+
|
|
6
|
+
export type SwappableAmountProps = {
|
|
7
|
+
/** Large display value (e.g. "49g"). */
|
|
8
|
+
value?: string
|
|
9
|
+
/** Whether to show the schedule button above the value. */
|
|
10
|
+
schedule?: boolean
|
|
11
|
+
/** Label text for the schedule button (e.g. "Weekly on Mondays"). */
|
|
12
|
+
scheduleLabel?: string
|
|
13
|
+
/** Label text for the amount/swap button (e.g. "₹5100"). */
|
|
14
|
+
amountLabel?: string
|
|
15
|
+
/** Callback when the schedule button is pressed. */
|
|
16
|
+
onSchedulePress?: () => void
|
|
17
|
+
/** Callback when the amount/swap button is pressed. */
|
|
18
|
+
onAmountPress?: () => void
|
|
19
|
+
/** Modes configuration for design token resolution. */
|
|
20
|
+
modes?: Record<string, any>
|
|
21
|
+
/** Container style override. */
|
|
22
|
+
style?: ViewStyle
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function SwappableAmount({
|
|
26
|
+
value = '49g',
|
|
27
|
+
schedule = false,
|
|
28
|
+
scheduleLabel = 'Weekly on Mondays',
|
|
29
|
+
amountLabel = '₹5100',
|
|
30
|
+
onSchedulePress,
|
|
31
|
+
onAmountPress,
|
|
32
|
+
modes = {},
|
|
33
|
+
style,
|
|
34
|
+
}: SwappableAmountProps) {
|
|
35
|
+
const gap = getVariableByName('swappableAmount/gap', modes) ?? 24
|
|
36
|
+
const padding = getVariableByName('swappableAmount/padding', modes) ?? 8
|
|
37
|
+
|
|
38
|
+
const foreground = getVariableByName('swappableAmount/foreground', modes) ?? '#0d0d0f'
|
|
39
|
+
const fontSize = getVariableByName('swappableAmount/fontSize', modes) ?? 56
|
|
40
|
+
const fontFamily = getVariableByName('swappableAmount/fontFamily', modes) ?? 'System'
|
|
41
|
+
const fontWeight = getVariableByName('swappableAmount/fontWeight', modes) ?? 900
|
|
42
|
+
const lineHeight = getVariableByName('swappableAmount/lineHeight', modes) ?? 56
|
|
43
|
+
|
|
44
|
+
const containerStyle: ViewStyle = {
|
|
45
|
+
flexDirection: 'column',
|
|
46
|
+
alignItems: 'center',
|
|
47
|
+
justifyContent: 'center',
|
|
48
|
+
gap: gap as number,
|
|
49
|
+
padding: padding as number,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const valueTextStyle: TextStyle = {
|
|
53
|
+
color: foreground as string,
|
|
54
|
+
fontSize: fontSize as number,
|
|
55
|
+
fontFamily: fontFamily as string,
|
|
56
|
+
fontWeight: String(fontWeight) as TextStyle['fontWeight'],
|
|
57
|
+
lineHeight: lineHeight as number,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<View style={[containerStyle, style]}>
|
|
62
|
+
{schedule && (
|
|
63
|
+
<Button
|
|
64
|
+
label={scheduleLabel}
|
|
65
|
+
icon="ic_calendar_week"
|
|
66
|
+
onPress={onSchedulePress}
|
|
67
|
+
modes={{
|
|
68
|
+
...modes,
|
|
69
|
+
AppearanceBrand: 'Neutral',
|
|
70
|
+
Emphasis: 'Low',
|
|
71
|
+
'Button / Size': 'S',
|
|
72
|
+
}}
|
|
73
|
+
/>
|
|
74
|
+
)}
|
|
75
|
+
|
|
76
|
+
<Text style={valueTextStyle}>{value}</Text>
|
|
77
|
+
|
|
78
|
+
<Button
|
|
79
|
+
label={amountLabel}
|
|
80
|
+
icon="ic_data_in_out"
|
|
81
|
+
onPress={onAmountPress}
|
|
82
|
+
modes={{
|
|
83
|
+
...modes,
|
|
84
|
+
Emphasis: 'Medium',
|
|
85
|
+
AppearanceBrand: 'Secondary',
|
|
86
|
+
}}
|
|
87
|
+
/>
|
|
88
|
+
</View>
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export default SwappableAmount
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Text as RNText, type TextStyle, type StyleProp } from 'react-native'
|
|
3
|
+
import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
|
|
4
|
+
|
|
5
|
+
export type TextProps = {
|
|
6
|
+
/** The text content to display. */
|
|
7
|
+
text?: string
|
|
8
|
+
/** Horizontal alignment of the text. */
|
|
9
|
+
textAlign?: 'Left' | 'Center'
|
|
10
|
+
/** Modes configuration for design token resolution. */
|
|
11
|
+
modes?: Record<string, any>
|
|
12
|
+
/** Style override for the text. */
|
|
13
|
+
style?: StyleProp<TextStyle>
|
|
14
|
+
/** Number of lines to limit the text to. */
|
|
15
|
+
numberOfLines?: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const TEXT_ALIGN_MAP: Record<NonNullable<TextProps['textAlign']>, TextStyle['textAlign']> = {
|
|
19
|
+
Left: 'left',
|
|
20
|
+
Center: 'center',
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function Text({
|
|
24
|
+
text = 'Korem ipsum ',
|
|
25
|
+
textAlign = 'Left',
|
|
26
|
+
modes = {},
|
|
27
|
+
style,
|
|
28
|
+
numberOfLines,
|
|
29
|
+
}: TextProps) {
|
|
30
|
+
const foreground = getVariableByName('text/foreground', modes) ?? '#000000'
|
|
31
|
+
const fontFamily = getVariableByName('text/fontFamily', modes) ?? 'JioType'
|
|
32
|
+
const fontSize = getVariableByName('text/fontSize', modes) ?? 14
|
|
33
|
+
const fontWeight = getVariableByName('text/fontWeight', modes) ?? '500'
|
|
34
|
+
const lineHeight = getVariableByName('text/lineHeight', modes) ?? 20
|
|
35
|
+
const letterSpacing = getVariableByName('text/letterSpacing', modes) ?? -0.5
|
|
36
|
+
|
|
37
|
+
const textStyle: TextStyle = {
|
|
38
|
+
color: foreground as string,
|
|
39
|
+
fontFamily: fontFamily as string,
|
|
40
|
+
fontSize: fontSize as number,
|
|
41
|
+
fontWeight: String(fontWeight) as TextStyle['fontWeight'],
|
|
42
|
+
lineHeight: lineHeight as number,
|
|
43
|
+
letterSpacing: letterSpacing as number,
|
|
44
|
+
textAlign: TEXT_ALIGN_MAP[textAlign],
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<RNText
|
|
49
|
+
style={[textStyle, style]}
|
|
50
|
+
numberOfLines={numberOfLines}
|
|
51
|
+
>
|
|
52
|
+
{text}
|
|
53
|
+
</RNText>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default Text
|