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
package/CHANGELOG.md CHANGED
@@ -4,6 +4,21 @@ All notable changes to this project are documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
+ ## [0.1.19] - 2026-06-29
8
+
9
+ - Card components — optional `onPress` handler added to `Card`, `CardInsight`, `CardProviderInfo`, `MediaCard`, `DebitCard`, `CardFeedback`, `RechargeCard`, and `TestimonialsCard`. When set, the card renders through a `Pressable` with `accessibilityRole="button"`, optional `disabled`, and a pressed-state opacity feedback; when omitted, behaviour is unchanged.
10
+
11
+ ---
12
+
13
+ ## [0.1.18] - 2026-06-29
14
+
15
+ - **Fix:** Remove `@react-native-masked-view/masked-view` — fixes `Element type is invalid` crash on New Architecture (`ProductMerchandisingCard` image cards, `AvatarGroup`, `GlassFill` progressive blur). All masking now uses `react-native-svg` (no new peer deps; consumers can drop `masked-view` if added as a workaround).
16
+ - `ProductMerchandisingCard` — footer image blur via SVG `FeGaussianBlur` + gradient mask (cross-platform, no per-platform `blurRadius` tuning).
17
+ - `AvatarGroup` — overlap cutout via SVG `Mask` + `ForeignObject`.
18
+ - `GlassFill` — progressive blur via stacked `BlurView` bands; no-native-blur fallback uses SVG gradient scrim.
19
+
20
+ ---
21
+
7
22
  ## [0.1.16] - 2026-06-26
8
23
 
9
24
  - Added `CarouselCardAccounts` — horizontally scrollable account-card strip built on `Carousel` with token-driven gap and snap-aligned card slots.
@@ -4,21 +4,23 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _react = _interopRequireDefault(require("react"));
7
+ var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
- var _maskedView = _interopRequireDefault(require("@react-native-masked-view/masked-view"));
10
9
  var _reactNativeSvg = _interopRequireWildcard(require("react-native-svg"));
11
10
  var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
12
11
  var _reactUtils = require("../../utils/react-utils");
13
12
  var _jsxRuntime = require("react/jsx-runtime");
14
13
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
15
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
16
14
  function AvatarGroup({
17
15
  modes = _reactUtils.EMPTY_MODES,
18
16
  children,
19
17
  style,
20
18
  ...rest
21
19
  }) {
20
+ // Stable, collision-free base for the per-avatar SVG mask ids so multiple
21
+ // groups on one screen (and multiple avatars in a group) never clash.
22
+ const rawId = (0, _react.useId)();
23
+ const maskBaseId = `avatargroup-mask-${rawId.replace(/[^a-zA-Z0-9_-]/g, '')}`;
22
24
  const gap = (0, _figmaVariablesResolver.getVariableByName)('avatarGroup/gap', modes);
23
25
  const avatarSize = (0, _figmaVariablesResolver.getVariableByName)('avatar/size', modes);
24
26
  const avatarRadius = (0, _figmaVariablesResolver.getVariableByName)('avatar/radius', modes);
@@ -47,7 +49,11 @@ function AvatarGroup({
47
49
  y: r
48
50
  };
49
51
 
50
- // Native Mask Path
52
+ // Native mask path: the full avatar square MINUS a circular hole where the
53
+ // next (overlapping) avatar sits. Drawn as a single `evenodd` path so the
54
+ // hole is cut out of the square. Filled WHITE because react-native-svg's
55
+ // `<Mask>` is a *luminance* mask (white = visible, black/absent = hidden) —
56
+ // the inverse of the old `@react-native-masked-view` alpha convention.
51
57
  const rectPath = `M 0 0 h ${avatarSizeInt} v ${avatarSizeInt} h -${avatarSizeInt} z`;
52
58
  const circlePath = `M ${holeCenter.x},${holeCenter.y} m -${holeRadius},0 a ${holeRadius},${holeRadius} 0 1,0 ${holeRadius * 2},0 a ${holeRadius},${holeRadius} 0 1,0 -${holeRadius * 2},0`;
53
59
  const maskPath = `${rectPath} ${circlePath}`;
@@ -105,25 +111,40 @@ function AvatarGroup({
105
111
  }, index);
106
112
  }
107
113
 
108
- // Native MaskedView
114
+ // Native: mask the avatar with react-native-svg instead of the
115
+ // unmaintained `@react-native-masked-view/masked-view`, whose
116
+ // legacy `requireNativeComponent('RNCMaskedView')` resolves to a
117
+ // plain object (crashing "Element type is invalid") under the New
118
+ // Architecture interop. react-native-svg ships a Fabric/codegen
119
+ // `<Mask>` + `<ForeignObject>` that resolves on both architectures;
120
+ // the avatar is hosted inside the `<ForeignObject>` and revealed
121
+ // through the luminance mask.
122
+ const maskId = `${maskBaseId}-${index}`;
109
123
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
110
124
  style: wrapperStyle,
111
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_maskedView.default, {
112
- style: {
113
- flex: 1,
114
- height: '100%'
115
- },
116
- maskElement: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.default, {
117
- height: "100%",
118
- width: "100%",
119
- viewBox: `0 0 ${avatarSizeInt} ${avatarSizeInt}`,
120
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Path, {
121
- d: maskPath,
122
- fill: "black",
123
- fillRule: "evenodd"
125
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNativeSvg.default, {
126
+ height: "100%",
127
+ width: "100%",
128
+ viewBox: `0 0 ${avatarSizeInt} ${avatarSizeInt}`,
129
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Defs, {
130
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Mask, {
131
+ id: maskId,
132
+ maskUnits: "userSpaceOnUse",
133
+ maskContentUnits: "userSpaceOnUse",
134
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Path, {
135
+ d: maskPath,
136
+ fill: "white",
137
+ fillRule: "evenodd"
138
+ })
124
139
  })
125
- }),
126
- children: clonedChild
140
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.ForeignObject, {
141
+ x: "0",
142
+ y: "0",
143
+ width: avatarSizeInt,
144
+ height: avatarSizeInt,
145
+ mask: `url(#${maskId})`,
146
+ children: clonedChild
147
+ })]
127
148
  })
