jfs-components 0.1.36 → 0.1.49
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 +29 -0
- package/lib/commonjs/components/Accordion/Accordion.js +16 -3
- package/lib/commonjs/components/AppBar/AppBar.js +118 -93
- package/lib/commonjs/components/CompareTable/CompareTable.js +98 -33
- package/lib/commonjs/components/FormField/FormField.js +9 -1
- package/lib/commonjs/components/FullscreenModal/FullscreenModal.js +4 -14
- package/lib/commonjs/components/HelloJioInput/HelloJioInput.js +20 -4
- package/lib/commonjs/components/PageHero/PageHero.js +3 -0
- package/lib/commonjs/components/ProductMerchandisingCard/ProductMerchandisingCard.js +50 -30
- package/lib/commonjs/components/Section/Section.js +3 -1
- package/lib/commonjs/components/ValueBackMetric/ValueBackMetric.js +117 -89
- package/lib/commonjs/components/index.js +7 -1
- package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -42204
- package/lib/commonjs/design-tokens/figma-modes.generated.js +8 -7
- package/lib/commonjs/icons/registry.js +1 -1
- package/lib/module/components/Accordion/Accordion.js +16 -3
- package/lib/module/components/AppBar/AppBar.js +116 -93
- package/lib/module/components/CompareTable/CompareTable.js +99 -34
- package/lib/module/components/FormField/FormField.js +9 -1
- package/lib/module/components/FullscreenModal/FullscreenModal.js +4 -14
- package/lib/module/components/HelloJioInput/HelloJioInput.js +20 -4
- package/lib/module/components/PageHero/PageHero.js +3 -0
- package/lib/module/components/ProductMerchandisingCard/ProductMerchandisingCard.js +50 -30
- package/lib/module/components/Section/Section.js +3 -1
- package/lib/module/components/ValueBackMetric/ValueBackMetric.js +120 -93
- package/lib/module/components/index.js +1 -1
- package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -42204
- package/lib/module/design-tokens/figma-modes.generated.js +8 -7
- package/lib/module/icons/registry.js +1 -1
- package/lib/typescript/src/components/Accordion/Accordion.d.ts +14 -1
- package/lib/typescript/src/components/AppBar/AppBar.d.ts +46 -14
- package/lib/typescript/src/components/CompareTable/CompareTable.d.ts +29 -12
- package/lib/typescript/src/components/HelloJioInput/HelloJioInput.d.ts +6 -4
- package/lib/typescript/src/components/PageHero/PageHero.d.ts +1 -0
- package/lib/typescript/src/components/ProductMerchandisingCard/ProductMerchandisingCard.d.ts +8 -1
- package/lib/typescript/src/components/Section/Section.d.ts +2 -1
- package/lib/typescript/src/components/ValueBackMetric/ValueBackMetric.d.ts +27 -16
- package/lib/typescript/src/components/index.d.ts +1 -1
- package/lib/typescript/src/design-tokens/figma-modes.generated.d.ts +2 -1
- package/lib/typescript/src/icons/registry.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/Accordion/Accordion.tsx +61 -33
- package/src/components/AppBar/AppBar.tsx +154 -124
- package/src/components/CompareTable/CompareTable.tsx +138 -52
- package/src/components/FormField/FormField.tsx +7 -0
- package/src/components/FullscreenModal/FullscreenModal.tsx +5 -14
- package/src/components/HelloJioInput/HelloJioInput.tsx +31 -12
- package/src/components/PageHero/PageHero.tsx +5 -0
- package/src/components/ProductMerchandisingCard/ProductMerchandisingCard.tsx +63 -30
- package/src/components/Section/Section.tsx +121 -156
- package/src/components/ValueBackMetric/ValueBackMetric.tsx +178 -104
- package/src/components/index.ts +6 -1
- package/src/design-tokens/Coin Variables-variables-full.json +1 -42204
- package/src/design-tokens/figma-modes.generated.ts +8 -7
- package/src/icons/registry.ts +1 -1
- package/D2C.md +0 -113
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import React from 'react'
|
|
1
|
+
import React, { useMemo } from 'react'
|
|
2
2
|
import {
|
|
3
3
|
View,
|
|
4
|
-
Text,
|
|
4
|
+
Text as RNText,
|
|
5
5
|
Pressable,
|
|
6
6
|
type StyleProp,
|
|
7
7
|
type ViewStyle,
|
|
@@ -11,35 +11,18 @@ import {
|
|
|
11
11
|
import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
|
|
12
12
|
import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils'
|
|
13
13
|
import Icon from '../Icon/Icon'
|
|
14
|
-
import
|
|
14
|
+
import Text from '../Text/Text'
|
|
15
15
|
import type { Modes } from '../../design-tokens'
|
|
16
16
|
|
|
17
17
|
const TITLE_LINE_HEIGHT_RATIO = 1.2
|
|
18
18
|
const VALUE_LINE_HEIGHT_RATIO = 1.2
|
|
19
19
|
const CAPTION_LINE_HEIGHT_RATIO = 1.5
|
|
20
|
-
|
|
21
|
-
// The Figma node binds the header-icon size and the per-part font sizes/weights
|
|
22
|
-
// to `valueBackMetric/*` variables, but those tokens are NOT in the committed
|
|
23
|
-
// variables snapshot (`npm run tokens -- find valueBackMetric` → no matches).
|
|
24
|
-
// They also intentionally differ from the `metricdata/*` typography defaults
|
|
25
|
-
// (e.g. `metricdata/value` resolves to 20px/700, whereas this component's value
|
|
26
|
-
// is 16px/500). So the sizes/weights below are encoded as literal constants
|
|
27
|
-
// matching the Figma design exactly. Colours, gaps and padding DO exist as real
|
|
28
|
-
// `metricdata/*` tokens (and match the design), so those resolve through
|
|
29
|
-
// `getVariableByName` and stay themeable.
|
|
30
|
-
const TITLE_FONT_SIZE = 12
|
|
31
|
-
const TITLE_FONT_WEIGHT: TextStyle['fontWeight'] = '500'
|
|
32
|
-
const VALUE_FONT_SIZE = 16
|
|
33
|
-
const VALUE_FONT_WEIGHT: TextStyle['fontWeight'] = '500'
|
|
34
|
-
const CAPTION_FONT_SIZE = 12
|
|
35
|
-
const CAPTION_FONT_WEIGHT: TextStyle['fontWeight'] = '400'
|
|
36
|
-
const FONT_FAMILY = 'JioType Var'
|
|
37
|
-
const CARD_BACKGROUND = '#ffffff'
|
|
38
20
|
const CARD_MIN_HEIGHT = 82
|
|
39
21
|
const ICON_SIZE = 18
|
|
22
|
+
const TEXT_WRAP_GAP = 4
|
|
23
|
+
|
|
40
24
|
// Figma renders the header glyph flush (all `icon/padding/*` tokens are 0); the
|
|
41
|
-
// shared Icon pulls padding from those tokens, so
|
|
42
|
-
// explicitly to keep the icon flush against the title.
|
|
25
|
+
// shared Icon pulls padding from those tokens, so zero it explicitly.
|
|
43
26
|
const ICON_PADDING_RESET: ViewStyle = {
|
|
44
27
|
paddingLeft: 0,
|
|
45
28
|
paddingRight: 0,
|
|
@@ -69,19 +52,31 @@ export type ValueBackMetricProps = {
|
|
|
69
52
|
value?: string | React.ReactNode
|
|
70
53
|
/** Muted caption below the value (12px, `#777`). Hidden when omitted. */
|
|
71
54
|
caption?: string
|
|
72
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* Bottom CTA label rendered as the shared {@link Text} (purple 12px via
|
|
57
|
+
* seeded `Text Appearance: Secondary` + `Text Sizes: Small`). Hidden when
|
|
58
|
+
* omitted. Ignored when the {@link link} slot is provided.
|
|
59
|
+
*/
|
|
73
60
|
linkLabel?: string
|
|
74
|
-
/**
|
|
61
|
+
/**
|
|
62
|
+
* Real slot for the bottom CTA. Highest precedence — when provided, these
|
|
63
|
+
* children render instead of the declarative `linkLabel` Text. Seeded
|
|
64
|
+
* `Text Appearance: Secondary` + `Text Sizes: Small` cascade into the slot
|
|
65
|
+
* (so a bare `<Text text="Earn" />` matches the design); child-level modes
|
|
66
|
+
* still win.
|
|
67
|
+
*/
|
|
68
|
+
link?: React.ReactNode
|
|
69
|
+
/** Fired when the declarative CTA (`linkLabel`) is pressed. */
|
|
75
70
|
onLinkPress?: (event: GestureResponderEvent) => void
|
|
76
71
|
/**
|
|
77
72
|
* Press handler for the whole card. When set, the card becomes pressable
|
|
78
73
|
* (rendered through a `Pressable` with `accessibilityRole="button"`).
|
|
79
|
-
* Independent of {@link onLinkPress} — the bottom
|
|
74
|
+
* Independent of {@link onLinkPress} — the bottom CTA keeps its own handler.
|
|
80
75
|
*/
|
|
81
76
|
onPress?: (event: GestureResponderEvent) => void
|
|
82
77
|
/** Disable interaction when `onPress` is set. */
|
|
83
78
|
disabled?: boolean
|
|
84
|
-
/** Design-token modes for theming. */
|
|
79
|
+
/** Design-token modes for theming. Cascaded to slot children. */
|
|
85
80
|
modes?: Modes
|
|
86
81
|
/** Override the container styles. */
|
|
87
82
|
style?: StyleProp<ViewStyle>
|
|
@@ -98,22 +93,114 @@ export type ValueBackMetricProps = {
|
|
|
98
93
|
accessibilityLabel?: string
|
|
99
94
|
}
|
|
100
95
|
|
|
96
|
+
interface ValueBackMetricTokens {
|
|
97
|
+
titleColor: string
|
|
98
|
+
titleFontFamily: string
|
|
99
|
+
titleFontSize: number
|
|
100
|
+
titleFontWeight: TextStyle['fontWeight']
|
|
101
|
+
valueColor: string
|
|
102
|
+
valueFontFamily: string
|
|
103
|
+
valueFontSize: number
|
|
104
|
+
valueFontWeight: TextStyle['fontWeight']
|
|
105
|
+
captionColor: string
|
|
106
|
+
captionFontFamily: string
|
|
107
|
+
captionFontSize: number
|
|
108
|
+
captionFontWeight: TextStyle['fontWeight']
|
|
109
|
+
gap: number
|
|
110
|
+
valueWrapGap: number
|
|
111
|
+
paddingHorizontal: number
|
|
112
|
+
paddingVertical: number
|
|
113
|
+
backgroundColor: string
|
|
114
|
+
iconColor: string
|
|
115
|
+
iconSize: number
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// The `valueBackMetric/*` layout + typography tokens are bound on the Figma
|
|
119
|
+
// node but are NOT yet in the committed variables snapshot
|
|
120
|
+
// (`npm run tokens -- find valueBackMetric` → no matches). Colours and the
|
|
121
|
+
// header-row gap do exist as `metricdata/*` / `icon/*` tokens. Until the
|
|
122
|
+
// export is re-synced, `getVariableByName` returns undefined for the
|
|
123
|
+
// valueBackMetric names and the Figma-node fallbacks below take over.
|
|
124
|
+
function resolveTokens(modes: Modes): ValueBackMetricTokens {
|
|
125
|
+
const titleColor = (getVariableByName('metricdata/title/color', modes) as string | null) ?? '#000000'
|
|
126
|
+
const valueColor = (getVariableByName('metricdata/value/color', modes) as string | null) ?? '#000000'
|
|
127
|
+
const captionColor = (getVariableByName('metricdata/caption/color', modes) as string | null) ?? '#777777'
|
|
128
|
+
|
|
129
|
+
const titleFontFamily =
|
|
130
|
+
(getVariableByName('valueBackMetric/title/fontfamily', modes) as string | null) ?? 'JioType Var'
|
|
131
|
+
const titleFontSize =
|
|
132
|
+
(getVariableByName('valueBackMetric/title/fontsize', modes) as number | null) ?? 12
|
|
133
|
+
const titleFontWeight = String(
|
|
134
|
+
getVariableByName('valueBackMetric/title/fontweight', modes) ?? 500
|
|
135
|
+
) as TextStyle['fontWeight']
|
|
136
|
+
|
|
137
|
+
const valueFontFamily =
|
|
138
|
+
(getVariableByName('valueBackMetric/value/fontfamily', modes) as string | null) ?? 'JioType Var'
|
|
139
|
+
const valueFontSize =
|
|
140
|
+
(getVariableByName('valueBackMetric/value/fontsize', modes) as number | null) ?? 16
|
|
141
|
+
// Figma binds the value face to JioType Medium; there is no dedicated
|
|
142
|
+
// valueBackMetric/value/fontweight token yet, so fall back to 500.
|
|
143
|
+
const valueFontWeight = '500' as TextStyle['fontWeight']
|
|
144
|
+
|
|
145
|
+
const captionFontFamily =
|
|
146
|
+
(getVariableByName('valueBackMetric/caption/fontfamily', modes) as string | null) ?? 'JioType Var'
|
|
147
|
+
const captionFontSize =
|
|
148
|
+
(getVariableByName('valueBackMetric/caption/fontsize', modes) as number | null) ?? 12
|
|
149
|
+
const captionFontWeight = String(
|
|
150
|
+
getVariableByName('valueBackMetric/caption/fontweight', modes) ?? 400
|
|
151
|
+
) as TextStyle['fontWeight']
|
|
152
|
+
|
|
153
|
+
const gap = (getVariableByName('valueBackMetric/gap', modes) as number | null) ?? 4
|
|
154
|
+
const valueWrapGap = (getVariableByName('metricdata/valueWrap/gap', modes) as number | null) ?? 4
|
|
155
|
+
// Design padding is 0 — do NOT fall back to metricdata/padding (10).
|
|
156
|
+
const paddingHorizontal =
|
|
157
|
+
(getVariableByName('valueBackMetric/padding/horizontal', modes) as number | null) ?? 0
|
|
158
|
+
const paddingVertical =
|
|
159
|
+
(getVariableByName('valueBackMetric/padding/vertical', modes) as number | null) ?? 0
|
|
160
|
+
const backgroundColor =
|
|
161
|
+
(getVariableByName('valueBackMetric/background/color', modes) as string | null) ?? '#ffffff'
|
|
162
|
+
|
|
163
|
+
const iconColor = (getVariableByName('icon/color', modes) as string | null) ?? '#ad8444'
|
|
164
|
+
const iconSize = (getVariableByName('icon/size', modes) as number | null) ?? ICON_SIZE
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
titleColor,
|
|
168
|
+
titleFontFamily,
|
|
169
|
+
titleFontSize,
|
|
170
|
+
titleFontWeight,
|
|
171
|
+
valueColor,
|
|
172
|
+
valueFontFamily,
|
|
173
|
+
valueFontSize,
|
|
174
|
+
valueFontWeight,
|
|
175
|
+
captionColor,
|
|
176
|
+
captionFontFamily,
|
|
177
|
+
captionFontSize,
|
|
178
|
+
captionFontWeight,
|
|
179
|
+
gap,
|
|
180
|
+
valueWrapGap,
|
|
181
|
+
paddingHorizontal,
|
|
182
|
+
paddingVertical,
|
|
183
|
+
backgroundColor,
|
|
184
|
+
iconColor,
|
|
185
|
+
iconSize,
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
101
189
|
/**
|
|
102
190
|
* ValueBackMetric — a compact, left-aligned "value back" card.
|
|
103
191
|
*
|
|
104
192
|
* Stacks a branded header row (icon + `title`, e.g. "JioPoints"), a prominent
|
|
105
|
-
* `value`, a muted `caption`, and an optional bottom `linkLabel`
|
|
106
|
-
* `value`, `caption` and
|
|
107
|
-
* (icon + title) always shows.
|
|
193
|
+
* `value`, a muted `caption`, and an optional bottom CTA (`linkLabel` / `link`
|
|
194
|
+
* slot, e.g. "Earn"). `value`, `caption` and the CTA each render only when
|
|
195
|
+
* provided; the header (icon + title) always shows.
|
|
108
196
|
*
|
|
109
|
-
* Colours
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* matching the design.
|
|
197
|
+
* Colours resolve from the `metricdata/*` tokens; the header glyph from the
|
|
198
|
+
* `icon/*` tokens (default 18px gold); the CTA from the shared {@link Text}
|
|
199
|
+
* with `Text Appearance: Secondary` + `Text Sizes: Small` seeded so it renders
|
|
200
|
+
* purple at 12px like the design (caller `modes` win). Layout/typography
|
|
201
|
+
* follow the Figma `valueBackMetric/*` variables — not yet in the committed
|
|
202
|
+
* token snapshot, so they resolve through `getVariableByName` with Figma-node
|
|
203
|
+
* fallbacks.
|
|
117
204
|
*
|
|
118
205
|
* @example
|
|
119
206
|
* ```tsx
|
|
@@ -133,6 +220,7 @@ function ValueBackMetric({
|
|
|
133
220
|
value,
|
|
134
221
|
caption,
|
|
135
222
|
linkLabel,
|
|
223
|
+
link,
|
|
136
224
|
onLinkPress,
|
|
137
225
|
onPress,
|
|
138
226
|
disabled,
|
|
@@ -143,76 +231,56 @@ function ValueBackMetric({
|
|
|
143
231
|
captionStyle,
|
|
144
232
|
accessibilityLabel,
|
|
145
233
|
}: ValueBackMetricProps) {
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
//
|
|
150
|
-
|
|
151
|
-
// header icon keeps the default gold `icon/color`. Seed only the link's
|
|
152
|
-
// modes; caller-supplied modes win.
|
|
153
|
-
const linkModes = React.useMemo<Modes>(
|
|
234
|
+
const tokens = useMemo(() => resolveTokens(modes), [modes])
|
|
235
|
+
|
|
236
|
+
// Figma Code-Connects the CTA to Text (not Link): purple, no underline.
|
|
237
|
+
// Seed Secondary + Small so it matches the design; caller modes win.
|
|
238
|
+
const linkModes = useMemo<Modes>(
|
|
154
239
|
() => ({ 'Text Appearance': 'Secondary', 'Text Sizes': 'Small', ...modes }),
|
|
155
240
|
[modes]
|
|
156
241
|
)
|
|
157
242
|
|
|
158
|
-
// The header glyph is token-driven: `icon/color` (gold by default, retinted
|
|
159
|
-
// via `AppearanceBrand`) and `icon/size` (18px). Passing them explicitly — as
|
|
160
|
-
// MetricData does — makes the glyph deterministic instead of relying on the
|
|
161
|
-
// shared Icon's internal token lookups.
|
|
162
|
-
const iconColor = (getVariableByName('icon/color', modes) as string | null) ?? '#ad8444'
|
|
163
|
-
const iconSize = (getVariableByName('icon/size', modes) as number | null) ?? ICON_SIZE
|
|
164
|
-
|
|
165
|
-
const gap = (getVariableByName('metricdata/gap', modes) as number | null) ?? 4
|
|
166
|
-
const valueWrapGap = (getVariableByName('metricdata/valueWrap/gap', modes) as number | null) ?? 4
|
|
167
|
-
const paddingHorizontal = (getVariableByName('metricdata/padding/horizontal', modes) as number | null) ?? 10
|
|
168
|
-
const paddingVertical = (getVariableByName('metricdata/padding/vertical', modes) as number | null) ?? 10
|
|
169
|
-
|
|
170
243
|
const containerStyle: ViewStyle = {
|
|
171
244
|
flexDirection: 'column',
|
|
172
245
|
alignItems: 'flex-start',
|
|
173
246
|
justifyContent: 'center',
|
|
174
|
-
gap,
|
|
175
|
-
paddingHorizontal,
|
|
176
|
-
paddingVertical,
|
|
247
|
+
gap: tokens.gap,
|
|
248
|
+
paddingHorizontal: tokens.paddingHorizontal,
|
|
249
|
+
paddingVertical: tokens.paddingVertical,
|
|
177
250
|
minHeight: CARD_MIN_HEIGHT,
|
|
178
|
-
backgroundColor:
|
|
251
|
+
backgroundColor: tokens.backgroundColor,
|
|
179
252
|
}
|
|
180
253
|
|
|
181
254
|
const titleTextStyle: TextStyle = {
|
|
182
|
-
color: titleColor,
|
|
183
|
-
fontFamily:
|
|
184
|
-
fontSize:
|
|
185
|
-
fontWeight:
|
|
186
|
-
lineHeight:
|
|
255
|
+
color: tokens.titleColor,
|
|
256
|
+
fontFamily: tokens.titleFontFamily,
|
|
257
|
+
fontSize: tokens.titleFontSize,
|
|
258
|
+
fontWeight: tokens.titleFontWeight,
|
|
259
|
+
lineHeight: tokens.titleFontSize * TITLE_LINE_HEIGHT_RATIO,
|
|
187
260
|
}
|
|
188
261
|
|
|
189
262
|
const valueTextStyle: TextStyle = {
|
|
190
|
-
color: valueColor,
|
|
191
|
-
fontFamily:
|
|
192
|
-
fontSize:
|
|
193
|
-
fontWeight:
|
|
194
|
-
lineHeight:
|
|
263
|
+
color: tokens.valueColor,
|
|
264
|
+
fontFamily: tokens.valueFontFamily,
|
|
265
|
+
fontSize: tokens.valueFontSize,
|
|
266
|
+
fontWeight: tokens.valueFontWeight,
|
|
267
|
+
lineHeight: tokens.valueFontSize * VALUE_LINE_HEIGHT_RATIO,
|
|
195
268
|
}
|
|
196
269
|
|
|
197
270
|
const captionTextStyle: TextStyle = {
|
|
198
|
-
color: captionColor,
|
|
199
|
-
fontFamily:
|
|
200
|
-
fontSize:
|
|
201
|
-
fontWeight:
|
|
202
|
-
lineHeight:
|
|
271
|
+
color: tokens.captionColor,
|
|
272
|
+
fontFamily: tokens.captionFontFamily,
|
|
273
|
+
fontSize: tokens.captionFontSize,
|
|
274
|
+
fontWeight: tokens.captionFontWeight,
|
|
275
|
+
lineHeight: tokens.captionFontSize * CAPTION_LINE_HEIGHT_RATIO,
|
|
203
276
|
}
|
|
204
277
|
|
|
205
|
-
// Mirrors the Figma swap slot, whose preferred instances are `Icon` and
|
|
206
|
-
// `Image`. A registry name renders the token-driven `Icon` (18px, gold,
|
|
207
|
-
// flush — all from the `icon/*` tokens); a custom node (`<Icon/>`,
|
|
208
|
-
// `<Image/>`, anything) renders as-is with `modes` cascaded into it, so an
|
|
209
|
-
// Icon instance follows the icon tokens while an Image keeps its own sizing.
|
|
210
278
|
const iconNode =
|
|
211
279
|
icon == null ? null : typeof icon === 'string' ? (
|
|
212
280
|
<Icon
|
|
213
281
|
iconName={icon}
|
|
214
|
-
size={iconSize}
|
|
215
|
-
color={iconColor}
|
|
282
|
+
size={tokens.iconSize}
|
|
283
|
+
color={tokens.iconColor}
|
|
216
284
|
modes={modes}
|
|
217
285
|
style={ICON_PADDING_RESET}
|
|
218
286
|
/>
|
|
@@ -222,6 +290,8 @@ function ValueBackMetric({
|
|
|
222
290
|
|
|
223
291
|
const hasValue = value !== undefined && value !== null && value !== ''
|
|
224
292
|
const hasCaption = caption !== undefined && caption !== ''
|
|
293
|
+
const hasLinkSlot = link !== undefined && link !== null && link !== false
|
|
294
|
+
const hasLinkLabel = linkLabel !== undefined && linkLabel !== ''
|
|
225
295
|
|
|
226
296
|
const resolvedLabel =
|
|
227
297
|
accessibilityLabel ??
|
|
@@ -229,43 +299,47 @@ function ValueBackMetric({
|
|
|
229
299
|
.filter(Boolean)
|
|
230
300
|
.join(', ') || undefined)
|
|
231
301
|
|
|
302
|
+
// Seed Secondary + Small into the CTA slot too, so a bare `<Text text="Earn" />`
|
|
303
|
+
// matches the design without the consumer re-seeding. Child-level modes still win.
|
|
304
|
+
const ctaNode = hasLinkSlot ? (
|
|
305
|
+
cloneChildrenWithModes(link, linkModes)
|
|
306
|
+
) : hasLinkLabel ? (
|
|
307
|
+
onLinkPress ? (
|
|
308
|
+
<Pressable
|
|
309
|
+
onPress={onLinkPress}
|
|
310
|
+
accessibilityRole="link"
|
|
311
|
+
accessibilityLabel={linkLabel}
|
|
312
|
+
>
|
|
313
|
+
<Text text={linkLabel} textAlign="Left" modes={linkModes} />
|
|
314
|
+
</Pressable>
|
|
315
|
+
) : (
|
|
316
|
+
<Text text={linkLabel} textAlign="Left" modes={linkModes} />
|
|
317
|
+
)
|
|
318
|
+
) : null
|
|
319
|
+
|
|
232
320
|
const content = (
|
|
233
321
|
<>
|
|
234
|
-
{
|
|
235
|
-
<View style={{ flexDirection: 'row', alignItems: 'center', gap: valueWrapGap }}>
|
|
322
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: tokens.valueWrapGap }}>
|
|
236
323
|
{iconNode}
|
|
237
324
|
{title !== undefined && title !== '' ? (
|
|
238
|
-
<
|
|
325
|
+
<RNText style={[titleTextStyle, titleStyle]}>{title}</RNText>
|
|
239
326
|
) : null}
|
|
240
327
|
</View>
|
|
241
328
|
|
|
242
|
-
{/* Value + caption block (each optional). */}
|
|
243
329
|
{hasValue || hasCaption ? (
|
|
244
|
-
<View style={{ flexDirection: 'column', alignItems: 'flex-start', gap:
|
|
330
|
+
<View style={{ flexDirection: 'column', alignItems: 'flex-start', gap: TEXT_WRAP_GAP }}>
|
|
245
331
|
{hasValue ? (
|
|
246
332
|
typeof value === 'string' ? (
|
|
247
|
-
<
|
|
333
|
+
<RNText style={[valueTextStyle, valueStyle]}>{value}</RNText>
|
|
248
334
|
) : (
|
|
249
335
|
value
|
|
250
336
|
)
|
|
251
337
|
) : null}
|
|
252
|
-
{hasCaption ? <
|
|
338
|
+
{hasCaption ? <RNText style={[captionTextStyle, captionStyle]}>{caption}</RNText> : null}
|
|
253
339
|
</View>
|
|
254
340
|
) : null}
|
|
255
341
|
|
|
256
|
-
{
|
|
257
|
-
(purple 12px, see above). `linkLabel` is checked inline (narrows it to
|
|
258
|
-
a non-undefined `string`) and `onPress` is spread conditionally, since
|
|
259
|
-
`exactOptionalPropertyTypes` forbids passing `undefined` to Link's
|
|
260
|
-
non-`undefined` optional props. */}
|
|
261
|
-
{linkLabel ? (
|
|
262
|
-
<Link
|
|
263
|
-
text={linkLabel}
|
|
264
|
-
autolayout="Hug"
|
|
265
|
-
modes={linkModes}
|
|
266
|
-
{...(onLinkPress ? { onPress: onLinkPress } : null)}
|
|
267
|
-
/>
|
|
268
|
-
) : null}
|
|
342
|
+
{ctaNode}
|
|
269
343
|
</>
|
|
270
344
|
)
|
|
271
345
|
|
package/src/components/index.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
export { default as AccountCard, type AccountCardProps, type AccountCardState } from './AccountCard/AccountCard'
|
|
2
2
|
export { default as ActionFooter, type ActionFooterProps } from './ActionFooter/ActionFooter'
|
|
3
3
|
export { default as Attached, type AttachedProps, type AttachedPosition } from './Attached/Attached'
|
|
4
|
-
export {
|
|
4
|
+
export {
|
|
5
|
+
default as AppBar,
|
|
6
|
+
JioDot,
|
|
7
|
+
type AppBarProps,
|
|
8
|
+
type JioDotProps,
|
|
9
|
+
} from './AppBar/AppBar'
|
|
5
10
|
export { default as Avatar, type AvatarProps } from './Avatar/Avatar'
|
|
6
11
|
export { default as AvatarGroup } from './AvatarGroup/AvatarGroup'
|
|
7
12
|
export { default as Badge, type BadgeProps, type BadgeType } from './Badge/Badge'
|