jfs-components 0.1.51 → 0.1.55
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/.cursor/D2C-SCREEN.md +2 -1
- package/.cursor/commands/D2C.md +2 -1
- package/CHANGELOG.md +17 -0
- package/lib/commonjs/components/ActionFooter/ActionFooter.js +319 -135
- package/lib/commonjs/components/Badge/Badge.js +20 -1
- package/lib/commonjs/components/Button/Button.js +139 -47
- package/lib/commonjs/components/ButtonGroup/ButtonGroup.js +1 -1
- package/lib/commonjs/components/Card/Card.js +151 -112
- package/lib/commonjs/components/Card/assets/gold-logo-mark.png +0 -0
- package/lib/commonjs/components/CategoryCard/CategoryCard.js +97 -63
- package/lib/commonjs/components/CategoryCard/assets/sample.png +0 -0
- package/lib/commonjs/components/CheckboxItem/CheckboxItem.js +59 -10
- package/lib/commonjs/components/CircularProgressBarDoted/CircularProgressBarDoted.js +1 -1
- package/lib/commonjs/components/ExpandableCheckbox/ExpandableCheckbox.js +132 -49
- package/lib/commonjs/components/HelloJioInput/HelloJioInput.js +56 -14
- package/lib/commonjs/components/IconCapsule/IconCapsule.js +1 -1
- package/lib/commonjs/components/MetricData/MetricData.js +26 -13
- package/lib/commonjs/components/MoneyValue/MoneyValue.js +1 -1
- package/lib/commonjs/components/Nudge/Nudge.js +1 -1
- package/lib/commonjs/components/PdpCcCard/PdpCcCard.js +47 -91
- package/lib/commonjs/components/PlanComparisonCard/PlanComparisonCard.js +52 -45
- package/lib/commonjs/components/PortfolioHero/PortfolioHero.js +1 -1
- package/lib/commonjs/components/Slider/Slider.js +3 -3
- package/lib/commonjs/components/TextInput/TextInput.js +26 -8
- package/lib/commonjs/components/Tooltip/Tooltip.js +3 -5
- package/lib/commonjs/components/index.js +7 -1
- package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
- package/lib/commonjs/design-tokens/figma-modes.generated.js +13 -13
- package/lib/commonjs/icons/registry.js +1 -1
- package/lib/module/components/ActionFooter/ActionFooter.js +322 -138
- package/lib/module/components/Badge/Badge.js +20 -1
- package/lib/module/components/Button/Button.js +140 -48
- package/lib/module/components/ButtonGroup/ButtonGroup.js +1 -1
- package/lib/module/components/Card/Card.js +152 -114
- package/lib/module/components/Card/assets/gold-logo-mark.png +0 -0
- package/lib/module/components/CategoryCard/CategoryCard.js +97 -63
- package/lib/module/components/CategoryCard/assets/sample.png +0 -0
- package/lib/module/components/CheckboxItem/CheckboxItem.js +59 -10
- package/lib/module/components/CircularProgressBarDoted/CircularProgressBarDoted.js +1 -1
- package/lib/module/components/ExpandableCheckbox/ExpandableCheckbox.js +135 -52
- package/lib/module/components/HelloJioInput/HelloJioInput.js +56 -14
- package/lib/module/components/IconCapsule/IconCapsule.js +1 -1
- package/lib/module/components/MetricData/MetricData.js +26 -14
- package/lib/module/components/MoneyValue/MoneyValue.js +1 -1
- package/lib/module/components/Nudge/Nudge.js +1 -1
- package/lib/module/components/PdpCcCard/PdpCcCard.js +48 -92
- package/lib/module/components/PlanComparisonCard/PlanComparisonCard.js +52 -45
- package/lib/module/components/PortfolioHero/PortfolioHero.js +1 -1
- package/lib/module/components/Slider/Slider.js +3 -3
- package/lib/module/components/TextInput/TextInput.js +27 -9
- package/lib/module/components/Tooltip/Tooltip.js +3 -5
- package/lib/module/components/index.js +1 -1
- package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
- package/lib/module/design-tokens/figma-modes.generated.js +13 -13
- package/lib/module/icons/registry.js +1 -1
- package/lib/typescript/src/components/ActionFooter/ActionFooter.d.ts +50 -21
- package/lib/typescript/src/components/Button/Button.d.ts +24 -1
- package/lib/typescript/src/components/ButtonGroup/ButtonGroup.d.ts +2 -2
- package/lib/typescript/src/components/Card/Card.d.ts +54 -25
- package/lib/typescript/src/components/CategoryCard/CategoryCard.d.ts +29 -12
- package/lib/typescript/src/components/CheckboxItem/CheckboxItem.d.ts +27 -9
- package/lib/typescript/src/components/ExpandableCheckbox/ExpandableCheckbox.d.ts +37 -12
- package/lib/typescript/src/components/IconCapsule/IconCapsule.d.ts +1 -1
- package/lib/typescript/src/components/MetricData/MetricData.d.ts +7 -5
- package/lib/typescript/src/components/PdpCcCard/PdpCcCard.d.ts +16 -6
- package/lib/typescript/src/components/PlanComparisonCard/PlanComparisonCard.d.ts +9 -2
- package/lib/typescript/src/components/index.d.ts +2 -2
- package/lib/typescript/src/icons/registry.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/ActionFooter/ActionFooter.tsx +375 -141
- package/src/components/Badge/Badge.tsx +21 -1
- package/src/components/Button/Button.tsx +192 -44
- package/src/components/ButtonGroup/ButtonGroup.tsx +2 -2
- package/src/components/Card/Card.tsx +370 -212
- package/src/components/Card/assets/gold-logo-mark.png +0 -0
- package/src/components/CategoryCard/CategoryCard.tsx +130 -84
- package/src/components/CategoryCard/assets/sample.png +0 -0
- package/src/components/CheckboxItem/CheckboxItem.tsx +72 -12
- package/src/components/CircularProgressBarDoted/CircularProgressBarDoted.tsx +1 -1
- package/src/components/ExpandableCheckbox/ExpandableCheckbox.tsx +186 -67
- package/src/components/HelloJioInput/HelloJioInput.tsx +58 -17
- package/src/components/IconCapsule/IconCapsule.tsx +1 -1
- package/src/components/MetricData/MetricData.tsx +39 -22
- package/src/components/MoneyValue/MoneyValue.tsx +1 -1
- package/src/components/Nudge/Nudge.tsx +1 -1
- package/src/components/PdpCcCard/PdpCcCard.tsx +41 -92
- package/src/components/PlanComparisonCard/PlanComparisonCard.tsx +73 -58
- package/src/components/PortfolioHero/PortfolioHero.tsx +1 -1
- package/src/components/Slider/Slider.tsx +3 -3
- package/src/components/TextInput/TextInput.tsx +26 -9
- package/src/components/Tooltip/Tooltip.tsx +3 -5
- package/src/components/index.ts +9 -2
- package/src/design-tokens/Coin Variables-variables-full.json +1 -1
- package/src/design-tokens/figma-modes.generated.ts +13 -13
- package/src/icons/registry.ts +1 -1
|
@@ -1,179 +1,292 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import React, {
|
|
2
|
+
createContext,
|
|
3
|
+
useContext,
|
|
4
|
+
useMemo,
|
|
5
|
+
} from 'react'
|
|
6
|
+
import {
|
|
7
|
+
View,
|
|
8
|
+
Text,
|
|
9
|
+
Pressable,
|
|
10
|
+
type ViewStyle,
|
|
11
|
+
type TextStyle,
|
|
12
|
+
type StyleProp,
|
|
13
|
+
} from 'react-native'
|
|
14
|
+
import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
|
|
15
|
+
import {
|
|
16
|
+
EMPTY_MODES,
|
|
17
|
+
cloneChildrenWithModes,
|
|
18
|
+
} from '../../utils/react-utils'
|
|
5
19
|
import type { Modes } from '../../design-tokens'
|
|
6
20
|
|
|
7
21
|
/**
|
|
8
|
-
* Context
|
|
9
|
-
*
|
|
10
|
-
* needing explicit mode prop passing for every child.
|
|
22
|
+
* Context so `Card.Title` / `Card.SupportText` resolve tokens from the parent
|
|
23
|
+
* card's `modes` without every call site having to pass them explicitly.
|
|
11
24
|
*/
|
|
12
|
-
const CardContext = createContext<{ modes
|
|
25
|
+
const CardContext = createContext<{ modes: Modes }>({ modes: EMPTY_MODES })
|
|
26
|
+
|
|
27
|
+
/** Canonical variant values. Maps 1:1 to Figma `Property 1`. */
|
|
28
|
+
export type CardVariant = 'default' | 'slim'
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Accepts both the canonical lowercase API and Figma's PascalCase property
|
|
32
|
+
* values so Code Connect / design tooling can pass either.
|
|
33
|
+
*/
|
|
34
|
+
export type CardVariantInput = CardVariant | 'Default' | 'Slim'
|
|
35
|
+
|
|
36
|
+
const normalizeVariant = (value: CardVariantInput | undefined): CardVariant => {
|
|
37
|
+
if (value === 'slim' || value === 'Slim') return 'slim'
|
|
38
|
+
return 'default'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const toNumber = (value: unknown, fallback: number): number => {
|
|
42
|
+
if (typeof value === 'number') {
|
|
43
|
+
return Number.isFinite(value) ? value : fallback
|
|
44
|
+
}
|
|
45
|
+
if (typeof value === 'string') {
|
|
46
|
+
const parsed = Number(value)
|
|
47
|
+
return Number.isFinite(parsed) ? parsed : fallback
|
|
48
|
+
}
|
|
49
|
+
return fallback
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const toFontWeight = (
|
|
53
|
+
value: unknown,
|
|
54
|
+
fallback: TextStyle['fontWeight']
|
|
55
|
+
): TextStyle['fontWeight'] => {
|
|
56
|
+
if (typeof value === 'number') return String(value) as TextStyle['fontWeight']
|
|
57
|
+
if (typeof value === 'string' && value.length > 0) {
|
|
58
|
+
return value as TextStyle['fontWeight']
|
|
59
|
+
}
|
|
60
|
+
return fallback
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Figma `Ratio` default for the media slot (node 766:6258) — 154×116.
|
|
65
|
+
* Kept as a named constant so stories / docs stay aligned with the design.
|
|
66
|
+
*/
|
|
67
|
+
export const CARD_MEDIA_ASPECT_RATIO = 154 / 116
|
|
13
68
|
|
|
14
69
|
export interface CardProps {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Visual layout variant matching Figma `Property 1`.
|
|
72
|
+
* - `'default'` — header + optional media + content (Figma Default)
|
|
73
|
+
* - `'slim'` — header + content only; `media` is ignored (Figma Slim)
|
|
74
|
+
*
|
|
75
|
+
* Defaults to `'default'`. Existing call sites that omit `media` continue
|
|
76
|
+
* to render a media-less default card (backward compatible). Prefer
|
|
77
|
+
* `variant="slim"` when you want the Slim contract explicitly.
|
|
78
|
+
*/
|
|
79
|
+
variant?: CardVariantInput
|
|
80
|
+
/**
|
|
81
|
+
* Content rendered in the header slot at the top of the card (e.g. a brand
|
|
82
|
+
* logo). Sits above the media slot, padded with `card/content/padding/*`.
|
|
83
|
+
*/
|
|
84
|
+
header?: React.ReactNode
|
|
85
|
+
/**
|
|
86
|
+
* Media slot content (e.g. `<Image />`). Wrapped in a container that
|
|
87
|
+
* respects `mediaAspectRatio`. Ignored when `variant="slim"`.
|
|
88
|
+
*/
|
|
89
|
+
media?: React.ReactNode
|
|
90
|
+
/** Content slot (e.g. `Card.Title`, `Card.SupportText`). */
|
|
91
|
+
children?: React.ReactNode
|
|
92
|
+
/** Modes object for token resolution. Cascades into all slots. */
|
|
93
|
+
modes?: Modes
|
|
94
|
+
/**
|
|
95
|
+
* Aspect ratio for the media slot container.
|
|
96
|
+
* Defaults to the Figma Ratio 154/116 (~1.328).
|
|
97
|
+
*/
|
|
98
|
+
mediaAspectRatio?: number
|
|
99
|
+
/** Style overrides for the card container. */
|
|
100
|
+
style?: StyleProp<ViewStyle>
|
|
101
|
+
/**
|
|
102
|
+
* Press handler for the whole card. When set, the card becomes pressable
|
|
103
|
+
* (`Pressable` + `accessibilityRole="button"`).
|
|
104
|
+
*/
|
|
105
|
+
onPress?: () => void
|
|
106
|
+
/** Disable interaction when `onPress` is set. */
|
|
107
|
+
disabled?: boolean
|
|
108
|
+
/** Accessibility label forwarded to the root. */
|
|
109
|
+
accessibilityLabel?: string
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
interface CardTokens {
|
|
113
|
+
containerStyle: ViewStyle
|
|
114
|
+
headerWrapperStyle: ViewStyle
|
|
115
|
+
mediaWrapperStyle: ViewStyle
|
|
116
|
+
contentWrapperStyle: ViewStyle
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function resolveCardTokens(
|
|
120
|
+
modes: Modes,
|
|
121
|
+
mediaAspectRatio: number
|
|
122
|
+
): CardTokens {
|
|
123
|
+
const backgroundColor =
|
|
124
|
+
(getVariableByName('card/background/color', modes) as string | null) ??
|
|
125
|
+
'#ffffff'
|
|
126
|
+
const borderColor =
|
|
127
|
+
(getVariableByName('card/border/color', modes) as string | null) ??
|
|
128
|
+
'#ffffff'
|
|
129
|
+
const borderWidth = toNumber(
|
|
130
|
+
getVariableByName('card/strokeWidth', modes),
|
|
131
|
+
0.5
|
|
132
|
+
)
|
|
133
|
+
const radius = toNumber(getVariableByName('card/radius', modes), 12)
|
|
134
|
+
// Figma root uses itemSpacing=4 (bound conceptually to card/gap). The
|
|
135
|
+
// component-set frames also use SPACE_BETWEEN + fixed heights for gallery
|
|
136
|
+
// layout — we hug content and apply gap only, so consumers aren't stuck
|
|
137
|
+
// with empty distributed space.
|
|
138
|
+
const gap = toNumber(getVariableByName('card/gap', modes), 4)
|
|
139
|
+
const paddingHorizontal = toNumber(
|
|
140
|
+
getVariableByName('card/padding-horizontal', modes),
|
|
141
|
+
0
|
|
142
|
+
)
|
|
143
|
+
const paddingVertical = toNumber(
|
|
144
|
+
getVariableByName('card/padding-vertical', modes),
|
|
145
|
+
0
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
const contentGap = toNumber(
|
|
149
|
+
getVariableByName('card/content/gap', modes),
|
|
150
|
+
4
|
|
151
|
+
)
|
|
152
|
+
const contentPaddingHorizontal = toNumber(
|
|
153
|
+
getVariableByName('card/content/padding/horizontal', modes),
|
|
154
|
+
12
|
|
155
|
+
)
|
|
156
|
+
const contentPaddingVertical = toNumber(
|
|
157
|
+
getVariableByName('card/content/padding/vertical', modes),
|
|
158
|
+
12
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
containerStyle: {
|
|
163
|
+
backgroundColor,
|
|
164
|
+
borderColor,
|
|
165
|
+
borderWidth,
|
|
166
|
+
borderRadius: radius,
|
|
167
|
+
gap,
|
|
168
|
+
paddingHorizontal,
|
|
169
|
+
paddingVertical,
|
|
170
|
+
overflow: 'hidden',
|
|
171
|
+
},
|
|
172
|
+
// Header wrap binds the same content-padding tokens as the content wrap
|
|
173
|
+
// in Figma (12/12) — not a separate header token set.
|
|
174
|
+
headerWrapperStyle: {
|
|
175
|
+
width: '100%',
|
|
176
|
+
flexDirection: 'row',
|
|
177
|
+
alignItems: 'flex-start',
|
|
178
|
+
paddingHorizontal: contentPaddingHorizontal,
|
|
179
|
+
paddingVertical: contentPaddingVertical,
|
|
180
|
+
},
|
|
181
|
+
mediaWrapperStyle: {
|
|
182
|
+
width: '100%',
|
|
183
|
+
aspectRatio: mediaAspectRatio,
|
|
184
|
+
overflow: 'hidden',
|
|
185
|
+
},
|
|
186
|
+
contentWrapperStyle: {
|
|
187
|
+
width: '100%',
|
|
188
|
+
gap: contentGap,
|
|
189
|
+
paddingHorizontal: contentPaddingHorizontal,
|
|
190
|
+
paddingVertical: contentPaddingVertical,
|
|
191
|
+
},
|
|
192
|
+
}
|
|
51
193
|
}
|
|
52
194
|
|
|
53
195
|
/**
|
|
54
|
-
* Card
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
196
|
+
* `Card` — Figma node 5739:794 (`Property 1=Default` / `Property 1=Slim`).
|
|
197
|
+
*
|
|
198
|
+
* Slots: optional `header`, optional `media` (Default only), and `children`
|
|
199
|
+
* for the content stack. Typography subcomponents (`Card.Title`,
|
|
200
|
+
* `Card.SupportText`) read tokens via context.
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
60
203
|
* ```tsx
|
|
61
|
-
* <Card
|
|
204
|
+
* <Card
|
|
205
|
+
* variant="default"
|
|
206
|
+
* header={<GoldLogo />}
|
|
207
|
+
* media={<Image imageSource={uri} ratio={154 / 116} />}
|
|
208
|
+
* modes={{ AppearanceBrand: 'Neutral' }}
|
|
209
|
+
* >
|
|
62
210
|
* <Card.SupportText>Support text</Card.SupportText>
|
|
63
211
|
* <Card.Title>Title</Card.Title>
|
|
64
212
|
* <Card.SupportText>Support text</Card.SupportText>
|
|
65
213
|
* </Card>
|
|
66
214
|
* ```
|
|
215
|
+
*
|
|
216
|
+
* @component
|
|
67
217
|
*/
|
|
68
218
|
export function Card({
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
219
|
+
variant: variantProp = 'default',
|
|
220
|
+
header,
|
|
221
|
+
media,
|
|
222
|
+
children,
|
|
223
|
+
modes: propModes = EMPTY_MODES,
|
|
224
|
+
mediaAspectRatio = CARD_MEDIA_ASPECT_RATIO,
|
|
225
|
+
style,
|
|
226
|
+
onPress,
|
|
227
|
+
disabled,
|
|
228
|
+
accessibilityLabel,
|
|
78
229
|
}: CardProps) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const content = (
|
|
140
|
-
<>
|
|
141
|
-
{header && (
|
|
142
|
-
<View style={headerWrapperStyle}>
|
|
143
|
-
{headerWithModes}
|
|
144
|
-
</View>
|
|
145
|
-
)}
|
|
146
|
-
{media && (
|
|
147
|
-
<View style={mediaWrapperStyle}>
|
|
148
|
-
{mediaWithModes}
|
|
149
|
-
</View>
|
|
150
|
-
)}
|
|
151
|
-
<View style={contentWrapperStyle}>
|
|
152
|
-
{children}
|
|
153
|
-
</View>
|
|
154
|
-
</>
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
return (
|
|
158
|
-
<CardContext.Provider value={{ modes }}>
|
|
159
|
-
{onPress ? (
|
|
160
|
-
<Pressable
|
|
161
|
-
style={[containerStyle, style]}
|
|
162
|
-
onPress={onPress}
|
|
163
|
-
disabled={disabled}
|
|
164
|
-
accessibilityRole="button"
|
|
165
|
-
accessibilityLabel={accessibilityLabel}
|
|
166
|
-
accessibilityState={{ disabled: !!disabled }}
|
|
167
|
-
>
|
|
168
|
-
{content}
|
|
169
|
-
</Pressable>
|
|
170
|
-
) : (
|
|
171
|
-
<View style={[containerStyle, style]} accessibilityLabel={accessibilityLabel}>
|
|
172
|
-
{content}
|
|
173
|
-
</View>
|
|
174
|
-
)}
|
|
175
|
-
</CardContext.Provider>
|
|
176
|
-
);
|
|
230
|
+
const variant = normalizeVariant(variantProp)
|
|
231
|
+
const modes = propModes ?? EMPTY_MODES
|
|
232
|
+
|
|
233
|
+
const tokens = useMemo(
|
|
234
|
+
() => resolveCardTokens(modes, mediaAspectRatio),
|
|
235
|
+
[modes, mediaAspectRatio]
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
// Slim suppresses media even if a consumer still passes it — matches Figma
|
|
239
|
+
// Property 1=Slim. Default keeps prior behavior: media renders when provided.
|
|
240
|
+
const showMedia = variant === 'default' && media != null
|
|
241
|
+
|
|
242
|
+
const processedHeader =
|
|
243
|
+
header != null
|
|
244
|
+
? cloneChildrenWithModes(React.Children.toArray(header), modes)
|
|
245
|
+
: null
|
|
246
|
+
|
|
247
|
+
const processedMedia = showMedia
|
|
248
|
+
? cloneChildrenWithModes(React.Children.toArray(media), modes)
|
|
249
|
+
: null
|
|
250
|
+
|
|
251
|
+
const processedChildren = cloneChildrenWithModes(
|
|
252
|
+
React.Children.toArray(children ?? null),
|
|
253
|
+
modes
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
const content = (
|
|
257
|
+
<>
|
|
258
|
+
{processedHeader ? (
|
|
259
|
+
<View style={tokens.headerWrapperStyle}>{processedHeader}</View>
|
|
260
|
+
) : null}
|
|
261
|
+
{processedMedia ? (
|
|
262
|
+
<View style={tokens.mediaWrapperStyle}>{processedMedia}</View>
|
|
263
|
+
) : null}
|
|
264
|
+
<View style={tokens.contentWrapperStyle}>{processedChildren}</View>
|
|
265
|
+
</>
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
const rootStyle: StyleProp<ViewStyle> = [tokens.containerStyle, style]
|
|
269
|
+
|
|
270
|
+
return (
|
|
271
|
+
<CardContext.Provider value={{ modes }}>
|
|
272
|
+
{onPress ? (
|
|
273
|
+
<Pressable
|
|
274
|
+
style={rootStyle}
|
|
275
|
+
onPress={onPress}
|
|
276
|
+
disabled={disabled}
|
|
277
|
+
accessibilityRole="button"
|
|
278
|
+
accessibilityLabel={accessibilityLabel}
|
|
279
|
+
accessibilityState={{ disabled: !!disabled }}
|
|
280
|
+
>
|
|
281
|
+
{content}
|
|
282
|
+
</Pressable>
|
|
283
|
+
) : (
|
|
284
|
+
<View style={rootStyle} accessibilityLabel={accessibilityLabel}>
|
|
285
|
+
{content}
|
|
286
|
+
</View>
|
|
287
|
+
)}
|
|
288
|
+
</CardContext.Provider>
|
|
289
|
+
)
|
|
177
290
|
}
|
|
178
291
|
|
|
179
292
|
// ----------------------------------------------------------------------------
|
|
@@ -181,68 +294,113 @@ export function Card({
|
|
|
181
294
|
// ----------------------------------------------------------------------------
|
|
182
295
|
|
|
183
296
|
export interface CardTextProps {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
297
|
+
children?: React.ReactNode
|
|
298
|
+
style?: StyleProp<TextStyle>
|
|
299
|
+
modes?: Modes
|
|
300
|
+
/**
|
|
301
|
+
* Line clamp before ellipsis. `Card.Title` defaults to `3` (Figma).
|
|
302
|
+
* Pass a different number to override, or `0` for no clamp.
|
|
303
|
+
*/
|
|
304
|
+
numberOfLines?: number
|
|
187
305
|
}
|
|
188
306
|
|
|
189
307
|
/**
|
|
190
|
-
* Title
|
|
191
|
-
* Uses tokens: card/title/*
|
|
308
|
+
* Title — tokens: `card/title/*`
|
|
192
309
|
*/
|
|
193
|
-
function Title({
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
310
|
+
function Title({
|
|
311
|
+
children,
|
|
312
|
+
style,
|
|
313
|
+
modes: propModes,
|
|
314
|
+
numberOfLines = 3,
|
|
315
|
+
}: CardTextProps) {
|
|
316
|
+
const context = useContext(CardContext)
|
|
317
|
+
const modes = propModes ?? context.modes ?? EMPTY_MODES
|
|
318
|
+
|
|
319
|
+
const color =
|
|
320
|
+
(getVariableByName('card/title/color', modes) as string | null) ?? '#000000'
|
|
321
|
+
const fontSize = toNumber(
|
|
322
|
+
getVariableByName('card/title/fontSize', modes),
|
|
323
|
+
16
|
|
324
|
+
)
|
|
325
|
+
const fontFamily =
|
|
326
|
+
(getVariableByName('card/title/fontFamily', modes) as string | null) ??
|
|
327
|
+
'JioType Var'
|
|
328
|
+
const lineHeight = toNumber(
|
|
329
|
+
getVariableByName('card/title/lineHeight', modes),
|
|
330
|
+
18
|
|
331
|
+
)
|
|
332
|
+
const fontWeight = toFontWeight(
|
|
333
|
+
getVariableByName('card/title/fontWeight', modes),
|
|
334
|
+
'900'
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
const textStyle: TextStyle = {
|
|
338
|
+
color,
|
|
339
|
+
fontSize,
|
|
340
|
+
fontFamily,
|
|
341
|
+
lineHeight,
|
|
342
|
+
fontWeight,
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return (
|
|
346
|
+
<Text
|
|
347
|
+
style={[textStyle, style]}
|
|
348
|
+
numberOfLines={numberOfLines > 0 ? numberOfLines : undefined}
|
|
349
|
+
>
|
|
350
|
+
{children}
|
|
351
|
+
</Text>
|
|
352
|
+
)
|
|
216
353
|
}
|
|
217
354
|
|
|
218
355
|
/**
|
|
219
|
-
*
|
|
220
|
-
* Uses tokens: card/supportive-text/*
|
|
356
|
+
* Supportive text — tokens: `card/supportive-text/*`
|
|
221
357
|
*/
|
|
222
|
-
function SupportText({
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
358
|
+
function SupportText({
|
|
359
|
+
children,
|
|
360
|
+
style,
|
|
361
|
+
modes: propModes,
|
|
362
|
+
numberOfLines,
|
|
363
|
+
}: CardTextProps) {
|
|
364
|
+
const context = useContext(CardContext)
|
|
365
|
+
const modes = propModes ?? context.modes ?? EMPTY_MODES
|
|
366
|
+
|
|
367
|
+
const color =
|
|
368
|
+
(getVariableByName('card/supportive-text/color', modes) as string | null) ??
|
|
369
|
+
'#1a1c1f'
|
|
370
|
+
const fontSize = toNumber(
|
|
371
|
+
getVariableByName('card/supportive-text/fontSize', modes),
|
|
372
|
+
12
|
|
373
|
+
)
|
|
374
|
+
const fontFamily =
|
|
375
|
+
(getVariableByName(
|
|
376
|
+
'card/supportive-text/fontFamily',
|
|
377
|
+
modes
|
|
378
|
+
) as string | null) ?? 'JioType Var'
|
|
379
|
+
const lineHeight = toNumber(
|
|
380
|
+
getVariableByName('card/supportive-text/lineHeight', modes),
|
|
381
|
+
16
|
|
382
|
+
)
|
|
383
|
+
const fontWeight = toFontWeight(
|
|
384
|
+
getVariableByName('card/supportive-text/fontWeight', modes),
|
|
385
|
+
'400'
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
const textStyle: TextStyle = {
|
|
389
|
+
color,
|
|
390
|
+
fontSize,
|
|
391
|
+
fontFamily,
|
|
392
|
+
lineHeight,
|
|
393
|
+
fontWeight,
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return (
|
|
397
|
+
<Text style={[textStyle, style]} numberOfLines={numberOfLines}>
|
|
398
|
+
{children}
|
|
399
|
+
</Text>
|
|
400
|
+
)
|
|
242
401
|
}
|
|
243
402
|
|
|
244
|
-
|
|
245
|
-
Card.
|
|
246
|
-
Card.SupportText = SupportText;
|
|
403
|
+
Card.Title = Title
|
|
404
|
+
Card.SupportText = SupportText
|
|
247
405
|
|
|
248
|
-
export default Card
|
|
406
|
+
export default Card
|
|
Binary file
|