128
149
  }, index);
129
150
  })
@@ -38,7 +38,10 @@ function Card({
38
38
  children,
39
39
  modes = _reactUtils.EMPTY_MODES,
40
40
  mediaAspectRatio = 154 / 116,
41
- style
41
+ style,
42
+ onPress,
43
+ disabled,
44
+ accessibilityLabel
42
45
  }) {
43
46
  // Resolve Card Container Tokens
44
47
  const backgroundColor = (0, _figmaVariablesResolver.getVariableByName)('card/background/color', modes);
@@ -102,22 +105,36 @@ function Card({
102
105
  paddingHorizontal: contentPaddingHorizontal,
103
106
  paddingVertical: contentPaddingVertical
104
107
  };
108
+ const content = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
109
+ children: [header && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
110
+ style: headerWrapperStyle,
111
+ children: headerWithModes
112
+ }), media && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
113
+ style: mediaWrapperStyle,
114
+ children: mediaWithModes
115
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
116
+ style: contentWrapperStyle,
117
+ children: children
118
+ })]
119
+ });
105
120
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(CardContext.Provider, {
106
121
  value: {
107
122
  modes
108
123
  },
109
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
124
+ children: onPress ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
125
+ style: [containerStyle, style],
126
+ onPress: onPress,
127
+ disabled: disabled,
128
+ accessibilityRole: "button",
129
+ accessibilityLabel: accessibilityLabel,
130
+ accessibilityState: {
131
+ disabled: !!disabled
132
+ },
133
+ children: content
134
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
110
135
  style: [containerStyle, style],
111
- children: [header && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
112
- style: headerWrapperStyle,
113
- children: headerWithModes
114
- }), media && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
115
- style: mediaWrapperStyle,
116
- children: mediaWithModes
117
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
118
- style: contentWrapperStyle,
119
- children: children
120
- })]
136
+ accessibilityLabel: accessibilityLabel,
137
+ children: content
121
138
  })
122
139
  });
123
140
  }
