jfs-components 0.1.34 → 0.1.35

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.
@@ -27,8 +27,8 @@ function resolveSize(size, modes) {
27
27
  height: size
28
28
  };
29
29
  if (size && typeof size === 'object') return size;
30
- const width = Number((0, _figmaVariablesResolver.getVariableByName)('media/width', modes));
31
- const height = Number((0, _figmaVariablesResolver.getVariableByName)('media/height', modes));
30
+ const width = Number((0, _figmaVariablesResolver.getVariableByName)('video/width', modes)) || DEFAULT_SIZE;
31
+ const height = Number((0, _figmaVariablesResolver.getVariableByName)('video/height', modes)) || DEFAULT_SIZE;
32
32
  return {
33
33
  width,
34
34
  height
@@ -55,8 +55,8 @@ function resolveSize(size, modes) {
55
55
  * webpack via platform extensions — same pattern as `MediaCard/GlassFill`.
56
56
  *
57
57
  * Token-driven sizing: when `size` is omitted, `LottiePlayer` reads
58
- * `media/width` and `media/height` from the Figma variables resolver, so the
59
- * animation matches the surrounding component's `Media / Output` mode
58
+ * `video/width` and `video/height` from the Figma variables resolver, so the
59
+ * animation matches the surrounding component's `Video / Output` mode
60
60
  * automatically. This is the same sizing contract `PageHero` and
61
61
  * `LottieIntroBlock` use for their `media` slots.
62
62
  *
@@ -67,7 +67,7 @@ function resolveSize(size, modes) {
67
67
  *
68
68
  * <LottiePlayer source={animation} /> // 117 × 117 (default)
69
69
  * <LottiePlayer source={animation} size={70} /> // 70 × 70
70
- * <LottiePlayer source={animation} modes={{ 'Media / Output': 'S' }} /> // 20 × 20
70
+ * <LottiePlayer source={animation} modes={{ 'Video / Output': 'S' }} /> // 20 × 20
71
71
  * <PageHero media={<LottiePlayer source={animation} />} />
72
72
  * ```
73
73
  */
@@ -18,8 +18,8 @@ function resolveSize(size, modes) {
18
18
  height: size
19
19
  };
20
20
  if (size && typeof size === 'object') return size;
21
- const width = Number((0, _figmaVariablesResolver.getVariableByName)('media/width', modes));
22
- const height = Number((0, _figmaVariablesResolver.getVariableByName)('media/height', modes));
21
+ const width = Number((0, _figmaVariablesResolver.getVariableByName)('video/width', modes)) || DEFAULT_SIZE;
22
+ const height = Number((0, _figmaVariablesResolver.getVariableByName)('video/height', modes)) || DEFAULT_SIZE;
23
23
  return {
24
24
  width,
25
25
  height
@@ -13,16 +13,24 @@ var _reactUtils = require("../../utils/react-utils");
13
13
  var _jsxRuntime = require("react/jsx-runtime");
14
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
15
  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); }
16
+ // Figma media frame is 117×117 ("Video / Output" L). Used when the token
17
+ // collection is missing from a consumer's variables JSON so the media slot
18
+ // never collapses to 0.
19
+ const MEDIA_FALLBACK = 117;
16
20
  /**
17
21
  * PageHero displays a centered hero block typically used at the top of a page
18
22
  * or feature screen. It contains an optional media slot (illustration / image
19
23
  * / Lottie / SVG / video — consumer's choice), an eyebrow line, a large
20
- * headline, an optional supporting line (e.g. price / timeline), and an
21
- * optional action button.
24
+ * headline, an optional supporting line (e.g. price), an optional body line
25
+ * (e.g. timeline), and an optional action button.
22
26
  *
23
27
  * All visual values are resolved from Figma design tokens via
24
- * `getVariableByName`. Slots cascade the active `modes` to their children
25
- * through `cloneChildrenWithModes`.
28
+ * `getVariableByName` (Figma node 4453:2348 "Page Hero"). Text colors react
29
+ * to the `Page type` (`MainPage | SubPage | JioPlus`) and `Color Mode`
30
+ * (`Light | Dark`) collections; type scale reacts to `PageHero Size`
31
+ * (`M | S`); the media box reacts to `Video / Output` (`L | M | S`). Slots
32
+ * cascade the active `modes` to their children through
33
+ * `cloneChildrenWithModes`.
26
34
  *
27
35
  * @component
28
36
  * @example
@@ -33,21 +41,19 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
33
41
  * supportingText="₹999/year · ₹0 until 2027"
34
42
  * buttonLabel="Renew for free"
35
43
  * onButtonPress={() => navigate('Upgrade')}
36
- * media={
37
- * <Image
38
- * imageSource={require('./assets/upgrade.png')}
39
- * width={117}
40
- * height={117}
41
- * />
42
- * }
44
+ * modes={{ 'Page type': 'JioPlus' }}
45
+ * media={<LottiePlayer source={animation} />}
43
46
  * />
44
47
  * ```
45
48
  */
46
49
  function PageHero({
47
50
  eyebrow = 'Upgrade to JioFinance+',
51
+ showEyebrow = true,
48
52
  headline = 'Resume earning cashback, extra points, and 1% gold',
49
53
  supportingText = '₹999/year · ₹0 until 2027',
50
54
  showSupportingText = true,
55
+ body,
56
+ showBody = true,
51
57
  buttonLabel = 'Renew for free',
52
58
  onButtonPress,
53
59
  showButton = true,
@@ -65,34 +71,49 @@ function PageHero({
65
71
  ...propModes
66
72
  }), [globalModes, propModes]);
67
73
  const gap = Number((0, _figmaVariablesResolver.getVariableByName)('PageHero/gap', modes));
68
- const paddingHorizontal = Number((0, _figmaVariablesResolver.getVariableByName)('PageHero/padding/horizontal', modes));
69
74
  const textWrapGap = Number((0, _figmaVariablesResolver.getVariableByName)('PageHero/textWrap/gap', modes));
70
75
 
71
- // Media slot box — matches the 117×117 frame in Figma (node 4540:7845).
72
- // Tokens fall back to 117 when not defined in the variables collection,
73
- // so the layout stays stable on consumers that haven't tokenized this yet.
74
- const mediaWidth = Number((0, _figmaVariablesResolver.getVariableByName)('media/width', modes));
75
- const mediaHeight = Number((0, _figmaVariablesResolver.getVariableByName)('media/height', modes));
76
- const eyebrowColor = (0, _figmaVariablesResolver.getVariableByName)('PageHero/eyebrow/color', modes);
77
- const eyebrowFontFamily = (0, _figmaVariablesResolver.getVariableByName)('PageHero/eyebrow/fontFamily', modes);
78
- const eyebrowFontSize = Number((0, _figmaVariablesResolver.getVariableByName)('PageHero/eyebrow/fontSize', modes));
79
- const eyebrowFontWeight = (0, _figmaVariablesResolver.getVariableByName)('PageHero/eyebrow/fontWeight', modes);
80
- const eyebrowLineHeight = Number((0, _figmaVariablesResolver.getVariableByName)('PageHero/eyebrow/lineHeight', modes));
81
- const headlineColor = (0, _figmaVariablesResolver.getVariableByName)('PageHero/headline/color', modes);
82
- const headlineFontFamily = (0, _figmaVariablesResolver.getVariableByName)('PageHero/headline/fontFamily', modes);
83
- const headlineFontSize = Number((0, _figmaVariablesResolver.getVariableByName)('PageHero/headline/fontSize', modes));
84
- const headlineFontWeight = (0, _figmaVariablesResolver.getVariableByName)('PageHero/headline/fontWeight', modes);
85
- const headlineLineHeight = Number((0, _figmaVariablesResolver.getVariableByName)('PageHero/headline/lineHeight', modes));
86
-
87
- // Only `lineHeight` is tokenized for the supporting text in the Figma source.
88
- // Color, font size and weight are inline literals in the design (12px medium
89
- // white) — we mirror that here so the visual stays faithful when no token
90
- // exists.
91
- const supportingTextLineHeight = Number((0, _figmaVariablesResolver.getVariableByName)('PageHero/supportingText/lineHeight', modes));
76
+ // Media slot box — Figma frame 4540:7845 ("Video"), sized by the
77
+ // `Video / Output` collection (L=117, M=70, S=20). Falls back to 117 when
78
+ // the collection is absent so the slot never collapses to 0×0.
79
+ const mediaWidth = Number((0, _figmaVariablesResolver.getVariableByName)('video/width', modes)) || MEDIA_FALLBACK;
80
+ const mediaHeight = Number((0, _figmaVariablesResolver.getVariableByName)('video/height', modes)) || MEDIA_FALLBACK;
81
+ const eyebrowStyle = (0, _react.useMemo)(() => ({
82
+ color: (0, _figmaVariablesResolver.getVariableByName)('PageHero/eyebrow/color', modes),
83
+ fontFamily: (0, _figmaVariablesResolver.getVariableByName)('PageHero/eyebrow/fontFamily', modes),
84
+ fontSize: Number((0, _figmaVariablesResolver.getVariableByName)('PageHero/eyebrow/fontSize', modes)),
85
+ fontWeight: String((0, _figmaVariablesResolver.getVariableByName)('PageHero/eyebrow/fontWeight', modes)),
86
+ lineHeight: Number((0, _figmaVariablesResolver.getVariableByName)('PageHero/eyebrow/lineHeight', modes)),
87
+ textAlign: 'center'
88
+ }), [modes]);
89
+ const headlineStyle = (0, _react.useMemo)(() => ({
90
+ color: (0, _figmaVariablesResolver.getVariableByName)('PageHero/headline/color', modes),
91
+ fontFamily: (0, _figmaVariablesResolver.getVariableByName)('PageHero/headline/fontFamily', modes),
92
+ fontSize: Number((0, _figmaVariablesResolver.getVariableByName)('PageHero/headline/fontSize', modes)),
93
+ fontWeight: String((0, _figmaVariablesResolver.getVariableByName)('PageHero/headline/fontWeight', modes)),
94
+ lineHeight: Number((0, _figmaVariablesResolver.getVariableByName)('PageHero/headline/lineHeight', modes)),
95
+ textAlign: 'center',
96
+ width: '100%'
97
+ }), [modes]);
98
+ const supportingTextStyle = (0, _react.useMemo)(() => ({
99
+ color: (0, _figmaVariablesResolver.getVariableByName)('PageHero/supportingText/color', modes),
100
+ fontFamily: (0, _figmaVariablesResolver.getVariableByName)('PageHero/supportingText/fontFamily', modes),
101
+ fontSize: Number((0, _figmaVariablesResolver.getVariableByName)('PageHero/supportingText/fontSize', modes)),
102
+ fontWeight: String((0, _figmaVariablesResolver.getVariableByName)('PageHero/supportingText/fontWeight', modes)),
103
+ lineHeight: Number((0, _figmaVariablesResolver.getVariableByName)('PageHero/supportingText/lineHeight', modes)),
104
+ textAlign: 'center'
105
+ }), [modes]);
106
+ const bodyStyle = (0, _react.useMemo)(() => ({
107
+ color: (0, _figmaVariablesResolver.getVariableByName)('PageHero/body/color', modes),
108
+ fontFamily: (0, _figmaVariablesResolver.getVariableByName)('PageHero/body/fontFamily', modes),
109
+ fontSize: Number((0, _figmaVariablesResolver.getVariableByName)('PageHero/body/fontSize', modes)),
110
+ fontWeight: String((0, _figmaVariablesResolver.getVariableByName)('PageHero/body/fontWeight', modes)),
111
+ lineHeight: Number((0, _figmaVariablesResolver.getVariableByName)('PageHero/body/lineHeight', modes)),
112
+ textAlign: 'center'
113
+ }), [modes]);
92
114
  const containerStyle = {
93
115
  flexDirection: 'column',
94
116
  alignItems: 'center',
95
- paddingHorizontal,
96
117
  gap,
97
118
  width: '100%'
98
119
  };
@@ -102,34 +123,6 @@ function PageHero({
102
123
  gap: textWrapGap,
103
124
  width: '100%'
104
125
  };
105
- const eyebrowStyle = {
106
- color: eyebrowColor,
107
- fontFamily: eyebrowFontFamily,
108
- fontSize: eyebrowFontSize,
109
- fontWeight: String(eyebrowFontWeight),
110
- lineHeight: eyebrowLineHeight,
111
- textAlign: 'center'
112
- };
113
- const headlineStyle = {
114
- color: headlineColor,
115
- fontFamily: headlineFontFamily,
116
- fontSize: headlineFontSize,
117
- fontWeight: String(headlineFontWeight),
118
- lineHeight: headlineLineHeight,
119
- textAlign: 'center',
120
- width: '100%'
121
- };
122
- const supportingTextStyle = {
123
- color: '#ffffff',
124
- fontFamily: 'System',
125
- fontSize: 12,
126
- fontWeight: '500',
127
- lineHeight: supportingTextLineHeight,
128
- textAlign: 'center'
129
- };
130
- const buttonWrapStyle = {
131
- width: '100%'
132
- };
133
126
  const buttonContent = (0, _react.useMemo)(() => {
134
127
  if (buttonSlot !== undefined && buttonSlot !== null) {
135
128
  return (0, _reactUtils.cloneChildrenWithModes)(buttonSlot, modes);
@@ -141,20 +134,16 @@ function PageHero({
141
134
  label: buttonLabel,
142
135
  onPress: onButtonPress,
143
136
  modes: modes,
144
- style: buttonWrapStyle
137
+ style: FULL_WIDTH
145
138
  });
146
- // buttonWrapStyle is a literal object created above; it is intentionally
147
- // omitted from deps because its identity changes on every render but its
148
- // shape never does.
149
- // eslint-disable-next-line react-hooks/exhaustive-deps
150
139
  }, [buttonSlot, showButton, buttonLabel, onButtonPress, modes]);
151
140
 
152
141
  // Sized container for the media slot. Always rendered when `media` is
153
- // provided, so the slot has a predictable box (matches Figma frame
154
- // 4540:7845 — 117×117 by default) even if the inner element omits its
155
- // own width/height. `overflow: 'hidden'` mirrors the Figma frame's
156
- // `clipsContent` so a slightly oversized illustration doesn't break
157
- // the centered layout.
142
+ // provided, so the slot has a predictable box (Figma frame 4540:7845 —
143
+ // 117×117 at `Video / Output = L`) even if the inner element omits its own
144
+ // width/height. `overflow: 'hidden'` mirrors the Figma frame's
145
+ // `clipsContent` so a slightly oversized illustration doesn't break the
146
+ // centered layout.
158
147
  const mediaContent = (0, _react.useMemo)(() => {
159
148
  if (media === undefined || media === null) return null;
160
149
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
@@ -168,22 +157,30 @@ function PageHero({
168
157
  children: (0, _reactUtils.cloneChildrenWithModes)(media, modes)
169
158
  });
170
159
  }, [media, mediaWidth, mediaHeight, modes]);
160
+ const hasEyebrow = showEyebrow && !!eyebrow;
161
+ const hasHeadline = !!headline;
171
162
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
172
163
  style: [containerStyle, style],
173
164
  testID: testID,
174
- children: [mediaContent, /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
165
+ children: [mediaContent, hasEyebrow || hasHeadline ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
175
166
  style: textWrapStyle,
176
- children: [eyebrow ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
167
+ children: [hasEyebrow ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
177
168
  style: eyebrowStyle,
178
169
  children: eyebrow
179
- }) : null, headline ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
170
+ }) : null, hasHeadline ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
180
171
  style: headlineStyle,
181
172
  children: headline
182
173
  }) : null]
183
- }), showSupportingText && supportingText ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
174
+ }) : null, showSupportingText && supportingText ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
184
175
  style: supportingTextStyle,
185
176
  children: supportingText
177
+ }) : null, showBody && body ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
178
+ style: bodyStyle,
179
+ children: body
186
180
  }) : null, buttonContent]
187
181
  });
188
182
  }
183
+ const FULL_WIDTH = {
184
+ width: '100%'
185
+ };
189
186
  var _default = exports.default = PageHero;