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.
Files changed (48) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/lib/commonjs/components/AvatarGroup/AvatarGroup.js +41 -20
  3. package/lib/commonjs/components/Card/Card.js +29 -12
  4. package/lib/commonjs/components/CardFeedback/CardFeedback.js +16 -2
  5. package/lib/commonjs/components/CardInsight/CardInsight.js +34 -13
  6. package/lib/commonjs/components/CardProviderInfo/CardProviderInfo.js +23 -3
  7. package/lib/commonjs/components/DebitCard/DebitCard.js +23 -3
  8. package/lib/commonjs/components/MediaCard/MediaCard.js +24 -7
  9. package/lib/commonjs/components/ProductMerchandisingCard/ProductMerchandisingCard.js +64 -60
  10. package/lib/commonjs/components/RechargeCard/RechargeCard.js +34 -13
  11. package/lib/commonjs/components/TestimonialsCard/TestimonialsCard.js +23 -5
  12. package/lib/commonjs/icons/registry.js +1 -1
  13. package/lib/commonjs/utils/GlassFill/GlassFill.js +69 -73
  14. package/lib/module/components/AvatarGroup/AvatarGroup.js +43 -21
  15. package/lib/module/components/Card/Card.js +31 -14
  16. package/lib/module/components/CardFeedback/CardFeedback.js +17 -3
  17. package/lib/module/components/CardInsight/CardInsight.js +36 -15
  18. package/lib/module/components/CardProviderInfo/CardProviderInfo.js +25 -5
  19. package/lib/module/components/DebitCard/DebitCard.js +25 -5
  20. package/lib/module/components/MediaCard/MediaCard.js +26 -9
  21. package/lib/module/components/ProductMerchandisingCard/ProductMerchandisingCard.js +66 -62
  22. package/lib/module/components/RechargeCard/RechargeCard.js +36 -15
  23. package/lib/module/components/TestimonialsCard/TestimonialsCard.js +25 -7
  24. package/lib/module/icons/registry.js +1 -1
  25. package/lib/module/utils/GlassFill/GlassFill.js +69 -72
  26. package/lib/typescript/src/components/Card/Card.d.ts +10 -1
  27. package/lib/typescript/src/components/CardFeedback/CardFeedback.d.ts +10 -1
  28. package/lib/typescript/src/components/CardInsight/CardInsight.d.ts +10 -1
  29. package/lib/typescript/src/components/CardProviderInfo/CardProviderInfo.d.ts +10 -1
  30. package/lib/typescript/src/components/DebitCard/DebitCard.d.ts +10 -1
  31. package/lib/typescript/src/components/MediaCard/MediaCard.d.ts +10 -1
  32. package/lib/typescript/src/components/RechargeCard/RechargeCard.d.ts +10 -1
  33. package/lib/typescript/src/components/TestimonialsCard/TestimonialsCard.d.ts +8 -1
  34. package/lib/typescript/src/icons/registry.d.ts +1 -1
  35. package/lib/typescript/src/utils/GlassFill/GlassFill.d.ts +11 -4
  36. package/package.json +1 -2
  37. package/src/components/AvatarGroup/AvatarGroup.tsx +44 -18
  38. package/src/components/Card/Card.tsx +46 -15
  39. package/src/components/CardFeedback/CardFeedback.tsx +29 -4
  40. package/src/components/CardInsight/CardInsight.tsx +48 -17
  41. package/src/components/CardProviderInfo/CardProviderInfo.tsx +36 -3
  42. package/src/components/DebitCard/DebitCard.tsx +36 -3
  43. package/src/components/MediaCard/MediaCard.tsx +40 -9
  44. package/src/components/ProductMerchandisingCard/ProductMerchandisingCard.tsx +76 -47
  45. package/src/components/RechargeCard/RechargeCard.tsx +48 -13
  46. package/src/components/TestimonialsCard/TestimonialsCard.tsx +37 -6
  47. package/src/icons/registry.ts +1 -1
  48. 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
- return (
131
- <View
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
  }
@@ -4,7 +4,7 @@
4
4
  * Auto-generated from SVG files in src/icons/
5
5
  * DO NOT EDIT MANUALLY - Run "npm run icons:generate" to regenerate
6
6
  *
7
- * Generated: 2026-06-26T16:43:17.033Z
7
+ * Generated: 2026-06-29T11:40:01.320Z
8
8
  */
9
9
 
10
10
  // Icon name to SVG data mapping
@@ -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 two `MaskedView` + `BlurView` layers (a faint base + a
35
- * slightly stronger accent near the bottom), each revealed via an eased
36
- * multi-stop SVG gradient mask so the blur swells smoothly rather than
37
- * along a hard seam. Works on iOS and Android with no extra native module.
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 a layer's vertical reveal mask. `offset` is the vertical
74
- * position (0 = top of the surface, 1 = bottom); `opacity` is the mask alpha
75
- * there (0 = layer hidden / fully clear, 1 = layer fully applied).
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) lets each layer
78
- * EASE in, so the blur swells smoothly toward the bottom instead of appearing
79
- * along a hard horizontal seam. That soft S-curve is what gives the surface its
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 layer of the progressive ramp.
89
- * - `stops` describe how this layer is revealed from top to bottom.
90
- * - `amount` is this layer's share (0–1) of the max `blurAmount`.
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
- * We stack just TWO layers on both platforms: a faint base blur that covers
93
- * most of the footer and a slightly stronger accent concentrated near the
94
- * bottom. Keeping the overlap shallow avoids compounding the dark tint of
95
- * multiple `BlurView`s (which is what made the earlier 3-layer ramp read as a
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 ProgressiveLayer {
100
- stops: MaskStop[]
104
+ interface ProgressiveBand {
105
+ start: number
101
106
  amount: number
102
107
  }
103
108
 
104
- // Base reveal: a faint trace of blur begins near the very top and grows
105
- // steadily downward, so the upper half still carries visible glass rather than
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
- const PROGRESSIVE_LAYERS: ProgressiveLayer[] = [
116
- { amount: 0.65, stops: BASE_MASK_STOPS },
117
- // Accent: the strongest blur, gathering over the lower portion for depth.
118
- {
119
- amount: 1.0,
120
- stops: [
121
- { offset: 0.0, opacity: 0 },
122
- { offset: 0.3, opacity: 0.15 },
123
- { offset: 0.65, opacity: 0.65 },
124
- { offset: 1.0, opacity: 1 },
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 alpha-gradient mask drawn with `react-native-svg`. `MaskedView`
163
- * reveals its child in proportion to this mask's alpha, so feeding it an eased
164
- * multi-stop gradient makes the layer's blur swell in smoothly from top to
165
- * bottom instead of along a hard seam.
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 GradientMask({ id, stops }: { id: string; stops: MaskStop[] }) {
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="#000000" stopOpacity={s.opacity} />
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
- <MaskedView
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
- {PROGRESSIVE_LAYERS.map((layer, i) => {
246
- const amount = Math.max(1, Math.round(peakBlur * layer.amount))
242
+ {PROGRESSIVE_BANDS.map((band, i) => {
243
+ const amount = Math.max(1, Math.round(peakBlur * band.amount))
247
244
  return (
248
- <MaskedView
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={StyleSheet.absoluteFill}
251
- maskElement={<GradientMask id={`${maskId}-${i}`} stops={layer.stops} />}
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
- </MaskedView>
262
+ </View>
260
263
  )
261
264
  })}
262
265
  </View>