@@ -29,7 +29,10 @@ const CardFeedbackContext = /*#__PURE__*/(0, _react.createContext)({});
29
29
  function CardFeedback({
30
30
  children,
31
31
  modes: propModes,
32
- style
32
+ style,
33
+ onPress,
34
+ disabled,
35
+ accessibilityLabel
33
36
  }) {
34
37
  const modes = {
35
38
  'Appearance.System': 'positive',
@@ -58,8 +61,19 @@ function CardFeedback({
58
61
  value: {
59
62
  modes
60
63
  },
61
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
64
+ children: onPress ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
65
+ style: [containerStyle, style],
66
+ onPress: onPress,
67
+ disabled: disabled,
68
+ accessibilityRole: "button",
69
+ accessibilityLabel: accessibilityLabel,
70
+ accessibilityState: {
71
+ disabled: !!disabled
72
+ },
73
+ children: children
74
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
62
75
  style: [containerStyle, style],
76
+ accessibilityLabel: accessibilityLabel,
63
77
  children: children
64
78
  })
65
79
  });
@@ -33,7 +33,10 @@ function CardInsight({
33
33
  footer,
34
34
  divider,
35
35
  modes = _reactUtils.EMPTY_MODES,
36
- style
36
+ style,
37
+ onPress,
38
+ disabled,
39
+ accessibilityLabel
37
40
  }) {
38
41
  const background = (0, _figmaVariablesResolver.getVariableByName)('cardInsight/background', modes) ?? '#ffffff';
39
42
  const radius = (0, _figmaVariablesResolver.getVariableByName)('cardInsight/radius', modes) ?? 12;
@@ -106,18 +109,18 @@ function CardInsight({
106
109
  };
107
110
  const footerNode = renderFooter();
108
111
  const showDivider = footerNode !== null && divider !== false && divider !== null;
109
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
110
- style: [{
111
- backgroundColor: background,
112
- borderRadius: radius,
113
- borderWidth,
114
- borderColor,
115
- paddingHorizontal,
116
- paddingVertical,
117
- gap,
118
- overflow: 'hidden',
119
- alignItems: 'stretch'
120
- }, style],
112
+ const containerStyle = {
113
+ backgroundColor: background,
114
+ borderRadius: radius,
115
+ borderWidth,
116
+ borderColor,
117
+ paddingHorizontal,
118
+ paddingVertical,
119
+ gap,
120
+ overflow: 'hidden',
121
+ alignItems: 'stretch'
122
+ };
123
+ const content = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
121
124
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
122
125
  style: {
123
126
  flexDirection: 'row',
@@ -165,5 +168,23 @@ function CardInsight({
165
168
  children: renderSlot()
166
169
  }), showDivider ? renderDivider() : null, footerNode]
167
170
  });
171
+ if (onPress) {
172
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
173
+ style: [containerStyle, style],
174
+ onPress: onPress,
175
+ disabled: disabled,
176
+ accessibilityRole: "button",
177
+ accessibilityLabel: accessibilityLabel ?? title,
178
+ accessibilityState: {
179
+ disabled: !!disabled
180
+ },
181
+ children: content
182
+ });
183
+ }
184
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
185
+ style: [containerStyle, style],
186
+ accessibilityLabel: accessibilityLabel,
187
+ children: content
188
+ });
168
189
  }
169
190
  var _default = exports.default = CardInsight;
@@ -23,7 +23,10 @@ function CardProviderInfo({
23
23
  imageSource,
24
24
  children,
25
25
  modes = _reactUtils.EMPTY_MODES,
26
- style
26
+ style,
27
+ onPress,
28
+ disabled,
29
+ accessibilityLabel
27
30
  }) {
28
31
  const background = (0, _figmaVariablesResolver.getVariableByName)('card/providerInfo/background', modes) ?? '#fef4e5';
29
32
  const border = (0, _figmaVariablesResolver.getVariableByName)('card/providerInfo/border', modes) ?? '#fef4e5';
@@ -48,8 +51,7 @@ function CardProviderInfo({
48
51
  for (let i = 0; i < childArray.length; i += 2) {
49
52
  rows.push(childArray.slice(i, i + 2));
50
53
  }
51
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
52
- style: [containerStyle, style],
54
+ const content = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
53
55
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_ProductLabel.default, {
54
56
  label: label,
55
57
  imageSource: imageSource,
@@ -72,5 +74,23 @@ function CardProviderInfo({
72
74
  }, i))
73
75
  })]
