jfs-components 0.1.17 → 0.1.18
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 +9 -0
- package/lib/commonjs/components/AvatarGroup/AvatarGroup.js +41 -20
- package/lib/commonjs/components/ProductMerchandisingCard/ProductMerchandisingCard.js +64 -60
- 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/ProductMerchandisingCard/ProductMerchandisingCard.js +66 -62
- package/lib/module/icons/registry.js +1 -1
- package/lib/module/utils/GlassFill/GlassFill.js +69 -72
- 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/ProductMerchandisingCard/ProductMerchandisingCard.tsx +76 -47
- package/src/icons/registry.ts +1 -1
- package/src/utils/GlassFill/GlassFill.tsx +59 -56
|
@@ -7,10 +7,8 @@ exports.default = void 0;
|
|
|
7
7
|
var _react = _interopRequireWildcard(require("react"));
|
|
8
8
|
var _reactNative = require("react-native");
|
|
9
9
|
var _blur = require("@react-native-community/blur");
|
|
10
|
-
var _maskedView = _interopRequireDefault(require("@react-native-masked-view/masked-view"));
|
|
11
10
|
var _reactNativeSvg = _interopRequireWildcard(require("react-native-svg"));
|
|
12
11
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
13
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
12
|
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
13
|
const DEFAULT_FALLBACK_DARK = '#1414174a';
|
|
16
14
|
const DEFAULT_FALLBACK_LIGHT = '#ffffff66';
|
|
@@ -20,32 +18,30 @@ const DEFAULT_FALLBACK_LIGHT = '#ffffff66';
|
|
|
20
18
|
const NATIVE_BLUR_NAME = _reactNative.Platform.OS === 'android' ? 'AndroidBlurView' : 'BlurView';
|
|
21
19
|
|
|
22
20
|
/**
|
|
23
|
-
* Alpha stop on
|
|
24
|
-
* position (0 = top of the surface, 1 = bottom); `opacity` is the
|
|
25
|
-
* there (0 =
|
|
21
|
+
* Alpha stop on the no-native-blur fallback gradient. `offset` is the vertical
|
|
22
|
+
* position (0 = top of the surface, 1 = bottom); `opacity` is the tint alpha
|
|
23
|
+
* there (0 = fully clear, 1 = full fallback color).
|
|
26
24
|
*
|
|
27
|
-
* Using several stops (rather than a single linear 0 → 1 ramp)
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* "glass" feel rather than a flat translucent panel.
|
|
25
|
+
* Using several stops (rather than a single linear 0 → 1 ramp) eases the tint
|
|
26
|
+
* in, so it swells smoothly toward the bottom instead of along a hard seam —
|
|
27
|
+
* the soft S-curve that gives the surface its "glass" feel.
|
|
31
28
|
*/
|
|
32
29
|
|
|
33
30
|
/**
|
|
34
|
-
* A single
|
|
35
|
-
* - `
|
|
36
|
-
*
|
|
31
|
+
* A single bottom-anchored band of the progressive blur stack.
|
|
32
|
+
* - `start` is where the band begins, as a fraction from the top (0 = covers
|
|
33
|
+
* the whole surface, 0.8 = only the bottom 20%). Each band runs from `start`
|
|
34
|
+
* to the bottom.
|
|
35
|
+
* - `amount` is the band's own blur strength as a share (0–1) of the peak.
|
|
37
36
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* heavy block), while still giving a genuine variable-radius result — the blur
|
|
43
|
-
* radius grows toward the bottom where the two layers overlap.
|
|
37
|
+
* Because each `BlurView` re-blurs everything rendered behind it, the bands
|
|
38
|
+
* COMPOUND where they overlap (toward the bottom), so the effective radius grows
|
|
39
|
+
* downward without any masking. The top region is covered only by the first,
|
|
40
|
+
* faint band; the bottom is covered by all of them.
|
|
44
41
|
*/
|
|
45
42
|
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
// snapping clear. Also reused for the no-native-blur fallback scrim.
|
|
43
|
+
// Eased tint ramp for the no-native-blur fallback scrim. A faint trace begins
|
|
44
|
+
// near the very top and grows steadily downward.
|
|
49
45
|
const BASE_MASK_STOPS = [{
|
|
50
46
|
offset: 0.0,
|
|
51
47
|
opacity: 0
|
|
@@ -62,26 +58,26 @@ const BASE_MASK_STOPS = [{
|
|
|
62
58
|
offset: 1.0,
|
|
63
59
|
opacity: 1
|
|
64
60
|
}];
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
//
|
|
70
|
-
{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
61
|
+
|
|
62
|
+
// Bottom-anchored blur bands (top → bottom). The first band is faint and covers
|
|
63
|
+
// the whole surface so the top reads as barely-there glass; each subsequent band
|
|
64
|
+
// starts lower and adds strength, compounding toward the bottom for a smooth
|
|
65
|
+
// variable-radius result. Quadrature of these shares lands the bottom at ~peak.
|
|
66
|
+
const PROGRESSIVE_BANDS = [{
|
|
67
|
+
start: 0.0,
|
|
68
|
+
amount: 0.18
|
|
69
|
+
}, {
|
|
70
|
+
start: 0.3,
|
|
71
|
+
amount: 0.28
|
|
72
|
+
}, {
|
|
73
|
+
start: 0.52,
|
|
74
|
+
amount: 0.38
|
|
75
|
+
}, {
|
|
76
|
+
start: 0.7,
|
|
77
|
+
amount: 0.5
|
|
78
|
+
}, {
|
|
79
|
+
start: 0.84,
|
|
80
|
+
amount: 0.6
|
|
85
81
|
}];
|
|
86
82
|
|
|
87
83
|
/**
|
|
@@ -114,13 +110,14 @@ const NATIVE_BLUR_SUPPORTED = (() => {
|
|
|
114
110
|
})();
|
|
115
111
|
|
|
116
112
|
/**
|
|
117
|
-
* Vertical
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
113
|
+
* Vertical color-gradient scrim drawn with `react-native-svg` — used as the
|
|
114
|
+
* no-native-blur fallback. Paints `color` at the eased per-stop alpha so the
|
|
115
|
+
* tint swells smoothly from clear (top) to full (bottom), exactly mirroring the
|
|
116
|
+
* old `MaskedView`-over-solid-color fallback but with no native-view masking.
|
|
121
117
|
*/
|
|
122
|
-
function
|
|
118
|
+
function GradientScrim({
|
|
123
119
|
id,
|
|
120
|
+
color,
|
|
124
121
|
stops
|
|
125
122
|
}) {
|
|
126
123
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNativeSvg.default, {
|
|
@@ -135,7 +132,7 @@ function GradientMask({
|
|
|
135
132
|
y2: "1",
|
|
136
133
|
children: stops.map((s, i) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Stop, {
|
|
137
134
|
offset: s.offset,
|
|
138
|
-
stopColor:
|
|
135
|
+
stopColor: color,
|
|
139
136
|
stopOpacity: s.opacity
|
|
140
137
|
}, i))
|
|
141
138
|
})
|
|
@@ -200,38 +197,37 @@ function GlassFill({
|
|
|
200
197
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
201
198
|
style: [_reactNative.StyleSheet.absoluteFill, style],
|
|
202
199
|
pointerEvents: "none",
|
|
203
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
stops: BASE_MASK_STOPS
|
|
208
|
-
}),
|
|
209
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
210
|
-
style: [_reactNative.StyleSheet.absoluteFill, {
|
|
211
|
-
backgroundColor: fallbackColor
|
|
212
|
-
}]
|
|
213
|
-
})
|
|
200
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(GradientScrim, {
|
|
201
|
+
id: `${maskId}-fb`,
|
|
202
|
+
color: fallbackColor,
|
|
203
|
+
stops: BASE_MASK_STOPS
|
|
214
204
|
})
|
|
215
205
|
});
|
|
216
206
|
}
|
|
217
207
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
218
208
|
style: [_reactNative.StyleSheet.absoluteFill, style],
|
|
219
209
|
pointerEvents: "none",
|
|
220
|
-
children:
|
|
221
|
-
const amount = Math.max(1, Math.round(peakBlur *
|
|
222
|
-
return
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
210
|
+
children: PROGRESSIVE_BANDS.map((band, i) => {
|
|
211
|
+
const amount = Math.max(1, Math.round(peakBlur * band.amount));
|
|
212
|
+
return (
|
|
213
|
+
/*#__PURE__*/
|
|
214
|
+
// Each band is clipped to start at `band.start` and run to
|
|
215
|
+
// the bottom; its `BlurView` blurs the content (and any
|
|
216
|
+
// lower bands) behind it, so the radius compounds downward.
|
|
217
|
+
(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
218
|
+
style: [_reactNative.StyleSheet.absoluteFill, {
|
|
219
|
+
top: `${band.start * 100}%`,
|
|
220
|
+
overflow: 'hidden'
|
|
221
|
+
}],
|
|
222
|
+
pointerEvents: "none",
|
|
223
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_blur.BlurView, {
|
|
224
|
+
style: _reactNative.StyleSheet.absoluteFill,
|
|
225
|
+
blurType: blurType,
|
|
226
|
+
blurAmount: amount,
|
|
227
|
+
reducedTransparencyFallbackColor: fallbackColor
|
|
228
|
+
})
|
|
229
|
+
}, i)
|
|
230
|
+
);
|
|
235
231
|
})
|
|
236
232
|
});
|
|
237
233
|
}
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import React from 'react';
|
|
3
|
+
import React, { useId } from 'react';
|
|
4
4
|
import { View, Platform } from 'react-native';
|
|
5
|
-
import
|
|
6
|
-
import Svg, { Path } from 'react-native-svg';
|
|
5
|
+
import Svg, { Defs, Mask, Path, ForeignObject } from 'react-native-svg';
|
|
7
6
|
import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
|
|
8
7
|
import { EMPTY_MODES, flattenChildren } from '../../utils/react-utils';
|
|
9
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
8
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
9
|
function AvatarGroup({
|
|
11
10
|
modes = EMPTY_MODES,
|
|
12
11
|
children,
|
|
13
12
|
style,
|
|
14
13
|
...rest
|
|
15
14
|
}) {
|
|
15
|
+
// Stable, collision-free base for the per-avatar SVG mask ids so multiple
|
|
16
|
+
// groups on one screen (and multiple avatars in a group) never clash.
|
|
17
|
+
const rawId = useId();
|
|
18
|
+
const maskBaseId = `avatargroup-mask-${rawId.replace(/[^a-zA-Z0-9_-]/g, '')}`;
|
|
16
19
|
const gap = getVariableByName('avatarGroup/gap', modes);
|
|
17
20
|
const avatarSize = getVariableByName('avatar/size', modes);
|
|
18
21
|
const avatarRadius = getVariableByName('avatar/radius', modes);
|
|
@@ -41,7 +44,11 @@ function AvatarGroup({
|
|
|
41
44
|
y: r
|
|
42
45
|
};
|
|
43
46
|
|
|
44
|
-
// Native
|
|
47
|
+
// Native mask path: the full avatar square MINUS a circular hole where the
|
|
48
|
+
// next (overlapping) avatar sits. Drawn as a single `evenodd` path so the
|
|
49
|
+
// hole is cut out of the square. Filled WHITE because react-native-svg's
|
|
50
|
+
// `<Mask>` is a *luminance* mask (white = visible, black/absent = hidden) —
|
|
51
|
+
// the inverse of the old `@react-native-masked-view` alpha convention.
|
|
45
52
|
const rectPath = `M 0 0 h ${avatarSizeInt} v ${avatarSizeInt} h -${avatarSizeInt} z`;
|
|
46
53
|
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`;
|
|
47
54
|
const maskPath = `${rectPath} ${circlePath}`;
|
|
@@ -99,25 +106,40 @@ function AvatarGroup({
|
|
|
99
106
|
}, index);
|
|
100
107
|
}
|
|
101
108
|
|
|
102
|
-
// Native
|
|
109
|
+
// Native: mask the avatar with react-native-svg instead of the
|
|
110
|
+
// unmaintained `@react-native-masked-view/masked-view`, whose
|
|
111
|
+
// legacy `requireNativeComponent('RNCMaskedView')` resolves to a
|
|
112
|
+
// plain object (crashing "Element type is invalid") under the New
|
|
113
|
+
// Architecture interop. react-native-svg ships a Fabric/codegen
|
|
114
|
+
// `<Mask>` + `<ForeignObject>` that resolves on both architectures;
|
|
115
|
+
// the avatar is hosted inside the `<ForeignObject>` and revealed
|
|
116
|
+
// through the luminance mask.
|
|
117
|
+
const maskId = `${maskBaseId}-${index}`;
|
|
103
118
|
return /*#__PURE__*/_jsx(View, {
|
|
104
119
|
style: wrapperStyle,
|
|
105
|
-
children: /*#__PURE__*/
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
120
|
+
children: /*#__PURE__*/_jsxs(Svg, {
|
|
121
|
+
height: "100%",
|
|
122
|
+
width: "100%",
|
|
123
|
+
viewBox: `0 0 ${avatarSizeInt} ${avatarSizeInt}`,
|
|
124
|
+
children: [/*#__PURE__*/_jsx(Defs, {
|
|
125
|
+
children: /*#__PURE__*/_jsx(Mask, {
|
|
126
|
+
id: maskId,
|
|
127
|
+
maskUnits: "userSpaceOnUse",
|
|
128
|
+
maskContentUnits: "userSpaceOnUse",
|
|
129
|
+
children: /*#__PURE__*/_jsx(Path, {
|
|
130
|
+
d: maskPath,
|
|
131
|
+
fill: "white",
|
|
132
|
+
fillRule: "evenodd"
|
|
133
|
+
})
|
|
118
134
|
})
|
|
119
|
-
}),
|
|
120
|
-
|
|
135
|
+
}), /*#__PURE__*/_jsx(ForeignObject, {
|
|
136
|
+
x: "0",
|
|
137
|
+
y: "0",
|
|
138
|
+
width: avatarSizeInt,
|
|
139
|
+
height: avatarSizeInt,
|
|
140
|
+
mask: `url(#${maskId})`,
|
|
141
|
+
children: clonedChild
|
|
142
|
+
})]
|
|
121
143
|
})
|
|
122
144
|
}, index);
|
|
123
145
|
})
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import React, { useId, useMemo } from 'react';
|
|
4
|
-
import { View, Text, Pressable, StyleSheet
|
|
5
|
-
import
|
|
6
|
-
import Svg, { Defs, LinearGradient, Stop, Rect } from 'react-native-svg';
|
|
4
|
+
import { View, Text, Pressable, StyleSheet } from 'react-native';
|
|
5
|
+
import Svg, { Defs, LinearGradient, Stop, Rect, Mask, Filter, FeGaussianBlur, Image as SvgImage } from 'react-native-svg';
|
|
7
6
|
import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
|
|
8
7
|
import { EMPTY_MODES, resolveTruncation } from '../../utils/react-utils';
|
|
9
8
|
import Avatar from '../Avatar/Avatar';
|
|
@@ -65,7 +64,9 @@ function ProductMerchandisingCard({
|
|
|
65
64
|
const rawId = useId();
|
|
66
65
|
const safeId = rawId.replace(/[^a-zA-Z0-9_-]/g, '');
|
|
67
66
|
const scrimId = `pmc-footer-scrim-${safeId}`;
|
|
67
|
+
const blurGradientId = `pmc-footer-blurgrad-${safeId}`;
|
|
68
68
|
const blurMaskId = `pmc-footer-blurmask-${safeId}`;
|
|
69
|
+
const blurFilterId = `pmc-footer-blurfilter-${safeId}`;
|
|
69
70
|
const normalizedImageSource = useMemo(() => normalizeImageSource(imageSource), [imageSource]);
|
|
70
71
|
const tokens = useMemo(() => resolveTokens(modes), [modes]);
|
|
71
72
|
const containerStyle = {
|
|
@@ -159,57 +160,63 @@ function ProductMerchandisingCard({
|
|
|
159
160
|
children: [normalizedImageSource != null ? /*#__PURE__*/_jsx(View, {
|
|
160
161
|
style: StyleSheet.absoluteFill,
|
|
161
162
|
pointerEvents: "none",
|
|
162
|
-
children: /*#__PURE__*/
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
163
|
+
children: /*#__PURE__*/_jsxs(Svg, {
|
|
164
|
+
width: "100%",
|
|
165
|
+
height: "100%",
|
|
166
|
+
children: [/*#__PURE__*/_jsxs(Defs, {
|
|
167
|
+
children: [/*#__PURE__*/_jsx(Filter, {
|
|
168
|
+
id: blurFilterId,
|
|
169
|
+
x: "-15%",
|
|
170
|
+
y: "-15%",
|
|
171
|
+
width: "130%",
|
|
172
|
+
height: "130%",
|
|
173
|
+
children: /*#__PURE__*/_jsx(FeGaussianBlur, {
|
|
174
|
+
stdDeviation: tokens.imageBlurStdDeviation,
|
|
175
|
+
edgeMode: "duplicate"
|
|
176
|
+
})
|
|
177
|
+
}), /*#__PURE__*/_jsxs(LinearGradient, {
|
|
178
|
+
id: blurGradientId,
|
|
179
|
+
x1: "0",
|
|
180
|
+
y1: "0",
|
|
181
|
+
x2: "0",
|
|
182
|
+
y2: "1",
|
|
183
|
+
children: [/*#__PURE__*/_jsx(Stop, {
|
|
184
|
+
offset: "0",
|
|
185
|
+
stopColor: "#ffffff",
|
|
186
|
+
stopOpacity: 0
|
|
187
|
+
}), /*#__PURE__*/_jsx(Stop, {
|
|
188
|
+
offset: "0.35",
|
|
189
|
+
stopColor: "#ffffff",
|
|
190
|
+
stopOpacity: 0.5
|
|
191
|
+
}), /*#__PURE__*/_jsx(Stop, {
|
|
192
|
+
offset: "0.7",
|
|
193
|
+
stopColor: "#ffffff",
|
|
194
|
+
stopOpacity: 0.92
|
|
195
|
+
}), /*#__PURE__*/_jsx(Stop, {
|
|
196
|
+
offset: "1",
|
|
197
|
+
stopColor: "#ffffff",
|
|
198
|
+
stopOpacity: 1
|
|
199
|
+
})]
|
|
200
|
+
}), /*#__PURE__*/_jsx(Mask, {
|
|
201
|
+
id: blurMaskId,
|
|
202
|
+
children: /*#__PURE__*/_jsx(Rect, {
|
|
203
|
+
x: "0",
|
|
204
|
+
y: "0",
|
|
205
|
+
width: "100%",
|
|
206
|
+
height: "100%",
|
|
207
|
+
fill: `url(#${blurGradientId})`
|
|
191
208
|
})
|
|
192
|
-
}), /*#__PURE__*/_jsx(Rect, {
|
|
193
|
-
x: "0",
|
|
194
|
-
y: "0",
|
|
195
|
-
width: "100%",
|
|
196
|
-
height: "100%",
|
|
197
|
-
fill: `url(#${blurMaskId})`
|
|
198
209
|
})]
|
|
199
|
-
}),
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
width: '100%',
|
|
210
|
-
height
|
|
211
|
-
}
|
|
212
|
-
})
|
|
210
|
+
}), /*#__PURE__*/_jsx(SvgImage, {
|
|
211
|
+
href: normalizedImageSource,
|
|
212
|
+
x: "0",
|
|
213
|
+
y: "0",
|
|
214
|
+
width: "100%",
|
|
215
|
+
height: "100%",
|
|
216
|
+
preserveAspectRatio: "xMidYMid slice",
|
|
217
|
+
filter: `url(#${blurFilterId})`,
|
|
218
|
+
mask: `url(#${blurMaskId})`
|
|
219
|
+
})]
|
|
213
220
|
})
|
|
214
221
|
}) : /*#__PURE__*/_jsx(GlassFill, {
|
|
215
222
|
tint: "dark",
|
|
@@ -328,19 +335,16 @@ function resolveTokens(modes) {
|
|
|
328
335
|
const sbFamily = asStr(getVariableByName('productMerchandisingcard/specialbadge/text/fontfamily', modes), 'JioType Var');
|
|
329
336
|
const sbWeight = asStr(getVariableByName('productMerchandisingcard/specialbadge/text/fontweight', modes), '500');
|
|
330
337
|
|
|
331
|
-
//
|
|
332
|
-
//
|
|
333
|
-
//
|
|
334
|
-
// "
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
android: Math.max(12, Math.round(blurRadius * 0.95)),
|
|
338
|
-
default: Math.max(8, Math.round(blurRadius * 0.6))
|
|
339
|
-
});
|
|
338
|
+
// SVG `<FeGaussianBlur stdDeviation>` is resolution-independent and renders
|
|
339
|
+
// an identical Gaussian on iOS, Android and web — so unlike the old
|
|
340
|
+
// `Image.blurRadius` path it needs no per-platform tuning. `stdDeviation` is
|
|
341
|
+
// roughly half a perceptual "blur radius", so we scale the `blur/minimal`
|
|
342
|
+
// token down to land on the same subtle frosted strength as the design.
|
|
343
|
+
const imageBlurStdDeviation = Math.max(4, Math.round(blurRadius * 0.35));
|
|
340
344
|
return {
|
|
341
345
|
radius,
|
|
342
346
|
blurIntensity: Math.max(0, Math.min(100, Math.round(blurRadius * BLUR_INTENSITY_FACTOR))),
|
|
343
|
-
|
|
347
|
+
imageBlurStdDeviation,
|
|
344
348
|
header: {
|
|
345
349
|
flexDirection: 'row',
|
|
346
350
|
alignItems: 'flex-start',
|