jfs-components 0.1.17 → 0.1.19
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 +15 -0
- package/lib/commonjs/components/AvatarGroup/AvatarGroup.js +41 -20
- package/lib/commonjs/components/Card/Card.js +29 -12
- package/lib/commonjs/components/CardFeedback/CardFeedback.js +16 -2
- package/lib/commonjs/components/CardInsight/CardInsight.js +34 -13
- package/lib/commonjs/components/CardProviderInfo/CardProviderInfo.js +23 -3
- package/lib/commonjs/components/DebitCard/DebitCard.js +23 -3
- package/lib/commonjs/components/MediaCard/MediaCard.js +24 -7
- package/lib/commonjs/components/ProductMerchandisingCard/ProductMerchandisingCard.js +64 -60
- package/lib/commonjs/components/RechargeCard/RechargeCard.js +34 -13
- package/lib/commonjs/components/TestimonialsCard/TestimonialsCard.js +23 -5
- package/lib/commonjs/icons/registry.js +1 -1
- package/lib/commonjs/utils/GlassFill/GlassFill.js +69 -73
- package/lib/module/components/AvatarGroup/AvatarGroup.js +43 -21
- package/lib/module/components/Card/Card.js +31 -14
- package/lib/module/components/CardFeedback/CardFeedback.js +17 -3
- package/lib/module/components/CardInsight/CardInsight.js +36 -15
- package/lib/module/components/CardProviderInfo/CardProviderInfo.js +25 -5
- package/lib/module/components/DebitCard/DebitCard.js +25 -5
- package/lib/module/components/MediaCard/MediaCard.js +26 -9
- package/lib/module/components/ProductMerchandisingCard/ProductMerchandisingCard.js +66 -62
- package/lib/module/components/RechargeCard/RechargeCard.js +36 -15
- package/lib/module/components/TestimonialsCard/TestimonialsCard.js +25 -7
- package/lib/module/icons/registry.js +1 -1
- package/lib/module/utils/GlassFill/GlassFill.js +69 -72
- package/lib/typescript/src/components/Card/Card.d.ts +10 -1
- package/lib/typescript/src/components/CardFeedback/CardFeedback.d.ts +10 -1
- package/lib/typescript/src/components/CardInsight/CardInsight.d.ts +10 -1
- package/lib/typescript/src/components/CardProviderInfo/CardProviderInfo.d.ts +10 -1
- package/lib/typescript/src/components/DebitCard/DebitCard.d.ts +10 -1
- package/lib/typescript/src/components/MediaCard/MediaCard.d.ts +10 -1
- package/lib/typescript/src/components/RechargeCard/RechargeCard.d.ts +10 -1
- package/lib/typescript/src/components/TestimonialsCard/TestimonialsCard.d.ts +8 -1
- package/lib/typescript/src/icons/registry.d.ts +1 -1
- package/lib/typescript/src/utils/GlassFill/GlassFill.d.ts +11 -4
- package/package.json +1 -2
- package/src/components/AvatarGroup/AvatarGroup.tsx +44 -18
- package/src/components/Card/Card.tsx +46 -15
- package/src/components/CardFeedback/CardFeedback.tsx +29 -4
- package/src/components/CardInsight/CardInsight.tsx +48 -17
- package/src/components/CardProviderInfo/CardProviderInfo.tsx +36 -3
- package/src/components/DebitCard/DebitCard.tsx +36 -3
- package/src/components/MediaCard/MediaCard.tsx +40 -9
- package/src/components/ProductMerchandisingCard/ProductMerchandisingCard.tsx +76 -47
- package/src/components/RechargeCard/RechargeCard.tsx +48 -13
- package/src/components/TestimonialsCard/TestimonialsCard.tsx +37 -6
- package/src/icons/registry.ts +1 -1
- package/src/utils/GlassFill/GlassFill.tsx +59 -56
|
@@ -2,6 +2,7 @@ import React from 'react'
|
|
|
2
2
|
import {
|
|
3
3
|
View,
|
|
4
4
|
Text,
|
|
5
|
+
Pressable,
|
|
5
6
|
type ViewStyle,
|
|
6
7
|
type TextStyle,
|
|
7
8
|
type StyleProp,
|
|
@@ -38,6 +39,13 @@ export type TestimonialsCardProps = {
|
|
|
38
39
|
* from the title and body.
|
|
39
40
|
*/
|
|
40
41
|
accessibilityLabel?: string
|
|
42
|
+
/**
|
|
43
|
+
* Press handler for the whole card. When set, the card becomes pressable
|
|
44
|
+
* (rendered through a `Pressable` with `accessibilityRole="button"`).
|
|
45
|
+
*/
|
|
46
|
+
onPress?: () => void
|
|
47
|
+
/** Disable interaction when `onPress` is set. */
|
|
48
|
+
disabled?: boolean
|
|
41
49
|
}
|
|
42
50
|
|
|
43
51
|
/**
|
|
@@ -63,6 +71,8 @@ function TestimonialsCard({
|
|
|
63
71
|
style,
|
|
64
72
|
avatarProps,
|
|
65
73
|
accessibilityLabel,
|
|
74
|
+
onPress,
|
|
75
|
+
disabled,
|
|
66
76
|
}: TestimonialsCardProps) {
|
|
67
77
|
// Container tokens
|
|
68
78
|
const background = getVariableByName('testimonialsCard/background', modes) ?? '#ffffff'
|
|
@@ -127,12 +137,8 @@ function TestimonialsCard({
|
|
|
127
137
|
const resolvedAccessibilityLabel =
|
|
128
138
|
accessibilityLabel ?? `Testimonial${title ? ` from ${title}` : ''}${body ? `: ${body}` : ''}`
|
|
129
139
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
style={[containerStyle, style]}
|
|
133
|
-
accessibilityRole="text"
|
|
134
|
-
accessibilityLabel={resolvedAccessibilityLabel}
|
|
135
|
-
>
|
|
140
|
+
const content = (
|
|
141
|
+
<>
|
|
136
142
|
<Avatar
|
|
137
143
|
style="Image"
|
|
138
144
|
modes={avatarModes}
|
|
@@ -150,6 +156,31 @@ function TestimonialsCard({
|
|
|
150
156
|
</Text>
|
|
151
157
|
)}
|
|
152
158
|
</View>
|
|
159
|
+
</>
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
if (onPress) {
|
|
163
|
+
return (
|
|
164
|
+
<Pressable
|
|
165
|
+
style={[containerStyle, style]}
|
|
166
|
+
onPress={onPress}
|
|
167
|
+
disabled={disabled}
|
|
168
|
+
accessibilityRole="button"
|
|
169
|
+
accessibilityLabel={resolvedAccessibilityLabel}
|
|
170
|
+
accessibilityState={{ disabled: !!disabled }}
|
|
171
|
+
>
|
|
172
|
+
{content}
|
|
173
|
+
</Pressable>
|
|
174
|
+
)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
<View
|
|
179
|
+
style={[containerStyle, style]}
|
|
180
|
+
accessibilityRole="text"
|
|
181
|
+
accessibilityLabel={resolvedAccessibilityLabel}
|
|
182
|
+
>
|
|
183
|
+
{content}
|
|
153
184
|
</View>
|
|
154
185
|
)
|
|
155
186
|
}
|
package/src/icons/registry.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React, { useId } from 'react'
|
|
2
2
|
import { View, StyleSheet, Platform, UIManager, type ViewStyle, type StyleProp } from 'react-native'
|
|
3
3
|
import { BlurView } from '@react-native-community/blur'
|
|
4
|
-
import MaskedView from '@react-native-masked-view/masked-view'
|
|
5
4
|
import Svg, { Defs, LinearGradient, Stop, Rect } from 'react-native-svg'
|
|
6
5
|
|
|
7
6
|
export type GlassTint = 'dark' | 'light'
|
|
@@ -31,10 +30,17 @@ export interface GlassFillProps {
|
|
|
31
30
|
/**
|
|
32
31
|
* Render a *progressive* (variable) blur instead of a uniform one: fully
|
|
33
32
|
* clear at the top, easing into a soft blur toward the bottom. Implemented
|
|
34
|
-
* by stacking
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
33
|
+
* mask-free by stacking several bottom-anchored `BlurView` "bands": each
|
|
34
|
+
* band is clipped to start a little lower than the last, and because a
|
|
35
|
+
* `BlurView` blurs whatever is rendered behind it, the bands COMPOUND toward
|
|
36
|
+
* the bottom (a lower band re-blurs the already-blurred output above it) so
|
|
37
|
+
* the effective radius swells smoothly downward. This deliberately avoids
|
|
38
|
+
* masking a native view — the old implementation wrapped each `BlurView` in
|
|
39
|
+
* `@react-native-masked-view/masked-view`, a legacy Paper component that
|
|
40
|
+
* resolves to a plain object (crashing "Element type is invalid") under the
|
|
41
|
+
* New Architecture interop. Works on iOS and Android with no extra native
|
|
42
|
+
* module. When the native blur isn't linked at all, falls back to a pure
|
|
43
|
+
* `react-native-svg` gradient scrim (see below).
|
|
38
44
|
*/
|
|
39
45
|
progressive?: boolean
|
|
40
46
|
/**
|
|
@@ -70,14 +76,13 @@ const DEFAULT_FALLBACK_LIGHT = '#ffffff66'
|
|
|
70
76
|
const NATIVE_BLUR_NAME = Platform.OS === 'android' ? 'AndroidBlurView' : 'BlurView'
|
|
71
77
|
|
|
72
78
|
/**
|
|
73
|
-
* Alpha stop on
|
|
74
|
-
* position (0 = top of the surface, 1 = bottom); `opacity` is the
|
|
75
|
-
* there (0 =
|
|
79
|
+
* Alpha stop on the no-native-blur fallback gradient. `offset` is the vertical
|
|
80
|
+
* position (0 = top of the surface, 1 = bottom); `opacity` is the tint alpha
|
|
81
|
+
* there (0 = fully clear, 1 = full fallback color).
|
|
76
82
|
*
|
|
77
|
-
* Using several stops (rather than a single linear 0 → 1 ramp)
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* "glass" feel rather than a flat translucent panel.
|
|
83
|
+
* Using several stops (rather than a single linear 0 → 1 ramp) eases the tint
|
|
84
|
+
* in, so it swells smoothly toward the bottom instead of along a hard seam —
|
|
85
|
+
* the soft S-curve that gives the surface its "glass" feel.
|
|
81
86
|
*/
|
|
82
87
|
interface MaskStop {
|
|
83
88
|
offset: number
|
|
@@ -85,25 +90,24 @@ interface MaskStop {
|
|
|
85
90
|
}
|
|
86
91
|
|
|
87
92
|
/**
|
|
88
|
-
* A single
|
|
89
|
-
* - `
|
|
90
|
-
*
|
|
93
|
+
* A single bottom-anchored band of the progressive blur stack.
|
|
94
|
+
* - `start` is where the band begins, as a fraction from the top (0 = covers
|
|
95
|
+
* the whole surface, 0.8 = only the bottom 20%). Each band runs from `start`
|
|
96
|
+
* to the bottom.
|
|
97
|
+
* - `amount` is the band's own blur strength as a share (0–1) of the peak.
|
|
91
98
|
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* heavy block), while still giving a genuine variable-radius result — the blur
|
|
97
|
-
* radius grows toward the bottom where the two layers overlap.
|
|
99
|
+
* Because each `BlurView` re-blurs everything rendered behind it, the bands
|
|
100
|
+
* COMPOUND where they overlap (toward the bottom), so the effective radius grows
|
|
101
|
+
* downward without any masking. The top region is covered only by the first,
|
|
102
|
+
* faint band; the bottom is covered by all of them.
|
|
98
103
|
*/
|
|
99
|
-
interface
|
|
100
|
-
|
|
104
|
+
interface ProgressiveBand {
|
|
105
|
+
start: number
|
|
101
106
|
amount: number
|
|
102
107
|
}
|
|
103
108
|
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
// snapping clear. Also reused for the no-native-blur fallback scrim.
|
|
109
|
+
// Eased tint ramp for the no-native-blur fallback scrim. A faint trace begins
|
|
110
|
+
// near the very top and grows steadily downward.
|
|
107
111
|
const BASE_MASK_STOPS: MaskStop[] = [
|
|
108
112
|
{ offset: 0.0, opacity: 0 },
|
|
109
113
|
{ offset: 0.08, opacity: 0.12 },
|
|
@@ -112,18 +116,16 @@ const BASE_MASK_STOPS: MaskStop[] = [
|
|
|
112
116
|
{ offset: 1.0, opacity: 1 },
|
|
113
117
|
]
|
|
114
118
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
],
|
|
126
|
-
},
|
|
119
|
+
// Bottom-anchored blur bands (top → bottom). The first band is faint and covers
|
|
120
|
+
// the whole surface so the top reads as barely-there glass; each subsequent band
|
|
121
|
+
// starts lower and adds strength, compounding toward the bottom for a smooth
|
|
122
|
+
// variable-radius result. Quadrature of these shares lands the bottom at ~peak.
|
|
123
|
+
const PROGRESSIVE_BANDS: ProgressiveBand[] = [
|
|
124
|
+
{ start: 0.0, amount: 0.18 },
|
|
125
|
+
{ start: 0.3, amount: 0.28 },
|
|
126
|
+
{ start: 0.52, amount: 0.38 },
|
|
127
|
+
{ start: 0.7, amount: 0.5 },
|
|
128
|
+
{ start: 0.84, amount: 0.6 },
|
|
127
129
|
]
|
|
128
130
|
|
|
129
131
|
/**
|
|
@@ -159,18 +161,18 @@ const NATIVE_BLUR_SUPPORTED: boolean = (() => {
|
|
|
159
161
|
})()
|
|
160
162
|
|
|
161
163
|
/**
|
|
162
|
-
* Vertical
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
164
|
+
* Vertical color-gradient scrim drawn with `react-native-svg` — used as the
|
|
165
|
+
* no-native-blur fallback. Paints `color` at the eased per-stop alpha so the
|
|
166
|
+
* tint swells smoothly from clear (top) to full (bottom), exactly mirroring the
|
|
167
|
+
* old `MaskedView`-over-solid-color fallback but with no native-view masking.
|
|
166
168
|
*/
|
|
167
|
-
function
|
|
169
|
+
function GradientScrim({ id, color, stops }: { id: string; color: string; stops: MaskStop[] }) {
|
|
168
170
|
return (
|
|
169
171
|
<Svg width="100%" height="100%">
|
|
170
172
|
<Defs>
|
|
171
173
|
<LinearGradient id={id} x1="0" y1="0" x2="0" y2="1">
|
|
172
174
|
{stops.map((s, i) => (
|
|
173
|
-
<Stop key={i} offset={s.offset} stopColor=
|
|
175
|
+
<Stop key={i} offset={s.offset} stopColor={color} stopOpacity={s.opacity} />
|
|
174
176
|
))}
|
|
175
177
|
</LinearGradient>
|
|
176
178
|
</Defs>
|
|
@@ -230,25 +232,26 @@ function GlassFill({
|
|
|
230
232
|
if (!NATIVE_BLUR_SUPPORTED) {
|
|
231
233
|
return (
|
|
232
234
|
<View style={[StyleSheet.absoluteFill, style]} pointerEvents="none">
|
|
233
|
-
<
|
|
234
|
-
style={StyleSheet.absoluteFill}
|
|
235
|
-
maskElement={<GradientMask id={`${maskId}-fb`} stops={BASE_MASK_STOPS} />}
|
|
236
|
-
>
|
|
237
|
-
<View style={[StyleSheet.absoluteFill, { backgroundColor: fallbackColor }]} />
|
|
238
|
-
</MaskedView>
|
|
235
|
+
<GradientScrim id={`${maskId}-fb`} color={fallbackColor} stops={BASE_MASK_STOPS} />
|
|
239
236
|
</View>
|
|
240
237
|
)
|
|
241
238
|
}
|
|
242
239
|
|
|
243
240
|
return (
|
|
244
241
|
<View style={[StyleSheet.absoluteFill, style]} pointerEvents="none">
|
|
245
|
-
{
|
|
246
|
-
const amount = Math.max(1, Math.round(peakBlur *
|
|
242
|
+
{PROGRESSIVE_BANDS.map((band, i) => {
|
|
243
|
+
const amount = Math.max(1, Math.round(peakBlur * band.amount))
|
|
247
244
|
return (
|
|
248
|
-
|
|
245
|
+
// Each band is clipped to start at `band.start` and run to
|
|
246
|
+
// the bottom; its `BlurView` blurs the content (and any
|
|
247
|
+
// lower bands) behind it, so the radius compounds downward.
|
|
248
|
+
<View
|
|
249
249
|
key={i}
|
|
250
|
-
style={
|
|
251
|
-
|
|
250
|
+
style={[
|
|
251
|
+
StyleSheet.absoluteFill,
|
|
252
|
+
{ top: `${band.start * 100}%`, overflow: 'hidden' },
|
|
253
|
+
]}
|
|
254
|
+
pointerEvents="none"
|
|
252
255
|
>
|
|
253
256
|
<BlurView
|
|
254
257
|
style={StyleSheet.absoluteFill}
|
|
@@ -256,7 +259,7 @@ function GlassFill({
|
|
|
256
259
|
blurAmount={amount}
|
|
257
260
|
reducedTransparencyFallbackColor={fallbackColor}
|
|
258
261
|
/>
|
|
259
|
-
</
|
|
262
|
+
</View>
|
|
260
263
|
)
|
|
261
264
|
})}
|
|
262
265
|
</View>
|