74
76
  });
77
+ if (onPress) {
78
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
79
+ style: [containerStyle, style],
80
+ onPress: onPress,
81
+ disabled: disabled,
82
+ accessibilityRole: "button",
83
+ accessibilityLabel: accessibilityLabel ?? label,
84
+ accessibilityState: {
85
+ disabled: !!disabled
86
+ },
87
+ children: content
88
+ });
89
+ }
90
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
91
+ style: [containerStyle, style],
92
+ accessibilityLabel: accessibilityLabel,
93
+ children: content
94
+ });
75
95
  }
76
96
  var _default = exports.default = CardProviderInfo;
@@ -22,7 +22,10 @@ function DebitCard({
22
22
  bankLogoSlot,
23
23
  providerLogoSlot,
24
24
  modes: propModes = _reactUtils.EMPTY_MODES,
25
- style
25
+ style,
26
+ onPress,
27
+ disabled,
28
+ accessibilityLabel
26
29
  }) {
27
30
  const {
28
31
  modes: globalModes
@@ -121,8 +124,7 @@ function DebitCard({
121
124
  };
122
125
  return cardArtSource;
123
126
  }, [cardArtSource]);
124
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
125
- style: [containerStyle, style],
127
+ const content = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
126
128
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
127
129
  style: headerStyle,
128
130
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
@@ -162,5 +164,23 @@ function DebitCard({
162
164
  })]
163
165
  })]
164
166
  });
167
+ if (onPress) {
168
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
169
+ style: [containerStyle, style],
170
+ onPress: onPress,
171
+ disabled: disabled,
172
+ accessibilityRole: "button",
173
+ accessibilityLabel: accessibilityLabel ?? `${bankName} ${cardType} ${cardNumber}`,
174
+ accessibilityState: {
175
+ disabled: !!disabled
176
+ },
177
+ children: content
178
+ });
179
+ }
180
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
181
+ style: [containerStyle, style],
182
+ accessibilityLabel: accessibilityLabel,
183
+ children: content
184
+ });
165
185
  }
166
186
  var _default = exports.default = DebitCard;
@@ -44,7 +44,10 @@ function MediaCard({
44
44
  media,
45
45
  children,
46
46
  modes = _reactUtils.EMPTY_MODES,
47
- style
47
+ style,
48
+ onPress,
49
+ disabled,
50
+ accessibilityLabel
48
51
  }) {
49
52
  const radius = parseFloat((0, _figmaVariablesResolver.getVariableByName)('cardMedia/radius', modes));
50
53
  const containerStyle = {
@@ -59,17 +62,31 @@ function MediaCard({
59
62
  accessibilityElementsHidden: true,
60
63
  importantForAccessibility: "no"
61
64
  }) : null);
65
+ const content = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
66
+ children: [background, children != null ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
67
+ style: _reactNative.StyleSheet.absoluteFill,
68
+ pointerEvents: "box-none",
69
+ children: children
70
+ }) : null]
71
+ });
62
72
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(MediaCardContext.Provider, {
63
73
  value: {
64
74
  modes
65
75
  },
66
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
76
+ children: onPress ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
77
+ style: [containerStyle, style],
78
+ onPress: onPress,
79
+ disabled: disabled,
80
+ accessibilityRole: "button",
81
+ accessibilityLabel: accessibilityLabel,
82
+ accessibilityState: {
83
+ disabled: !!disabled
84
+ },
85
+ children: content
86
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
67
87
  style: [containerStyle, style],
68
- children: [background, children != null ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
69
- style: _reactNative.StyleSheet.absoluteFill,
70
- pointerEvents: "box-none",
71
- children: children
72
- }) : null]
88
+ accessibilityLabel: accessibilityLabel,
89
+ children: content
73
90
  })
74
91
  });
75
92
  }
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
- var _maskedView = _interopRequireDefault(require("@react-native-masked-view/masked-view"));
10
9
  var _reactNativeSvg = _interopRequireWildcard(require("react-native-svg"));
11
10
  var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
12
11
  var _reactUtils = require("../../utils/react-utils");
