jfs-components 0.0.74 → 0.0.78
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 +109 -0
- package/lib/commonjs/components/Accordion/Accordion.js +55 -55
- package/lib/commonjs/components/ActionFooter/ActionFooter.js +193 -82
- package/lib/commonjs/components/Avatar/Avatar.js +20 -0
- package/lib/commonjs/components/Badge/Badge.js +23 -0
- package/lib/commonjs/components/Button/Button.js +37 -0
- package/lib/commonjs/components/Checkbox/Checkbox.js +21 -9
- package/lib/commonjs/components/DropdownInput/DropdownInput.js +30 -16
- package/lib/commonjs/components/ExpandableCheckbox/ExpandableCheckbox.js +167 -0
- package/lib/commonjs/components/FormField/FormField.js +14 -1
- package/lib/commonjs/components/FullscreenModal/FullscreenModal.js +355 -0
- package/lib/commonjs/components/IconButton/IconButton.js +20 -0
- package/lib/commonjs/components/Image/Image.js +26 -1
- package/lib/commonjs/components/ListItem/ListItem.js +25 -10
- package/lib/commonjs/components/LottiePlayer/LottiePlayer.js +116 -0
- package/lib/commonjs/components/LottiePlayer/LottiePlayer.web.js +82 -0
- package/lib/commonjs/components/LottiePlayer/loadNativeLottieView.js +74 -0
- package/lib/commonjs/components/LottiePlayer/loadWebLottieView.js +50 -0
- package/lib/commonjs/components/MessageField/MessageField.js +318 -0
- package/lib/commonjs/components/NavArrow/NavArrow.js +58 -17
- package/lib/commonjs/components/PageHero/PageHero.js +41 -5
- package/lib/commonjs/components/RechargeCard/RechargeCard.js +32 -17
- package/lib/commonjs/components/Stepper/Step.js +47 -60
- package/lib/commonjs/components/Stepper/StepLabel.js +40 -10
- package/lib/commonjs/components/Stepper/Stepper.js +15 -17
- package/lib/commonjs/components/SuggestiveSearch/SuggestiveSearch.js +487 -0
- package/lib/commonjs/components/Text/Text.js +31 -1
- package/lib/commonjs/components/TextInput/TextInput.js +16 -1
- package/lib/commonjs/components/Title/Title.js +10 -2
- package/lib/commonjs/components/index.js +35 -0
- package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
- package/lib/commonjs/icons/Icon.js +16 -0
- package/lib/commonjs/icons/registry.js +1 -1
- package/lib/commonjs/index.js +12 -0
- package/lib/commonjs/skeleton/Skeleton.js +234 -0
- package/lib/commonjs/skeleton/SkeletonGroup.js +140 -0
- package/lib/commonjs/skeleton/index.js +58 -0
- package/lib/commonjs/skeleton/shimmer-tokens.js +189 -0
- package/lib/commonjs/skeleton/useReducedMotion.js +64 -0
- package/lib/module/components/Accordion/Accordion.js +56 -56
- package/lib/module/components/ActionFooter/ActionFooter.js +193 -83
- package/lib/module/components/Avatar/Avatar.js +19 -0
- package/lib/module/components/Badge/Badge.js +23 -0
- package/lib/module/components/Button/Button.js +37 -0
- package/lib/module/components/Checkbox/Checkbox.js +22 -10
- package/lib/module/components/DropdownInput/DropdownInput.js +30 -16
- package/lib/module/components/ExpandableCheckbox/ExpandableCheckbox.js +161 -0
- package/lib/module/components/FormField/FormField.js +16 -3
- package/lib/module/components/FullscreenModal/FullscreenModal.js +350 -0
- package/lib/module/components/IconButton/IconButton.js +20 -0
- package/lib/module/components/Image/Image.js +25 -1
- package/lib/module/components/ListItem/ListItem.js +25 -10
- package/lib/module/components/LottiePlayer/LottiePlayer.js +111 -0
- package/lib/module/components/LottiePlayer/LottiePlayer.web.js +77 -0
- package/lib/module/components/LottiePlayer/loadNativeLottieView.js +69 -0
- package/lib/module/components/LottiePlayer/loadWebLottieView.js +45 -0
- package/lib/module/components/MessageField/MessageField.js +313 -0
- package/lib/module/components/NavArrow/NavArrow.js +59 -18
- package/lib/module/components/PageHero/PageHero.js +41 -5
- package/lib/module/components/RechargeCard/RechargeCard.js +33 -17
- package/lib/module/components/Stepper/Step.js +48 -61
- package/lib/module/components/Stepper/StepLabel.js +40 -10
- package/lib/module/components/Stepper/Stepper.js +15 -17
- package/lib/module/components/SuggestiveSearch/SuggestiveSearch.js +481 -0
- package/lib/module/components/Text/Text.js +31 -1
- package/lib/module/components/TextInput/TextInput.js +17 -2
- package/lib/module/components/Title/Title.js +10 -2
- package/lib/module/components/index.js +5 -0
- package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
- package/lib/module/icons/Icon.js +16 -0
- package/lib/module/icons/registry.js +1 -1
- package/lib/module/index.js +2 -1
- package/lib/module/skeleton/Skeleton.js +229 -0
- package/lib/module/skeleton/SkeletonGroup.js +133 -0
- package/lib/module/skeleton/index.js +6 -0
- package/lib/module/skeleton/shimmer-tokens.js +181 -0
- package/lib/module/skeleton/useReducedMotion.js +61 -0
- package/lib/typescript/src/components/Accordion/Accordion.d.ts +14 -20
- package/lib/typescript/src/components/ActionFooter/ActionFooter.d.ts +26 -21
- package/lib/typescript/src/components/Avatar/Avatar.d.ts +7 -1
- package/lib/typescript/src/components/Badge/Badge.d.ts +7 -1
- package/lib/typescript/src/components/Button/Button.d.ts +8 -1
- package/lib/typescript/src/components/ExpandableCheckbox/ExpandableCheckbox.d.ts +63 -0
- package/lib/typescript/src/components/FullscreenModal/FullscreenModal.d.ts +99 -0
- package/lib/typescript/src/components/IconButton/IconButton.d.ts +7 -1
- package/lib/typescript/src/components/Image/Image.d.ts +8 -1
- package/lib/typescript/src/components/LottiePlayer/LottiePlayer.d.ts +85 -0
- package/lib/typescript/src/components/LottiePlayer/LottiePlayer.web.d.ts +28 -0
- package/lib/typescript/src/components/LottiePlayer/loadNativeLottieView.d.ts +11 -0
- package/lib/typescript/src/components/LottiePlayer/loadWebLottieView.d.ts +11 -0
- package/lib/typescript/src/components/MessageField/MessageField.d.ts +81 -0
- package/lib/typescript/src/components/NavArrow/NavArrow.d.ts +10 -5
- package/lib/typescript/src/components/PageHero/PageHero.d.ts +31 -5
- package/lib/typescript/src/components/Stepper/Step.d.ts +4 -1
- package/lib/typescript/src/components/Stepper/StepLabel.d.ts +4 -1
- package/lib/typescript/src/components/Stepper/Stepper.d.ts +3 -1
- package/lib/typescript/src/components/SuggestiveSearch/SuggestiveSearch.d.ts +123 -0
- package/lib/typescript/src/components/Text/Text.d.ts +20 -1
- package/lib/typescript/src/components/index.d.ts +8 -3
- package/lib/typescript/src/icons/Icon.d.ts +7 -1
- package/lib/typescript/src/icons/registry.d.ts +1 -1
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/skeleton/Skeleton.d.ts +60 -0
- package/lib/typescript/src/skeleton/SkeletonGroup.d.ts +78 -0
- package/lib/typescript/src/skeleton/index.d.ts +5 -0
- package/lib/typescript/src/skeleton/shimmer-tokens.d.ts +160 -0
- package/lib/typescript/src/skeleton/useReducedMotion.d.ts +15 -0
- package/package.json +11 -1
- package/src/components/Accordion/Accordion.tsx +113 -73
- package/src/components/ActionFooter/ActionFooter.tsx +210 -92
- package/src/components/Avatar/Avatar.tsx +26 -0
- package/src/components/Badge/Badge.tsx +27 -0
- package/src/components/Button/Button.tsx +40 -0
- package/src/components/Checkbox/Checkbox.tsx +22 -9
- package/src/components/DropdownInput/DropdownInput.tsx +67 -39
- package/src/components/ExpandableCheckbox/ExpandableCheckbox.tsx +237 -0
- package/src/components/FormField/FormField.tsx +19 -3
- package/src/components/FullscreenModal/FullscreenModal.tsx +414 -0
- package/src/components/IconButton/IconButton.tsx +27 -0
- package/src/components/Image/Image.tsx +25 -0
- package/src/components/ListItem/ListItem.tsx +21 -10
- package/src/components/LottiePlayer/LottiePlayer.tsx +145 -0
- package/src/components/LottiePlayer/LottiePlayer.web.tsx +94 -0
- package/src/components/LottiePlayer/loadNativeLottieView.tsx +87 -0
- package/src/components/LottiePlayer/loadWebLottieView.tsx +64 -0
- package/src/components/MessageField/MessageField.tsx +543 -0
- package/src/components/NavArrow/NavArrow.tsx +81 -17
- package/src/components/PageHero/PageHero.tsx +61 -4
- package/src/components/RechargeCard/RechargeCard.tsx +32 -24
- package/src/components/Stepper/Step.tsx +52 -51
- package/src/components/Stepper/StepLabel.tsx +46 -9
- package/src/components/Stepper/Stepper.tsx +20 -15
- package/src/components/SuggestiveSearch/SuggestiveSearch.tsx +756 -0
- package/src/components/Text/Text.tsx +54 -0
- package/src/components/TextInput/TextInput.tsx +14 -1
- package/src/components/Title/Title.tsx +13 -2
- package/src/components/index.ts +8 -3
- package/src/design-tokens/Coin Variables-variables-full.json +1 -1
- package/src/icons/Icon.tsx +17 -0
- package/src/icons/registry.ts +1 -1
- package/src/index.ts +1 -0
- package/src/skeleton/Skeleton.tsx +298 -0
- package/src/skeleton/SkeletonGroup.tsx +193 -0
- package/src/skeleton/index.ts +10 -0
- package/src/skeleton/shimmer-tokens.ts +221 -0
- package/src/skeleton/useReducedMotion.ts +72 -0
|
@@ -32,6 +32,23 @@ export type PageHeroProps = {
|
|
|
32
32
|
* `modes` are automatically cascaded into this slot.
|
|
33
33
|
*/
|
|
34
34
|
buttonSlot?: React.ReactNode
|
|
35
|
+
/**
|
|
36
|
+
* Optional media element shown above the text block (eyebrow + headline).
|
|
37
|
+
*
|
|
38
|
+
* Intentionally typed as `React.ReactNode` so the consumer can bring any
|
|
39
|
+
* renderer they like — `<Image />`, `<IconCapsule />`, a Lottie player
|
|
40
|
+
* (`lottie-react-native` / `@lottiefiles/dotlottie-react`), an `<SvgXml />`
|
|
41
|
+
* from `react-native-svg`, a `<Video />` from `react-native-video`, a
|
|
42
|
+
* gradient view, or a custom illustration. The library deliberately does
|
|
43
|
+
* NOT wrap Lottie / video runtimes (they require native modules + pod
|
|
44
|
+
* autolinking on every consumer's app), so PageHero just allocates a
|
|
45
|
+
* token-sized container and lets the slot render whatever it wants.
|
|
46
|
+
*
|
|
47
|
+
* The slot is rendered inside a `width × height` box driven by
|
|
48
|
+
* `media/width` and `media/height` tokens (default 117×117). `modes` are
|
|
49
|
+
* automatically cascaded into the slot via `cloneChildrenWithModes`.
|
|
50
|
+
*/
|
|
51
|
+
media?: React.ReactNode
|
|
35
52
|
/** Mode configuration for design-token theming. */
|
|
36
53
|
modes?: Record<string, any>
|
|
37
54
|
/** Style overrides applied to the outer container. */
|
|
@@ -41,12 +58,14 @@ export type PageHeroProps = {
|
|
|
41
58
|
|
|
42
59
|
/**
|
|
43
60
|
* PageHero displays a centered hero block typically used at the top of a page
|
|
44
|
-
* or feature screen. It contains an
|
|
45
|
-
*
|
|
61
|
+
* or feature screen. It contains an optional media slot (illustration / image
|
|
62
|
+
* / Lottie / SVG / video — consumer's choice), an eyebrow line, a large
|
|
63
|
+
* headline, an optional supporting line (e.g. price / timeline), and an
|
|
64
|
+
* optional action button.
|
|
46
65
|
*
|
|
47
66
|
* All visual values are resolved from Figma design tokens via
|
|
48
|
-
* `getVariableByName`.
|
|
49
|
-
*
|
|
67
|
+
* `getVariableByName`. Slots cascade the active `modes` to their children
|
|
68
|
+
* through `cloneChildrenWithModes`.
|
|
50
69
|
*
|
|
51
70
|
* @component
|
|
52
71
|
* @example
|
|
@@ -57,6 +76,13 @@ export type PageHeroProps = {
|
|
|
57
76
|
* supportingText="₹999/year · ₹0 until 2027"
|
|
58
77
|
* buttonLabel="Renew for free"
|
|
59
78
|
* onButtonPress={() => navigate('Upgrade')}
|
|
79
|
+
* media={
|
|
80
|
+
* <Image
|
|
81
|
+
* imageSource={require('./assets/upgrade.png')}
|
|
82
|
+
* width={117}
|
|
83
|
+
* height={117}
|
|
84
|
+
* />
|
|
85
|
+
* }
|
|
60
86
|
* />
|
|
61
87
|
* ```
|
|
62
88
|
*/
|
|
@@ -69,6 +95,7 @@ function PageHero({
|
|
|
69
95
|
onButtonPress,
|
|
70
96
|
showButton = true,
|
|
71
97
|
buttonSlot,
|
|
98
|
+
media,
|
|
72
99
|
modes: propModes = EMPTY_MODES,
|
|
73
100
|
style,
|
|
74
101
|
testID,
|
|
@@ -86,6 +113,12 @@ function PageHero({
|
|
|
86
113
|
const textWrapGap =
|
|
87
114
|
Number(getVariableByName('PageHero/textWrap/gap', modes)) || 8
|
|
88
115
|
|
|
116
|
+
// Media slot box — matches the 117×117 frame in Figma (node 4540:7845).
|
|
117
|
+
// Tokens fall back to 117 when not defined in the variables collection,
|
|
118
|
+
// so the layout stays stable on consumers that haven't tokenized this yet.
|
|
119
|
+
const mediaWidth = Number(getVariableByName('media/width', modes)) || 117
|
|
120
|
+
const mediaHeight = Number(getVariableByName('media/height', modes)) || 117
|
|
121
|
+
|
|
89
122
|
const eyebrowColor =
|
|
90
123
|
getVariableByName('PageHero/eyebrow/color', modes) || '#ffffff'
|
|
91
124
|
const eyebrowFontFamily =
|
|
@@ -183,8 +216,32 @@ function PageHero({
|
|
|
183
216
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
184
217
|
}, [buttonSlot, showButton, buttonLabel, onButtonPress, modes])
|
|
185
218
|
|
|
219
|
+
// Sized container for the media slot. Always rendered when `media` is
|
|
220
|
+
// provided, so the slot has a predictable box (matches Figma frame
|
|
221
|
+
// 4540:7845 — 117×117 by default) even if the inner element omits its
|
|
222
|
+
// own width/height. `overflow: 'hidden'` mirrors the Figma frame's
|
|
223
|
+
// `clipsContent` so a slightly oversized illustration doesn't break
|
|
224
|
+
// the centered layout.
|
|
225
|
+
const mediaContent = useMemo<React.ReactNode>(() => {
|
|
226
|
+
if (media === undefined || media === null) return null
|
|
227
|
+
return (
|
|
228
|
+
<View
|
|
229
|
+
style={{
|
|
230
|
+
width: mediaWidth,
|
|
231
|
+
height: mediaHeight,
|
|
232
|
+
alignItems: 'center',
|
|
233
|
+
justifyContent: 'center',
|
|
234
|
+
overflow: 'hidden',
|
|
235
|
+
}}
|
|
236
|
+
>
|
|
237
|
+
{cloneChildrenWithModes(media, modes)}
|
|
238
|
+
</View>
|
|
239
|
+
)
|
|
240
|
+
}, [media, mediaWidth, mediaHeight, modes])
|
|
241
|
+
|
|
186
242
|
return (
|
|
187
243
|
<View style={[containerStyle, style]} testID={testID}>
|
|
244
|
+
{mediaContent}
|
|
188
245
|
<View style={textWrapStyle}>
|
|
189
246
|
{eyebrow ? <Text style={eyebrowStyle}>{eyebrow}</Text> : null}
|
|
190
247
|
{headline ? <Text style={headlineStyle}>{headline}</Text> : null}
|
|
@@ -1,11 +1,26 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import { View, Text,
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, Text, type ViewStyle } from 'react-native';
|
|
3
3
|
import ButtonGroup from '../ButtonGroup/ButtonGroup';
|
|
4
4
|
import AvatarGroup from '../AvatarGroup/AvatarGroup';
|
|
5
5
|
import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
|
|
6
6
|
import { EMPTY_MODES } from '../../utils/react-utils';
|
|
7
7
|
import MoneyValue from '../MoneyValue/MoneyValue';
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
// Defaults applied to the inner ButtonGroup so the card matches Figma out of
|
|
10
|
+
// the box. They are spread *before* the caller's `modes` so any consumer can
|
|
11
|
+
// override an individual key (e.g. swap the size to "M").
|
|
12
|
+
const DEFAULT_BUTTON_GROUP_MODES: Record<string, string> = {
|
|
13
|
+
AppearanceBrand: 'Secondary',
|
|
14
|
+
'Button / Size': 'S',
|
|
15
|
+
Emphasis: 'High',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Defaults applied to the inner MoneyValue so the price renders at the
|
|
19
|
+
// 36 px / 900-weight scale defined for cards in Figma. Same merge rule as
|
|
20
|
+
// the button group — consumer `modes` override these.
|
|
21
|
+
const DEFAULT_MONEY_VALUE_MODES: Record<string, string> = {
|
|
22
|
+
Context3: 'Balance & Cards',
|
|
23
|
+
};
|
|
9
24
|
|
|
10
25
|
|
|
11
26
|
export type RechargeCardProps = {
|
|
@@ -66,17 +81,19 @@ export default function RechargeCard({
|
|
|
66
81
|
modes = EMPTY_MODES,
|
|
67
82
|
style,
|
|
68
83
|
}: RechargeCardProps) {
|
|
69
|
-
// Container Tokens
|
|
70
|
-
const backgroundColor = getVariableByName('rechargeCard/background', modes) || '#
|
|
84
|
+
// Container Tokens (defaults mirror Figma node 2235:937).
|
|
85
|
+
const backgroundColor = getVariableByName('rechargeCard/background', modes) || '#ffffff';
|
|
71
86
|
const paddingHorizontal = parseInt(getVariableByName('rechargeCard/padding/horizontal', modes) || 16, 10);
|
|
72
87
|
const paddingVertical = parseInt(getVariableByName('rechargeCard/padding/vertical', modes) || 20, 10);
|
|
73
88
|
const gap = parseInt(getVariableByName('rechargeCard/gap', modes) || 20, 10);
|
|
74
89
|
const radius = parseInt(getVariableByName('rechargeCard/radius', modes) || 20, 10);
|
|
75
|
-
const minWidth = parseInt(getVariableByName('rechargeCard/minWidth', modes) ||
|
|
90
|
+
const minWidth = parseInt(getVariableByName('rechargeCard/minWidth', modes) || 312, 10);
|
|
91
|
+
const strokeWidth = parseInt(getVariableByName('rechargeCard/strokeWidth', modes) || 1, 10);
|
|
92
|
+
const strokeColor = getVariableByName('rechargeCard/stroke/color', modes) || '#ebebed';
|
|
76
93
|
|
|
77
94
|
// Header Tokens
|
|
78
95
|
const headerGap = parseInt(getVariableByName('rechargeCard/header/gap', modes) || 4, 10);
|
|
79
|
-
const titleColor = getVariableByName('rechargeCard/title/color', modes) || '#
|
|
96
|
+
const titleColor = getVariableByName('rechargeCard/title/color', modes) || '#000000';
|
|
80
97
|
const titleFontSize = parseInt(getVariableByName('rechargeCard/title/fontSize', modes) || 12, 10);
|
|
81
98
|
const titleFontFamily = getVariableByName('rechargeCard/title/fontFamily', modes) || 'JioType Var';
|
|
82
99
|
const titleLineHeight = parseInt(getVariableByName('rechargeCard/title/lineHeight', modes) || 14, 10);
|
|
@@ -87,30 +104,26 @@ export default function RechargeCard({
|
|
|
87
104
|
const specItemGap = parseInt(getVariableByName('rechargeCard/specItem/gap', modes) || 4, 10);
|
|
88
105
|
|
|
89
106
|
// Spec Label Tokens
|
|
90
|
-
const specLabelColor = getVariableByName('rechargeCard/specItem/label/color', modes) || '#
|
|
107
|
+
const specLabelColor = getVariableByName('rechargeCard/specItem/label/color', modes) || '#000000';
|
|
91
108
|
const specLabelFontSize = parseInt(getVariableByName('rechargeCard/specItem/label/fontSize', modes) || 12, 10);
|
|
92
109
|
const specLabelFontFamily = getVariableByName('rechargeCard/specItem/label/fontFamily', modes) || 'JioType Var';
|
|
93
110
|
const specLabelLineHeight = parseInt(getVariableByName('rechargeCard/specItem/label/lineHeight', modes) || 14, 10);
|
|
94
111
|
const specLabelFontWeight = getVariableByName('rechargeCard/specItem/label/fontWeight', modes) || '500';
|
|
95
112
|
|
|
96
113
|
// Spec Value Tokens
|
|
97
|
-
const specValueColor = getVariableByName('rechargeCard/specItem/value/color', modes) || '#
|
|
114
|
+
const specValueColor = getVariableByName('rechargeCard/specItem/value/color', modes) || '#000000';
|
|
98
115
|
const specValueFontSize = parseInt(getVariableByName('rechargeCard/specItem/value/fontSize', modes) || 14, 10);
|
|
99
116
|
const specValueFontFamily = getVariableByName('rechargeCard/specItem/value/fontFamily', modes) || 'JioType Var';
|
|
100
117
|
const specValueLineHeight = parseInt(getVariableByName('rechargeCard/specItem/value/lineHeight', modes) || 17, 10);
|
|
101
118
|
const specValueFontWeight = getVariableByName('rechargeCard/specItem/value/fontWeight', modes) || '500';
|
|
102
119
|
|
|
103
120
|
// Disclaimer Tokens
|
|
104
|
-
const disclaimerColor = getVariableByName('rechargeCard/disclaimer/color', modes) || '#
|
|
121
|
+
const disclaimerColor = getVariableByName('rechargeCard/disclaimer/color', modes) || '#000000';
|
|
105
122
|
const disclaimerFontSize = parseInt(getVariableByName('rechargeCard/disclaimer/fontSize', modes) || 10, 10);
|
|
106
123
|
const disclaimerFontFamily = getVariableByName('rechargeCard/disclaimer/fontFamily', modes) || 'JioType Var';
|
|
107
124
|
const disclaimerLineHeight = parseInt(getVariableByName('rechargeCard/disclaimer/lineHeight', modes) || 13, 10);
|
|
108
125
|
const disclaimerFontWeight = getVariableByName('rechargeCard/disclaimer/fontWeight', modes) || '400';
|
|
109
126
|
|
|
110
|
-
// Button Group Tokens
|
|
111
|
-
// Handled by ButtonGroup component directly
|
|
112
|
-
|
|
113
|
-
// Helpers
|
|
114
127
|
const resolveFontWeight = (weight: string | number) => typeof weight === 'number' ? weight.toString() : weight;
|
|
115
128
|
|
|
116
129
|
// Pass modes to subscription children (e.g. AvatarGroup)
|
|
@@ -125,6 +138,8 @@ export default function RechargeCard({
|
|
|
125
138
|
paddingVertical,
|
|
126
139
|
gap,
|
|
127
140
|
borderRadius: radius,
|
|
141
|
+
borderWidth: strokeWidth,
|
|
142
|
+
borderColor: strokeColor,
|
|
128
143
|
minWidth,
|
|
129
144
|
alignItems: 'flex-start',
|
|
130
145
|
}, style]}>
|
|
@@ -142,7 +157,7 @@ export default function RechargeCard({
|
|
|
142
157
|
<MoneyValue
|
|
143
158
|
value={price}
|
|
144
159
|
currency="₹"
|
|
145
|
-
modes={modes}
|
|
160
|
+
modes={{ ...DEFAULT_MONEY_VALUE_MODES, ...modes }}
|
|
146
161
|
/>
|
|
147
162
|
</View>
|
|
148
163
|
|
|
@@ -224,15 +239,8 @@ export default function RechargeCard({
|
|
|
224
239
|
{disclaimer}
|
|
225
240
|
</Text>
|
|
226
241
|
|
|
227
|
-
{/* Button Group */}
|
|
228
|
-
<ButtonGroup
|
|
229
|
-
modes={{
|
|
230
|
-
...modes,
|
|
231
|
-
"Appearance.Brand": "Secondary",
|
|
232
|
-
"Button / Size": "S",
|
|
233
|
-
"Emphasis": "High"
|
|
234
|
-
}}
|
|
235
|
-
>
|
|
242
|
+
{/* Button Group: defaults are overridable via the consumer's `modes` */}
|
|
243
|
+
<ButtonGroup modes={{ ...DEFAULT_BUTTON_GROUP_MODES, ...modes }}>
|
|
236
244
|
{actions}
|
|
237
245
|
</ButtonGroup>
|
|
238
246
|
</View>
|
|
@@ -3,7 +3,7 @@ import { View, Text, type ViewStyle, type TextStyle } from 'react-native'
|
|
|
3
3
|
import Svg, { Path } from 'react-native-svg'
|
|
4
4
|
import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
|
|
5
5
|
import { StepLabel } from './StepLabel'
|
|
6
|
-
import { EMPTY_MODES } from '../../utils/react-utils'
|
|
6
|
+
import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils'
|
|
7
7
|
|
|
8
8
|
export type StepStatus = 'number' | 'complete' | 'error' | 'warning'
|
|
9
9
|
|
|
@@ -14,14 +14,21 @@ export type StepProps = {
|
|
|
14
14
|
// Injected by Stepper, or provided manually
|
|
15
15
|
index?: number
|
|
16
16
|
|
|
17
|
-
//
|
|
17
|
+
// Connector line visibility — explicit prop (Figma `showLine`).
|
|
18
|
+
// Stepper sets this to false on the last item.
|
|
19
|
+
showLine?: boolean
|
|
20
|
+
|
|
21
|
+
// Custom style for the connecting line. Kept for backwards compatibility;
|
|
22
|
+
// when provided, it is merged on top of the default line style.
|
|
18
23
|
connectorStyle?: ViewStyle
|
|
19
24
|
|
|
20
|
-
//
|
|
25
|
+
// Content props matching Figma component interface
|
|
21
26
|
title?: string
|
|
22
27
|
supportingText?: string
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
metaText?: string
|
|
29
|
+
subtitle?: boolean
|
|
30
|
+
meta?: boolean
|
|
31
|
+
status?: StepStatus
|
|
25
32
|
}
|
|
26
33
|
|
|
27
34
|
export function Step({
|
|
@@ -29,35 +36,37 @@ export function Step({
|
|
|
29
36
|
modes = EMPTY_MODES,
|
|
30
37
|
style,
|
|
31
38
|
index = 0,
|
|
39
|
+
showLine = true,
|
|
32
40
|
connectorStyle,
|
|
33
41
|
title,
|
|
34
42
|
supportingText,
|
|
43
|
+
metaText,
|
|
35
44
|
subtitle = true,
|
|
45
|
+
meta = true,
|
|
36
46
|
status = 'number',
|
|
37
47
|
}: StepProps) {
|
|
38
|
-
// Container styles
|
|
39
48
|
const minHeight =
|
|
40
49
|
Number(getVariableByName('steperItem/minHeight', modes) as unknown) || 52
|
|
41
50
|
const gap =
|
|
42
|
-
Number(getVariableByName('steperItem/gap', modes) as unknown) ||
|
|
51
|
+
Number(getVariableByName('steperItem/gap', modes) as unknown) || 16
|
|
43
52
|
|
|
44
|
-
// Indicator dimensions and styles
|
|
45
53
|
const indicatorSize =
|
|
46
|
-
Number(getVariableByName('stepIndicator/size', modes) as unknown) ||
|
|
54
|
+
Number(getVariableByName('stepIndicator/size', modes) as unknown) || 36
|
|
47
55
|
const indicatorRadius =
|
|
48
56
|
Number(getVariableByName('stepIndicator/radius', modes) as unknown) || 9999
|
|
49
57
|
const indicatorBg =
|
|
50
58
|
(getVariableByName('stepIndicator/background', modes) as string) ||
|
|
51
|
-
'#
|
|
59
|
+
'#5d00b5'
|
|
52
60
|
const indicatorBorderColor =
|
|
53
61
|
(getVariableByName('stepIndicator/border/color', modes) as string) ||
|
|
54
|
-
'#
|
|
62
|
+
'#5d00b5'
|
|
55
63
|
const indicatorBorderSize =
|
|
56
64
|
Number(getVariableByName('stepIndicator/border/size', modes) as unknown) || 1
|
|
57
65
|
const iconColor =
|
|
58
66
|
(getVariableByName('stepIndicator/icon/color', modes) as string) || '#ffffff'
|
|
67
|
+
const stepStatusSize =
|
|
68
|
+
Number(getVariableByName('stepStatus/size', modes) as unknown) || 18
|
|
59
69
|
|
|
60
|
-
// Label styles (for number)
|
|
61
70
|
const labelFontSize =
|
|
62
71
|
Number(getVariableByName('stepIndicator/label/fontSize', modes) as unknown) || 12
|
|
63
72
|
const labelFontFamily =
|
|
@@ -67,28 +76,28 @@ export function Step({
|
|
|
67
76
|
const labelFontWeight =
|
|
68
77
|
(getVariableByName('stepIndicator/label/fontWeight', modes) as string) || '500'
|
|
69
78
|
|
|
70
|
-
// Vertical line styles
|
|
71
79
|
const lineSize =
|
|
72
80
|
Number(getVariableByName('steperItem/lineSize', modes) as unknown) || 2
|
|
73
81
|
const lineColor =
|
|
74
|
-
(getVariableByName('steperItem/line', modes) as string) || '#
|
|
82
|
+
(getVariableByName('steperItem/line', modes) as string) || '#5d00b5'
|
|
75
83
|
const badgeWrapGap =
|
|
76
84
|
Number(getVariableByName('steperItem/badgeWrap/gap', modes) as unknown) || 2
|
|
77
85
|
|
|
78
86
|
const containerStyle: ViewStyle = {
|
|
79
87
|
flexDirection: 'row',
|
|
80
88
|
minHeight,
|
|
89
|
+
gap,
|
|
81
90
|
...style,
|
|
82
91
|
}
|
|
83
92
|
|
|
84
|
-
// FIX: This wrapper should NOT expand. It should be exact width of the indicator.
|
|
85
93
|
const indicatorWrapperStyle: ViewStyle = {
|
|
86
94
|
flexDirection: 'column',
|
|
87
95
|
alignItems: 'center',
|
|
88
96
|
width: indicatorSize,
|
|
89
|
-
flexGrow: 0,
|
|
97
|
+
flexGrow: 0,
|
|
90
98
|
flexShrink: 0,
|
|
91
99
|
gap: badgeWrapGap,
|
|
100
|
+
alignSelf: 'stretch',
|
|
92
101
|
}
|
|
93
102
|
|
|
94
103
|
const indicatorStyle: ViewStyle = {
|
|
@@ -103,6 +112,13 @@ export function Step({
|
|
|
103
112
|
overflow: 'hidden',
|
|
104
113
|
}
|
|
105
114
|
|
|
115
|
+
const stepStatusContainerStyle: ViewStyle = {
|
|
116
|
+
width: stepStatusSize,
|
|
117
|
+
height: stepStatusSize,
|
|
118
|
+
alignItems: 'center',
|
|
119
|
+
justifyContent: 'center',
|
|
120
|
+
}
|
|
121
|
+
|
|
106
122
|
const labelStyle: TextStyle = {
|
|
107
123
|
color: iconColor,
|
|
108
124
|
fontSize: labelFontSize,
|
|
@@ -112,35 +128,31 @@ export function Step({
|
|
|
112
128
|
textAlign: 'center',
|
|
113
129
|
}
|
|
114
130
|
|
|
115
|
-
// Combine base line style with injected connectorStyle
|
|
116
131
|
const lineStyle: ViewStyle = {
|
|
117
132
|
width: lineSize,
|
|
118
133
|
backgroundColor: lineColor,
|
|
119
|
-
flexGrow: 1,
|
|
120
|
-
|
|
134
|
+
flexGrow: 1,
|
|
135
|
+
minHeight: 1,
|
|
136
|
+
...connectorStyle,
|
|
121
137
|
}
|
|
122
138
|
|
|
123
|
-
// Helper for icons
|
|
124
139
|
const renderIcon = () => {
|
|
125
140
|
switch (status) {
|
|
126
141
|
case 'complete':
|
|
127
|
-
// Checkmark
|
|
128
142
|
return (
|
|
129
|
-
<Svg width={
|
|
143
|
+
<Svg width={stepStatusSize} height={stepStatusSize} viewBox="0 0 24 24" fill="none">
|
|
130
144
|
<Path d="M20 6L9 17L4 12" stroke={iconColor} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
|
|
131
145
|
</Svg>
|
|
132
146
|
)
|
|
133
147
|
case 'error':
|
|
134
|
-
// X mark
|
|
135
148
|
return (
|
|
136
|
-
<Svg width={
|
|
149
|
+
<Svg width={stepStatusSize} height={stepStatusSize} viewBox="0 0 24 24" fill="none">
|
|
137
150
|
<Path d="M18 6L6 18M6 6l12 12" stroke={iconColor} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
|
|
138
151
|
</Svg>
|
|
139
152
|
)
|
|
140
153
|
case 'warning':
|
|
141
|
-
// Exclamation / Triangle
|
|
142
154
|
return (
|
|
143
|
-
<Svg width={
|
|
155
|
+
<Svg width={stepStatusSize} height={stepStatusSize} viewBox="0 0 24 24" fill="none">
|
|
144
156
|
<Path d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" stroke={iconColor} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" />
|
|
145
157
|
</Svg>
|
|
146
158
|
)
|
|
@@ -150,42 +162,31 @@ export function Step({
|
|
|
150
162
|
}
|
|
151
163
|
}
|
|
152
164
|
|
|
153
|
-
|
|
154
|
-
const childrenWithProps = React.Children.map(children, (child) => {
|
|
155
|
-
if (React.isValidElement(child)) {
|
|
156
|
-
return React.cloneElement(child, { modes } as any)
|
|
157
|
-
}
|
|
158
|
-
return child
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
// Determine if we have content to pad
|
|
162
|
-
// Default padding bottom to 16 if line is shown, but also respect connectorStyle display
|
|
163
|
-
// If display is none, we probably don't want the padding bottom either.
|
|
164
|
-
const isLineHidden = connectorStyle?.display === 'none'
|
|
165
|
-
const contentPaddingBottom = isLineHidden ? 0 : 16
|
|
165
|
+
const hasSlotChildren = React.Children.count(children) > 0
|
|
166
166
|
|
|
167
167
|
return (
|
|
168
168
|
<View style={containerStyle}>
|
|
169
169
|
<View style={indicatorWrapperStyle}>
|
|
170
170
|
<View style={indicatorStyle}>
|
|
171
|
-
{renderIcon()}
|
|
171
|
+
<View style={stepStatusContainerStyle}>{renderIcon()}</View>
|
|
172
172
|
</View>
|
|
173
|
-
<View style={lineStyle} />
|
|
173
|
+
{showLine ? <View style={lineStyle} /> : null}
|
|
174
174
|
</View>
|
|
175
175
|
|
|
176
|
-
{
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
<View style={{ flex: 1, paddingBottom: contentPaddingBottom }}>
|
|
181
|
-
{title ? (
|
|
176
|
+
<View style={{ flex: 1 }}>
|
|
177
|
+
{hasSlotChildren ? (
|
|
178
|
+
cloneChildrenWithModes(children, modes)
|
|
179
|
+
) : (
|
|
182
180
|
<StepLabel
|
|
183
|
-
title
|
|
184
|
-
|
|
181
|
+
{...(title !== undefined ? { title } : {})}
|
|
182
|
+
{...(supportingText !== undefined
|
|
183
|
+
? { supportingText }
|
|
184
|
+
: {})}
|
|
185
|
+
{...(metaText !== undefined ? { metaText } : {})}
|
|
186
|
+
subtitle={subtitle}
|
|
187
|
+
meta={meta}
|
|
185
188
|
modes={modes}
|
|
186
189
|
/>
|
|
187
|
-
) : (
|
|
188
|
-
childrenWithProps
|
|
189
190
|
)}
|
|
190
191
|
</View>
|
|
191
192
|
</View>
|
|
@@ -6,6 +6,9 @@ import { EMPTY_MODES } from '../../utils/react-utils'
|
|
|
6
6
|
export type StepLabelProps = {
|
|
7
7
|
title?: string
|
|
8
8
|
supportingText?: string
|
|
9
|
+
metaText?: string
|
|
10
|
+
subtitle?: boolean
|
|
11
|
+
meta?: boolean
|
|
9
12
|
modes?: Record<string, any>
|
|
10
13
|
style?: ViewStyle
|
|
11
14
|
}
|
|
@@ -13,10 +16,12 @@ export type StepLabelProps = {
|
|
|
13
16
|
export function StepLabel({
|
|
14
17
|
title = 'Stepper Item',
|
|
15
18
|
supportingText,
|
|
19
|
+
metaText,
|
|
20
|
+
subtitle = true,
|
|
21
|
+
meta = true,
|
|
16
22
|
modes = EMPTY_MODES,
|
|
17
23
|
style,
|
|
18
24
|
}: StepLabelProps) {
|
|
19
|
-
// Title styles
|
|
20
25
|
const titleColor =
|
|
21
26
|
(getVariableByName('steperItem/title/color', modes) as string) || '#0d0d0f'
|
|
22
27
|
const titleFontSize =
|
|
@@ -30,26 +35,46 @@ export function StepLabel({
|
|
|
30
35
|
const titleFontWeight =
|
|
31
36
|
(getVariableByName('steperItem/title/fontWeight', modes) as string) || '700'
|
|
32
37
|
|
|
33
|
-
// Subtitle
|
|
38
|
+
// The Subtitle (supportingText) and Meta both default to the "Neutral"
|
|
39
|
+
// AppearanceBrand. A caller-supplied `AppearanceBrand` still wins (it is
|
|
40
|
+
// spread after the default), so each remains overridable. The Title keeps
|
|
41
|
+
// its own appearance resolution.
|
|
42
|
+
const subtitleModes = { AppearanceBrand: 'Neutral', ...modes }
|
|
43
|
+
const metaModes = { AppearanceBrand: 'Neutral', ...modes }
|
|
44
|
+
|
|
34
45
|
const subtitleColor =
|
|
35
|
-
(getVariableByName('steperItem/subtitle/color',
|
|
46
|
+
(getVariableByName('steperItem/subtitle/color', subtitleModes) as string) ||
|
|
36
47
|
'#3d4047'
|
|
37
48
|
const subtitleFontSize =
|
|
38
49
|
Number(
|
|
39
|
-
getVariableByName('steperItem/subtitle/fontSize',
|
|
50
|
+
getVariableByName('steperItem/subtitle/fontSize', subtitleModes) as unknown
|
|
40
51
|
) || 12
|
|
41
52
|
const subtitleFontFamily =
|
|
42
|
-
(getVariableByName('steperItem/subtitle/fontFamily',
|
|
53
|
+
(getVariableByName('steperItem/subtitle/fontFamily', subtitleModes) as string) ||
|
|
43
54
|
undefined
|
|
44
55
|
const subtitleLineHeight =
|
|
45
56
|
Number(
|
|
46
|
-
getVariableByName('steperItem/subtitle/lineHeight',
|
|
57
|
+
getVariableByName('steperItem/subtitle/lineHeight', subtitleModes) as unknown
|
|
47
58
|
) || 16
|
|
48
59
|
const subtitleFontWeight =
|
|
49
|
-
(getVariableByName('steperItem/subtitle/fontWeight',
|
|
60
|
+
(getVariableByName('steperItem/subtitle/fontWeight', subtitleModes) as string) ||
|
|
50
61
|
'400'
|
|
51
62
|
|
|
52
|
-
|
|
63
|
+
const metaColor =
|
|
64
|
+
(getVariableByName('steperItem/meta/color', metaModes) as string) || '#f7ab21'
|
|
65
|
+
const metaFontSize =
|
|
66
|
+
Number(getVariableByName('steperItem/meta/fontSize', metaModes) as unknown) || 10
|
|
67
|
+
// The Figma variable is authored as "fontFamily Copy" (with a space + suffix).
|
|
68
|
+
// Match the literal Figma name to avoid a missing-variable warning.
|
|
69
|
+
const metaFontFamily =
|
|
70
|
+
(getVariableByName('steperItem/meta/fontFamily Copy', metaModes) as string) ||
|
|
71
|
+
undefined
|
|
72
|
+
const metaLineHeight =
|
|
73
|
+
Number(getVariableByName('steperItem/meta/lineHeight', metaModes) as unknown) ||
|
|
74
|
+
12
|
|
75
|
+
const metaFontWeight =
|
|
76
|
+
(getVariableByName('steperItem/meta/fontWeight', metaModes) as string) || '700'
|
|
77
|
+
|
|
53
78
|
const textGap =
|
|
54
79
|
Number(getVariableByName('steperItem/textWrap/gap', modes) as unknown) || 2
|
|
55
80
|
|
|
@@ -69,12 +94,24 @@ export function StepLabel({
|
|
|
69
94
|
lineHeight: subtitleLineHeight,
|
|
70
95
|
}
|
|
71
96
|
|
|
97
|
+
const metaStyle: TextStyle = {
|
|
98
|
+
color: metaColor,
|
|
99
|
+
fontSize: metaFontSize,
|
|
100
|
+
fontFamily: metaFontFamily,
|
|
101
|
+
fontWeight: metaFontWeight as TextStyle['fontWeight'],
|
|
102
|
+
lineHeight: metaLineHeight,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const showSubtitle = subtitle && !!supportingText
|
|
106
|
+
const showMeta = meta && !!metaText
|
|
107
|
+
|
|
72
108
|
return (
|
|
73
109
|
<View style={[{ gap: textGap, flex: 1 }, style]}>
|
|
74
110
|
<Text style={titleStyle}>{title}</Text>
|
|
75
|
-
{
|
|
111
|
+
{showSubtitle ? (
|
|
76
112
|
<Text style={subtitleStyle}>{supportingText}</Text>
|
|
77
113
|
) : null}
|
|
114
|
+
{showMeta ? <Text style={metaStyle}>{metaText}</Text> : null}
|
|
78
115
|
</View>
|
|
79
116
|
)
|
|
80
117
|
}
|
|
@@ -6,8 +6,10 @@ import { StepLabel } from './StepLabel'
|
|
|
6
6
|
import { EMPTY_MODES } from '../../utils/react-utils'
|
|
7
7
|
|
|
8
8
|
export { Step, StepLabel }
|
|
9
|
+
export type { StepProps, StepStatus } from './Step'
|
|
10
|
+
export type { StepLabelProps } from './StepLabel'
|
|
9
11
|
|
|
10
|
-
type StepperProps = {
|
|
12
|
+
export type StepperProps = {
|
|
11
13
|
children?: React.ReactNode
|
|
12
14
|
modes?: Record<string, any>
|
|
13
15
|
style?: ViewStyle
|
|
@@ -18,7 +20,6 @@ export default function Stepper({
|
|
|
18
20
|
modes = EMPTY_MODES,
|
|
19
21
|
style,
|
|
20
22
|
}: StepperProps) {
|
|
21
|
-
// Stepper container styles
|
|
22
23
|
const paddingHorizontal =
|
|
23
24
|
Number(getVariableByName('stepper/padding/horizontal', modes) as unknown) ||
|
|
24
25
|
8
|
|
@@ -33,20 +34,24 @@ export default function Stepper({
|
|
|
33
34
|
...style,
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
// Inject index and connectorStyle logic into Step children
|
|
37
37
|
const steps = React.Children.toArray(children)
|
|
38
|
-
const
|
|
39
|
-
if (React.isValidElement(child))
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
38
|
+
const stepsWithProps = steps.map((child, stepIndex) => {
|
|
39
|
+
if (!React.isValidElement(child)) return child
|
|
40
|
+
|
|
41
|
+
const isLast = stepIndex === steps.length - 1
|
|
42
|
+
const childProps = (child.props as any) || {}
|
|
43
|
+
const childModes = childProps.modes
|
|
44
|
+
? { ...modes, ...childProps.modes }
|
|
45
|
+
: modes
|
|
46
|
+
|
|
47
|
+
return React.cloneElement(child, {
|
|
48
|
+
...childProps,
|
|
49
|
+
index: childProps.index ?? stepIndex,
|
|
50
|
+
modes: childModes,
|
|
51
|
+
showLine:
|
|
52
|
+
childProps.showLine !== undefined ? childProps.showLine : !isLast,
|
|
53
|
+
} as any)
|
|
49
54
|
})
|
|
50
55
|
|
|
51
|
-
return <View style={containerStyle}>{
|
|
56
|
+
return <View style={containerStyle}>{stepsWithProps}</View>
|
|
52
57
|
}
|