@@ -71,7 +70,9 @@ function ProductMerchandisingCard({
71
70
  const rawId = (0, _react.useId)();
72
71
  const safeId = rawId.replace(/[^a-zA-Z0-9_-]/g, '');
73
72
  const scrimId = `pmc-footer-scrim-${safeId}`;
73
+ const blurGradientId = `pmc-footer-blurgrad-${safeId}`;
74
74
  const blurMaskId = `pmc-footer-blurmask-${safeId}`;
75
+ const blurFilterId = `pmc-footer-blurfilter-${safeId}`;
75
76
  const normalizedImageSource = (0, _react.useMemo)(() => normalizeImageSource(imageSource), [imageSource]);
76
77
  const tokens = (0, _react.useMemo)(() => resolveTokens(modes), [modes]);
77
78
  const containerStyle = {
@@ -165,57 +166,63 @@ function ProductMerchandisingCard({
165
166
  children: [normalizedImageSource != null ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
166
167
  style: _reactNative.StyleSheet.absoluteFill,
167
168
  pointerEvents: "none",
168
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_maskedView.default, {
169
- style: _reactNative.StyleSheet.absoluteFill,
170
- maskElement: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNativeSvg.default, {
171
- width: "100%",
172
- height: "100%",
173
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Defs, {
174
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNativeSvg.LinearGradient, {
175
- id: blurMaskId,
176
- x1: "0",
177
- y1: "0",
178
- x2: "0",
179
- y2: "1",
180
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Stop, {
181
- offset: "0",
182
- stopColor: "#000000",
183
- stopOpacity: 0
184
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Stop, {
185
- offset: "0.35",
186
- stopColor: "#000000",
187
- stopOpacity: 0.5
188
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Stop, {
189
- offset: "0.7",
190
- stopColor: "#000000",
191
- stopOpacity: 0.92
192
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Stop, {
193
- offset: "1",
194
- stopColor: "#000000",
195
- stopOpacity: 1
196
- })]
169
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNativeSvg.default, {
170
+ width: "100%",
171
+ height: "100%",
172
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNativeSvg.Defs, {
173
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Filter, {
174
+ id: blurFilterId,
175
+ x: "-15%",
176
+ y: "-15%",
177
+ width: "130%",
178
+ height: "130%",
179
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.FeGaussianBlur, {
180
+ stdDeviation: tokens.imageBlurStdDeviation,
181
+ edgeMode: "duplicate"
182
+ })
183
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNativeSvg.LinearGradient, {
184
+ id: blurGradientId,
185
+ x1: "0",
186
+ y1: "0",
187
+ x2: "0",
188
+ y2: "1",
189
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Stop, {
190
+ offset: "0",
191
+ stopColor: "#ffffff",
192
+ stopOpacity: 0
193
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Stop, {
194
+ offset: "0.35",
195
+ stopColor: "#ffffff",
196
+ stopOpacity: 0.5
197
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Stop, {
198
+ offset: "0.7",
199
+ stopColor: "#ffffff",
200
+ stopOpacity: 0.92
201
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Stop, {
202
+ offset: "1",
203
+ stopColor: "#ffffff",
204
+ stopOpacity: 1
205
+ })]
206
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Mask, {
207
+ id: blurMaskId,
208
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Rect, {
209
+ x: "0",
210
+ y: "0",
211
+ width: "100%",
212
+ height: "100%",
213
+ fill: `url(#${blurGradientId})`
197
214
  })
198
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Rect, {
199
- x: "0",
200
- y: "0",
201
- width: "100%",
202
- height: "100%",
203
- fill: `url(#${blurMaskId})`
204
215
  })]
205
- }),
206
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
207
- source: normalizedImageSource,
208
- blurRadius: tokens.imageBlurRadius,
209
- resizeMode: "cover",
210
- style: {
211
- position: 'absolute',
212
- left: 0,
213
- right: 0,
214
- bottom: 0,
215
- width: '100%',
216
- height
217
- }
218
- })
216
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Image, {
217
+ href: normalizedImageSource,
218
+ x: "0",
219
+ y: "0",
220
+ width: "100%",
221
+ height: "100%",
222
+ preserveAspectRatio: "xMidYMid slice",
223
+ filter: `url(#${blurFilterId})`,
224
+ mask: `url(#${blurMaskId})`
225
+ })]
219
226
  })
220
227
  }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_GlassFill.default, {
221
228
  tint: "dark",
@@ -334,19 +341,16 @@ function resolveTokens(modes) {
334
341
  const sbFamily = asStr((0, _figmaVariablesResolver.getVariableByName)('productMerchandisingcard/specialbadge/text/fontfamily', modes), 'JioType Var');
335
342
  const sbWeight = asStr((0, _figmaVariablesResolver.getVariableByName)('productMerchandisingcard/specialbadge/text/fontweight', modes), '500');
336
343
 
337
- // `Image.blurRadius` is interpreted differently per platform — iOS applies a
338
- // strong Gaussian while Android's IterativeBoxBlur is gentler at the same
339
- // numeric radius so we tune each platform to land on the same perceived
340
- // "minimal" frosted strength as the Figma design.
341
- const imageBlurRadius = _reactNative.Platform.select({
342
- ios: Math.max(6, Math.round(blurRadius * 0.5)),
343
- android: Math.max(12, Math.round(blurRadius * 0.95)),
344
- default: Math.max(8, Math.round(blurRadius * 0.6))
345
- });
344
+ // SVG `<FeGaussianBlur stdDeviation>` is resolution-independent and renders
345
+ // an identical Gaussian on iOS, Android and web so unlike the old
346
+ // `Image.blurRadius` path it needs no per-platform tuning. `stdDeviation` is
347
+ // roughly half a perceptual "blur radius", so we scale the `blur/minimal`
348
+ // token down to land on the same subtle frosted strength as the design.
349
+ const imageBlurStdDeviation = Math.max(4, Math.round(blurRadius * 0.35));
346
350
  return {
347
351
  radius,
348
352
  blurIntensity: Math.max(0, Math.min(100, Math.round(blurRadius * BLUR_INTENSITY_FACTOR))),
349
- imageBlurRadius,
353
+ imageBlurStdDeviation,
350
354
  header: {
351
355
  flexDirection: 'row',
352
356
  alignItems: 'flex-start',
@@ -41,7 +41,10 @@ function RechargeCard({
41
41
  subscriptionContent,
42
42
  actions,
43
43
  modes = _reactUtils.EMPTY_MODES,
44
- style
44
+ style,
45
+ onPress,
46
+ disabled,
47
+ accessibilityLabel
45
48
  }) {
46
49
  // Container Tokens (defaults mirror Figma node 2235:937).
47
50
  const backgroundColor = (0, _figmaVariablesResolver.getVariableByName)('rechargeCard/background', modes);
@@ -90,18 +93,18 @@ function RechargeCard({
90
93
  // Pass modes to subscription children (e.g. AvatarGroup)
91
94
  // Now encapsulated, so we just pass children to AvatarGroup
92
95
  const hasSubscriptions = _react.default.Children.count(subscriptionContent) > 0;
93
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
94
- style: [{
95
- backgroundColor,
96
- paddingHorizontal,
97
- paddingVertical,
98
- gap,
99
- borderRadius: radius,
100
- borderWidth: strokeWidth,
101
- borderColor: strokeColor,
102
- minWidth,
103
- alignItems: 'flex-start'
104
- }, style],
96
+ const containerStyle = {
97
+ backgroundColor,
98
+ paddingHorizontal,
99
+ paddingVertical,
100
+ gap,
101
+ borderRadius: radius,
102
+ borderWidth: strokeWidth,
103
+ borderColor: strokeColor,
104
+ minWidth,
105
+ alignItems: 'flex-start'
106
+ };
107
+ const content = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
105
108
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
106
109
  style: {
107
110
  gap: headerGap,
@@ -217,4 +220,22 @@ function RechargeCard({
217
220
  children: actions
218
221
  })]
219
222
  });
223
+ if (onPress) {
224
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
225
+ style: [containerStyle, style],
226
+ onPress: onPress,
227
+ disabled: disabled,
228
+ accessibilityRole: "button",
229
+ accessibilityLabel: accessibilityLabel ?? title,
230
+ accessibilityState: {
231
+ disabled: !!disabled
232
+ },
233
+ children: content
234
+ });
235
+ }
236
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
237
+ style: [containerStyle, style],
238
+ accessibilityLabel: accessibilityLabel,
239
+ children: content
240
+ });
220
241
  }