jfs-components 0.0.73 → 0.0.77

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 (134) hide show
  1. package/CHANGELOG.md +115 -6
  2. package/lib/commonjs/components/AccountCard/AccountCard.js +247 -0
  3. package/lib/commonjs/components/ActionFooter/ActionFooter.js +147 -82
  4. package/lib/commonjs/components/AppBar/AppBar.js +17 -11
  5. package/lib/commonjs/components/Avatar/Avatar.js +20 -0
  6. package/lib/commonjs/components/Badge/Badge.js +23 -0
  7. package/lib/commonjs/components/Button/Button.js +37 -0
  8. package/lib/commonjs/components/CardBankAccount/CardBankAccount.js +18 -2
  9. package/lib/commonjs/components/CheckboxItem/CheckboxItem.js +40 -25
  10. package/lib/commonjs/components/Dropdown/Dropdown.js +214 -0
  11. package/lib/commonjs/components/DropdownInput/DropdownInput.js +542 -0
  12. package/lib/commonjs/components/FormField/FormField.js +328 -178
  13. package/lib/commonjs/components/IconButton/IconButton.js +20 -0
  14. package/lib/commonjs/components/Image/Image.js +26 -1
  15. package/lib/commonjs/components/LottieIntroBlock/LottieIntroBlock.js +150 -0
  16. package/lib/commonjs/components/LottiePlayer/LottiePlayer.js +116 -0
  17. package/lib/commonjs/components/LottiePlayer/LottiePlayer.web.js +82 -0
  18. package/lib/commonjs/components/LottiePlayer/loadNativeLottieView.js +74 -0
  19. package/lib/commonjs/components/LottiePlayer/loadWebLottieView.js +50 -0
  20. package/lib/commonjs/components/PageHero/PageHero.js +189 -0
  21. package/lib/commonjs/components/PoweredByLabel/PoweredByLabel.js +135 -0
  22. package/lib/commonjs/components/PoweredByLabel/finvu.png +0 -0
  23. package/lib/commonjs/components/RechargeCard/RechargeCard.js +32 -17
  24. package/lib/commonjs/components/Text/Text.js +40 -3
  25. package/lib/commonjs/components/Tooltip/Tooltip.js +34 -27
  26. package/lib/commonjs/components/index.js +67 -0
  27. package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
  28. package/lib/commonjs/icons/Icon.js +16 -0
  29. package/lib/commonjs/icons/registry.js +1 -1
  30. package/lib/commonjs/index.js +12 -0
  31. package/lib/commonjs/skeleton/Skeleton.js +234 -0
  32. package/lib/commonjs/skeleton/SkeletonGroup.js +140 -0
  33. package/lib/commonjs/skeleton/index.js +58 -0
  34. package/lib/commonjs/skeleton/shimmer-tokens.js +189 -0
  35. package/lib/commonjs/skeleton/useReducedMotion.js +64 -0
  36. package/lib/module/components/AccountCard/AccountCard.js +241 -0
  37. package/lib/module/components/ActionFooter/ActionFooter.js +146 -82
  38. package/lib/module/components/AppBar/AppBar.js +17 -11
  39. package/lib/module/components/Avatar/Avatar.js +19 -0
  40. package/lib/module/components/Badge/Badge.js +23 -0
  41. package/lib/module/components/Button/Button.js +37 -0
  42. package/lib/module/components/CardBankAccount/CardBankAccount.js +17 -2
  43. package/lib/module/components/CheckboxItem/CheckboxItem.js +41 -26
  44. package/lib/module/components/Dropdown/Dropdown.js +206 -0
  45. package/lib/module/components/DropdownInput/DropdownInput.js +536 -0
  46. package/lib/module/components/FormField/FormField.js +330 -180
  47. package/lib/module/components/IconButton/IconButton.js +20 -0
  48. package/lib/module/components/Image/Image.js +25 -1
  49. package/lib/module/components/LottieIntroBlock/LottieIntroBlock.js +144 -0
  50. package/lib/module/components/LottiePlayer/LottiePlayer.js +111 -0
  51. package/lib/module/components/LottiePlayer/LottiePlayer.web.js +77 -0
  52. package/lib/module/components/LottiePlayer/loadNativeLottieView.js +69 -0
  53. package/lib/module/components/LottiePlayer/loadWebLottieView.js +45 -0
  54. package/lib/module/components/PageHero/PageHero.js +183 -0
  55. package/lib/module/components/PoweredByLabel/PoweredByLabel.js +130 -0
  56. package/lib/module/components/PoweredByLabel/finvu.png +0 -0
  57. package/lib/module/components/RechargeCard/RechargeCard.js +33 -17
  58. package/lib/module/components/Text/Text.js +40 -3
  59. package/lib/module/components/Tooltip/Tooltip.js +34 -27
  60. package/lib/module/components/index.js +8 -1
  61. package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
  62. package/lib/module/icons/Icon.js +16 -0
  63. package/lib/module/icons/registry.js +1 -1
  64. package/lib/module/index.js +2 -1
  65. package/lib/module/skeleton/Skeleton.js +229 -0
  66. package/lib/module/skeleton/SkeletonGroup.js +133 -0
  67. package/lib/module/skeleton/index.js +6 -0
  68. package/lib/module/skeleton/shimmer-tokens.js +181 -0
  69. package/lib/module/skeleton/useReducedMotion.js +61 -0
  70. package/lib/typescript/src/components/AccountCard/AccountCard.d.ts +81 -0
  71. package/lib/typescript/src/components/ActionFooter/ActionFooter.d.ts +26 -21
  72. package/lib/typescript/src/components/Avatar/Avatar.d.ts +7 -1
  73. package/lib/typescript/src/components/Badge/Badge.d.ts +7 -1
  74. package/lib/typescript/src/components/Button/Button.d.ts +8 -1
  75. package/lib/typescript/src/components/CardBankAccount/CardBankAccount.d.ts +9 -2
  76. package/lib/typescript/src/components/CheckboxItem/CheckboxItem.d.ts +18 -2
  77. package/lib/typescript/src/components/Dropdown/Dropdown.d.ts +62 -0
  78. package/lib/typescript/src/components/DropdownInput/DropdownInput.d.ts +107 -0
  79. package/lib/typescript/src/components/FormField/FormField.d.ts +76 -19
  80. package/lib/typescript/src/components/IconButton/IconButton.d.ts +7 -1
  81. package/lib/typescript/src/components/Image/Image.d.ts +8 -1
  82. package/lib/typescript/src/components/LottieIntroBlock/LottieIntroBlock.d.ts +58 -0
  83. package/lib/typescript/src/components/LottiePlayer/LottiePlayer.d.ts +85 -0
  84. package/lib/typescript/src/components/LottiePlayer/LottiePlayer.web.d.ts +28 -0
  85. package/lib/typescript/src/components/LottiePlayer/loadNativeLottieView.d.ts +11 -0
  86. package/lib/typescript/src/components/LottiePlayer/loadWebLottieView.d.ts +11 -0
  87. package/lib/typescript/src/components/PageHero/PageHero.d.ts +79 -0
  88. package/lib/typescript/src/components/PoweredByLabel/PoweredByLabel.d.ts +70 -0
  89. package/lib/typescript/src/components/Text/Text.d.ts +31 -2
  90. package/lib/typescript/src/components/Tooltip/Tooltip.d.ts +13 -2
  91. package/lib/typescript/src/components/index.d.ts +8 -1
  92. package/lib/typescript/src/icons/Icon.d.ts +7 -1
  93. package/lib/typescript/src/icons/registry.d.ts +1 -1
  94. package/lib/typescript/src/index.d.ts +1 -0
  95. package/lib/typescript/src/skeleton/Skeleton.d.ts +60 -0
  96. package/lib/typescript/src/skeleton/SkeletonGroup.d.ts +78 -0
  97. package/lib/typescript/src/skeleton/index.d.ts +5 -0
  98. package/lib/typescript/src/skeleton/shimmer-tokens.d.ts +160 -0
  99. package/lib/typescript/src/skeleton/useReducedMotion.d.ts +15 -0
  100. package/package.json +11 -3
  101. package/src/components/AccountCard/AccountCard.tsx +376 -0
  102. package/src/components/ActionFooter/ActionFooter.tsx +152 -86
  103. package/src/components/AppBar/AppBar.tsx +25 -14
  104. package/src/components/Avatar/Avatar.tsx +26 -0
  105. package/src/components/Badge/Badge.tsx +27 -0
  106. package/src/components/Button/Button.tsx +40 -0
  107. package/src/components/CardBankAccount/CardBankAccount.tsx +29 -3
  108. package/src/components/CheckboxItem/CheckboxItem.tsx +65 -30
  109. package/src/components/Dropdown/Dropdown.tsx +331 -0
  110. package/src/components/DropdownInput/DropdownInput.tsx +819 -0
  111. package/src/components/FormField/FormField.tsx +542 -215
  112. package/src/components/IconButton/IconButton.tsx +27 -0
  113. package/src/components/Image/Image.tsx +25 -0
  114. package/src/components/LottieIntroBlock/LottieIntroBlock.tsx +202 -0
  115. package/src/components/LottiePlayer/LottiePlayer.tsx +145 -0
  116. package/src/components/LottiePlayer/LottiePlayer.web.tsx +94 -0
  117. package/src/components/LottiePlayer/loadNativeLottieView.tsx +87 -0
  118. package/src/components/LottiePlayer/loadWebLottieView.tsx +64 -0
  119. package/src/components/PageHero/PageHero.tsx +257 -0
  120. package/src/components/PoweredByLabel/PoweredByLabel.tsx +221 -0
  121. package/src/components/PoweredByLabel/finvu.png +0 -0
  122. package/src/components/RechargeCard/RechargeCard.tsx +32 -24
  123. package/src/components/Text/Text.tsx +78 -3
  124. package/src/components/Tooltip/Tooltip.tsx +50 -25
  125. package/src/components/index.ts +16 -1
  126. package/src/design-tokens/Coin Variables-variables-full.json +1 -1
  127. package/src/icons/Icon.tsx +17 -0
  128. package/src/icons/registry.ts +1 -1
  129. package/src/index.ts +1 -0
  130. package/src/skeleton/Skeleton.tsx +298 -0
  131. package/src/skeleton/SkeletonGroup.tsx +193 -0
  132. package/src/skeleton/index.ts +10 -0
  133. package/src/skeleton/shimmer-tokens.ts +221 -0
  134. package/src/skeleton/useReducedMotion.ts +72 -0
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+
3
+ import React, { useMemo } from 'react';
4
+ import { View, Text } from 'react-native';
5
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
6
+ import { useTokens } from '../../design-tokens/JFSThemeProvider';
7
+ import Button from '../Button/Button';
8
+ import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils';
9
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
+ const DEFAULT_MEDIA_SIZE = 117;
11
+ /**
12
+ * LottieIntroBlock displays a centered onboarding/intro block composed of a
13
+ * media slot (typically a Lottie animation or illustration) above a title,
14
+ * an optional supportive paragraph, and an optional action button.
15
+ *
16
+ * All visual values are resolved from Figma design tokens via
17
+ * `getVariableByName`. Slots cascade the active `modes` to their children
18
+ * through `cloneChildrenWithModes`.
19
+ *
20
+ * @component
21
+ * @example
22
+ * ```tsx
23
+ * <LottieIntroBlock
24
+ * title="Let's get to know how your financial health is doing"
25
+ * supportText="From assets to taxes, stay on top of everything in one simple view."
26
+ * buttonLabel="Get started"
27
+ * onButtonPress={() => navigate('NextScreen')}
28
+ * media={<MyLottiePlayer source={animationSource} />}
29
+ * />
30
+ * ```
31
+ */
32
+ function LottieIntroBlock({
33
+ title = "Let's get to know how your financial health is doing",
34
+ showSupportText = true,
35
+ supportText = 'From assets to taxes, stay on top of everything in one simple view.',
36
+ showButton = true,
37
+ buttonLabel = 'Button',
38
+ onButtonPress,
39
+ media,
40
+ buttonSlot,
41
+ modes: propModes = EMPTY_MODES,
42
+ style,
43
+ testID
44
+ }) {
45
+ const {
46
+ modes: globalModes
47
+ } = useTokens();
48
+ const modes = useMemo(() => ({
49
+ ...globalModes,
50
+ ...propModes
51
+ }), [globalModes, propModes]);
52
+
53
+ // Container
54
+ const gap = Number(getVariableByName('lottieIntroBlock/gap', modes)) || 36;
55
+ const paddingHorizontal = Number(getVariableByName('lottieIntroBlock/padding/horizontal', modes)) || 0;
56
+ const paddingVertical = Number(getVariableByName('lottieIntroBlock/padding/vertical', modes)) || 16;
57
+
58
+ // Text wrap
59
+ const textWrapGap = Number(getVariableByName('lottieIntroBlock/textWrap/gap', modes)) || 16;
60
+
61
+ // Title
62
+ const titleColor = getVariableByName('lottieIntroBlock/title/foreground', modes) || '#0d0d0f';
63
+ const titleFontSize = Number(getVariableByName('lottieIntroBlock/title/fontSize', modes)) || 23;
64
+ const titleFontFamily = getVariableByName('lottieIntroBlock/title/fontFamily', modes) || 'System';
65
+ const titleLineHeight = Number(getVariableByName('lottieIntroBlock/title/lineHeight', modes)) || 23;
66
+ const titleFontWeight = getVariableByName('lottieIntroBlock/title/fontWeight', modes) || 900;
67
+
68
+ // Support text
69
+ const supportColor = getVariableByName('lottieIntroBlock/supportText/foreground', modes) || '#0d0d0f';
70
+ const supportFontSize = Number(getVariableByName('lottieIntroBlock/supportText/fontSize', modes)) || 14;
71
+ const supportFontFamily = getVariableByName('lottieIntroBlock/supportText/fontFamily', modes) || 'System';
72
+ const supportLineHeight = Number(getVariableByName('lottieIntroBlock/supportText/lineHeight', modes)) || 18;
73
+ const supportFontWeight = getVariableByName('lottieIntroBlock/supportText/fontWeight', modes) || 400;
74
+ const containerStyle = {
75
+ flexDirection: 'column',
76
+ alignItems: 'center',
77
+ paddingHorizontal,
78
+ paddingVertical,
79
+ gap
80
+ };
81
+ const textWrapStyle = {
82
+ flexDirection: 'column',
83
+ alignItems: 'center',
84
+ gap: textWrapGap,
85
+ width: '100%'
86
+ };
87
+ const titleStyle = {
88
+ color: titleColor,
89
+ fontSize: titleFontSize,
90
+ fontFamily: titleFontFamily,
91
+ lineHeight: titleLineHeight,
92
+ fontWeight: String(titleFontWeight),
93
+ textAlign: 'center'
94
+ };
95
+ const supportTextStyle = {
96
+ color: supportColor,
97
+ fontSize: supportFontSize,
98
+ fontFamily: supportFontFamily,
99
+ lineHeight: supportLineHeight,
100
+ fontWeight: String(supportFontWeight),
101
+ textAlign: 'center'
102
+ };
103
+ const mediaContent = useMemo(() => {
104
+ if (media === undefined || media === null) {
105
+ return /*#__PURE__*/_jsx(View, {
106
+ style: {
107
+ width: DEFAULT_MEDIA_SIZE,
108
+ height: DEFAULT_MEDIA_SIZE
109
+ },
110
+ accessibilityElementsHidden: true,
111
+ importantForAccessibility: "no-hide-descendants"
112
+ });
113
+ }
114
+ return cloneChildrenWithModes(media, modes);
115
+ }, [media, modes]);
116
+ const buttonContent = useMemo(() => {
117
+ if (buttonSlot !== undefined && buttonSlot !== null) {
118
+ return cloneChildrenWithModes(buttonSlot, modes);
119
+ }
120
+ if (!showButton) {
121
+ return null;
122
+ }
123
+ return /*#__PURE__*/_jsx(Button, {
124
+ label: buttonLabel,
125
+ onPress: onButtonPress,
126
+ modes: modes
127
+ });
128
+ }, [buttonSlot, showButton, buttonLabel, onButtonPress, modes]);
129
+ return /*#__PURE__*/_jsxs(View, {
130
+ style: [containerStyle, style],
131
+ testID: testID,
132
+ children: [mediaContent, /*#__PURE__*/_jsxs(View, {
133
+ style: textWrapStyle,
134
+ children: [/*#__PURE__*/_jsx(Text, {
135
+ style: titleStyle,
136
+ children: title
137
+ }), showSupportText && supportText ? /*#__PURE__*/_jsx(Text, {
138
+ style: supportTextStyle,
139
+ children: supportText
140
+ }) : null, buttonContent]
141
+ })]
142
+ });
143
+ }
144
+ export default LottieIntroBlock;
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+
3
+ import React, { useMemo } from 'react';
4
+ import { View } from 'react-native';
5
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
6
+ import { useTokens } from '../../design-tokens/JFSThemeProvider';
7
+ import { EMPTY_MODES } from '../../utils/react-utils';
8
+ import { getNativeLottieView } from './loadNativeLottieView';
9
+
10
+ /**
11
+ * A parsed Lottie animation. The JSON object you get from
12
+ * `require('./animation.json')` or `fetch().then(r => r.json())`. We keep the
13
+ * type intentionally loose because both `lottie-react-native` and `lottie-react`
14
+ * accept slightly different shapes — `LottiePlayer` narrows back to the
15
+ * platform-specific type internally.
16
+ */
17
+ import { jsx as _jsx } from "react/jsx-runtime";
18
+ const DEFAULT_SIZE = 117;
19
+ function resolveSize(size, modes) {
20
+ if (typeof size === 'number') return {
21
+ width: size,
22
+ height: size
23
+ };
24
+ if (size && typeof size === 'object') return size;
25
+ const width = Number(getVariableByName('media/width', modes)) || DEFAULT_SIZE;
26
+ const height = Number(getVariableByName('media/height', modes)) || DEFAULT_SIZE;
27
+ return {
28
+ width,
29
+ height
30
+ };
31
+ }
32
+
33
+ /**
34
+ * Renders a Lottie animation using the consumer's installed
35
+ * `lottie-react-native` (native) or `lottie-react` (web) — both are declared
36
+ * as **optional peer dependencies** of `jfs-components`, so installing the
37
+ * library does not pull them in. Add the relevant package to your app only
38
+ * if you actually use `LottiePlayer`:
39
+ *
40
+ * ```sh
41
+ * # React Native (iOS / Android)
42
+ * npm install lottie-react-native
43
+ * cd ios && pod install
44
+ *
45
+ * # Web (or react-native-web)
46
+ * npm install lottie-react
47
+ * ```
48
+ *
49
+ * The web build (`LottiePlayer.web.tsx`) is picked automatically by Metro /
50
+ * webpack via platform extensions — same pattern as `MediaCard/GlassFill`.
51
+ *
52
+ * Token-driven sizing: when `size` is omitted, `LottiePlayer` reads
53
+ * `media/width` and `media/height` from the Figma variables resolver, so the
54
+ * animation matches the surrounding component's `Media / Output` mode
55
+ * automatically. This is the same sizing contract `PageHero` and
56
+ * `LottieIntroBlock` use for their `media` slots.
57
+ *
58
+ * @component
59
+ * @example
60
+ * ```tsx
61
+ * import animation from './assets/loader.json';
62
+ *
63
+ * <LottiePlayer source={animation} /> // 117 × 117 (default)
64
+ * <LottiePlayer source={animation} size={70} /> // 70 × 70
65
+ * <LottiePlayer source={animation} modes={{ 'Media / Output': 'S' }} /> // 20 × 20
66
+ * <PageHero media={<LottiePlayer source={animation} />} />
67
+ * ```
68
+ */
69
+ function LottiePlayer({
70
+ source,
71
+ size,
72
+ autoPlay = true,
73
+ loop = true,
74
+ modes: propModes = EMPTY_MODES,
75
+ style,
76
+ accessibilityLabel,
77
+ testID
78
+ }) {
79
+ const {
80
+ modes: globalModes
81
+ } = useTokens();
82
+ const modes = useMemo(() => globalModes === EMPTY_MODES && propModes === EMPTY_MODES ? EMPTY_MODES : {
83
+ ...globalModes,
84
+ ...propModes
85
+ }, [globalModes, propModes]);
86
+ const {
87
+ width,
88
+ height
89
+ } = useMemo(() => resolveSize(size, modes), [size, modes]);
90
+ const NativeLottieView = useMemo(() => getNativeLottieView(), []);
91
+ return /*#__PURE__*/_jsx(View, {
92
+ style: [{
93
+ width,
94
+ height
95
+ }, style],
96
+ testID: testID,
97
+ accessibilityLabel: accessibilityLabel,
98
+ accessibilityElementsHidden: accessibilityLabel ? undefined : true,
99
+ importantForAccessibility: accessibilityLabel ? 'auto' : 'no',
100
+ children: /*#__PURE__*/_jsx(NativeLottieView, {
101
+ source: source,
102
+ autoPlay: autoPlay,
103
+ loop: loop,
104
+ style: {
105
+ width: '100%',
106
+ height: '100%'
107
+ }
108
+ })
109
+ });
110
+ }
111
+ export default /*#__PURE__*/React.memo(LottiePlayer);
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+
3
+ import React, { useMemo } from 'react';
4
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
5
+ import { useTokens } from '../../design-tokens/JFSThemeProvider';
6
+ import { EMPTY_MODES } from '../../utils/react-utils';
7
+ import { getWebLottieView } from './loadWebLottieView';
8
+ import { jsx as _jsx } from "react/jsx-runtime";
9
+ const DEFAULT_SIZE = 117;
10
+ function resolveSize(size, modes) {
11
+ if (typeof size === 'number') return {
12
+ width: size,
13
+ height: size
14
+ };
15
+ if (size && typeof size === 'object') return size;
16
+ const width = Number(getVariableByName('media/width', modes)) || DEFAULT_SIZE;
17
+ const height = Number(getVariableByName('media/height', modes)) || DEFAULT_SIZE;
18
+ return {
19
+ width,
20
+ height
21
+ };
22
+ }
23
+
24
+ /**
25
+ * Web build of `LottiePlayer` — picked automatically by webpack /
26
+ * Metro-for-web via the `.web.tsx` platform extension. Uses `lottie-react`
27
+ * (which wraps `lottie-web`) and renders a plain DOM container.
28
+ *
29
+ * Public API mirrors `LottiePlayer.tsx` (native). See that file for the
30
+ * documented prop reference and usage patterns.
31
+ */
32
+ function LottiePlayer({
33
+ source,
34
+ size,
35
+ autoPlay = true,
36
+ loop = true,
37
+ modes: propModes = EMPTY_MODES,
38
+ style,
39
+ accessibilityLabel,
40
+ testID
41
+ }) {
42
+ const {
43
+ modes: globalModes
44
+ } = useTokens();
45
+ const modes = useMemo(() => globalModes === EMPTY_MODES && propModes === EMPTY_MODES ? EMPTY_MODES : {
46
+ ...globalModes,
47
+ ...propModes
48
+ }, [globalModes, propModes]);
49
+ const {
50
+ width,
51
+ height
52
+ } = useMemo(() => resolveSize(size, modes), [size, modes]);
53
+ const WebLottieView = useMemo(() => getWebLottieView(), []);
54
+ return /*#__PURE__*/_jsx("div", {
55
+ style: {
56
+ width,
57
+ height,
58
+ display: 'flex',
59
+ alignItems: 'center',
60
+ justifyContent: 'center',
61
+ ...style
62
+ },
63
+ "data-testid": testID,
64
+ "aria-label": accessibilityLabel,
65
+ "aria-hidden": accessibilityLabel ? undefined : true,
66
+ children: /*#__PURE__*/_jsx(WebLottieView, {
67
+ animationData: source,
68
+ autoplay: autoPlay,
69
+ loop: loop,
70
+ style: {
71
+ width: '100%',
72
+ height: '100%'
73
+ }
74
+ })
75
+ });
76
+ }
77
+ export default /*#__PURE__*/React.memo(LottiePlayer);
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+
3
+ import React from 'react';
4
+ import { Text, View } from 'react-native';
5
+
6
+ /** Props we forward to the underlying native Lottie view. */
7
+ import { jsx as _jsx } from "react/jsx-runtime";
8
+ const INSTALL_HINT = 'LottiePlayer requires lottie-react-native in your app.\n' + ' npm install lottie-react-native\n' + ' cd ios && pod install';
9
+
10
+ /**
11
+ * Metro resolves `require('lottie-react-native')` at bundle time even inside
12
+ * try/catch, which breaks apps that import `jfs-components` without having
13
+ * the optional peer installed. Splitting the module id into a runtime string
14
+ * keeps Metro from statically linking it — the native module is loaded only
15
+ * when present in the consumer's node_modules.
16
+ */
17
+ function resolveNativeLottieModuleName() {
18
+ return ['lottie', '-react', '-native'].join('');
19
+ }
20
+ function LottieUnavailableView({
21
+ style
22
+ }) {
23
+ if (__DEV__) {
24
+ return /*#__PURE__*/_jsx(View, {
25
+ style: [style, {
26
+ alignItems: 'center',
27
+ justifyContent: 'center',
28
+ backgroundColor: 'rgba(255, 196, 0, 0.12)',
29
+ borderWidth: 1,
30
+ borderColor: 'rgba(255, 196, 0, 0.45)',
31
+ borderRadius: 8,
32
+ padding: 8
33
+ }],
34
+ children: /*#__PURE__*/_jsx(Text, {
35
+ style: {
36
+ color: '#8a6d00',
37
+ fontSize: 11,
38
+ textAlign: 'center',
39
+ lineHeight: 15
40
+ },
41
+ children: INSTALL_HINT
42
+ })
43
+ });
44
+ }
45
+ return /*#__PURE__*/_jsx(View, {
46
+ style: style
47
+ });
48
+ }
49
+ function LottieUnavailable(props) {
50
+ React.useEffect(() => {
51
+ if (__DEV__) {
52
+ console.warn(`[jfs-components/LottiePlayer] ${INSTALL_HINT}`);
53
+ }
54
+ }, []);
55
+ return /*#__PURE__*/_jsx(LottieUnavailableView, {
56
+ style: props.style
57
+ });
58
+ }
59
+ let cachedView;
60
+ export function getNativeLottieView() {
61
+ if (cachedView !== undefined) return cachedView;
62
+ try {
63
+ const mod = require(resolveNativeLottieModuleName());
64
+ cachedView = mod.default ?? LottieUnavailable;
65
+ } catch {
66
+ cachedView = LottieUnavailable;
67
+ }
68
+ return cachedView;
69
+ }
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+
3
+ import React from 'react';
4
+
5
+ /** Props we forward to the underlying web Lottie view. */
6
+ import { jsx as _jsx } from "react/jsx-runtime";
7
+ const INSTALL_HINT = 'LottiePlayer requires lottie-react in your app.\n' + ' npm install lottie-react';
8
+ function resolveWebLottieModuleName() {
9
+ return ['lottie', '-react'].join('');
10
+ }
11
+ function LottieUnavailable(props) {
12
+ React.useEffect(() => {
13
+ if (typeof __DEV__ !== 'undefined' && __DEV__) {
14
+ console.warn(`[jfs-components/LottiePlayer] ${INSTALL_HINT}`);
15
+ }
16
+ }, []);
17
+ return /*#__PURE__*/_jsx("div", {
18
+ style: {
19
+ ...props.style,
20
+ display: 'flex',
21
+ alignItems: 'center',
22
+ justifyContent: 'center',
23
+ backgroundColor: 'rgba(255, 196, 0, 0.12)',
24
+ border: '1px solid rgba(255, 196, 0, 0.45)',
25
+ borderRadius: 8,
26
+ padding: 8,
27
+ color: '#8a6d00',
28
+ fontSize: 11,
29
+ textAlign: 'center',
30
+ lineHeight: '15px'
31
+ },
32
+ children: typeof __DEV__ !== 'undefined' && __DEV__ ? INSTALL_HINT : null
33
+ });
34
+ }
35
+ let cachedView;
36
+ export function getWebLottieView() {
37
+ if (cachedView !== undefined) return cachedView;
38
+ try {
39
+ const mod = require(resolveWebLottieModuleName());
40
+ cachedView = mod.default ?? LottieUnavailable;
41
+ } catch {
42
+ cachedView = LottieUnavailable;
43
+ }
44
+ return cachedView;
45
+ }
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+
3
+ import React, { useMemo } from 'react';
4
+ import { View, Text } from 'react-native';
5
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
6
+ import { useTokens } from '../../design-tokens/JFSThemeProvider';
7
+ import Button from '../Button/Button';
8
+ import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils';
9
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
+ /**
11
+ * PageHero displays a centered hero block typically used at the top of a page
12
+ * or feature screen. It contains an optional media slot (illustration / image
13
+ * / Lottie / SVG / video — consumer's choice), an eyebrow line, a large
14
+ * headline, an optional supporting line (e.g. price / timeline), and an
15
+ * optional action button.
16
+ *
17
+ * All visual values are resolved from Figma design tokens via
18
+ * `getVariableByName`. Slots cascade the active `modes` to their children
19
+ * through `cloneChildrenWithModes`.
20
+ *
21
+ * @component
22
+ * @example
23
+ * ```tsx
24
+ * <PageHero
25
+ * eyebrow="Upgrade to JioFinance+"
26
+ * headline="Resume earning cashback, extra points, and 1% gold"
27
+ * supportingText="₹999/year · ₹0 until 2027"
28
+ * buttonLabel="Renew for free"
29
+ * onButtonPress={() => navigate('Upgrade')}
30
+ * media={
31
+ * <Image
32
+ * imageSource={require('./assets/upgrade.png')}
33
+ * width={117}
34
+ * height={117}
35
+ * />
36
+ * }
37
+ * />
38
+ * ```
39
+ */
40
+ function PageHero({
41
+ eyebrow = 'Upgrade to JioFinance+',
42
+ headline = 'Resume earning cashback, extra points, and 1% gold',
43
+ supportingText = '₹999/year · ₹0 until 2027',
44
+ showSupportingText = true,
45
+ buttonLabel = 'Renew for free',
46
+ onButtonPress,
47
+ showButton = true,
48
+ buttonSlot,
49
+ media,
50
+ modes: propModes = EMPTY_MODES,
51
+ style,
52
+ testID
53
+ }) {
54
+ const {
55
+ modes: globalModes
56
+ } = useTokens();
57
+ const modes = useMemo(() => ({
58
+ ...globalModes,
59
+ ...propModes
60
+ }), [globalModes, propModes]);
61
+ const gap = Number(getVariableByName('PageHero/gap', modes)) || 16;
62
+ const paddingHorizontal = Number(getVariableByName('PageHero/padding/horizontal', modes)) || 0;
63
+ const textWrapGap = Number(getVariableByName('PageHero/textWrap/gap', modes)) || 8;
64
+
65
+ // Media slot box — matches the 117×117 frame in Figma (node 4540:7845).
66
+ // Tokens fall back to 117 when not defined in the variables collection,
67
+ // so the layout stays stable on consumers that haven't tokenized this yet.
68
+ const mediaWidth = Number(getVariableByName('media/width', modes)) || 117;
69
+ const mediaHeight = Number(getVariableByName('media/height', modes)) || 117;
70
+ const eyebrowColor = getVariableByName('PageHero/eyebrow/color', modes) || '#ffffff';
71
+ const eyebrowFontFamily = getVariableByName('PageHero/eyebrow/fontFamily', modes) || 'System';
72
+ const eyebrowFontSize = Number(getVariableByName('PageHero/eyebrow/fontSize', modes)) || 18;
73
+ const eyebrowFontWeight = getVariableByName('PageHero/eyebrow/fontWeight', modes) || 700;
74
+ const eyebrowLineHeight = Number(getVariableByName('PageHero/eyebrow/lineHeight', modes)) || 20;
75
+ const headlineColor = getVariableByName('PageHero/headline/color', modes) || '#ffffff';
76
+ const headlineFontFamily = getVariableByName('PageHero/headline/fontFamily', modes) || 'System';
77
+ const headlineFontSize = Number(getVariableByName('PageHero/headline/fontSize', modes)) || 29;
78
+ const headlineFontWeight = getVariableByName('PageHero/headline/fontWeight', modes) || 900;
79
+ const headlineLineHeight = Number(getVariableByName('PageHero/headline/lineHeight', modes)) || 29;
80
+
81
+ // Only `lineHeight` is tokenized for the supporting text in the Figma source.
82
+ // Color, font size and weight are inline literals in the design (12px medium
83
+ // white) — we mirror that here so the visual stays faithful when no token
84
+ // exists.
85
+ const supportingTextLineHeight = Number(getVariableByName('PageHero/supportingText/lineHeight', modes)) || 16;
86
+ const containerStyle = {
87
+ flexDirection: 'column',
88
+ alignItems: 'center',
89
+ paddingHorizontal,
90
+ gap,
91
+ width: '100%'
92
+ };
93
+ const textWrapStyle = {
94
+ flexDirection: 'column',
95
+ alignItems: 'center',
96
+ gap: textWrapGap,
97
+ width: '100%'
98
+ };
99
+ const eyebrowStyle = {
100
+ color: eyebrowColor,
101
+ fontFamily: eyebrowFontFamily,
102
+ fontSize: eyebrowFontSize,
103
+ fontWeight: String(eyebrowFontWeight),
104
+ lineHeight: eyebrowLineHeight,
105
+ textAlign: 'center'
106
+ };
107
+ const headlineStyle = {
108
+ color: headlineColor,
109
+ fontFamily: headlineFontFamily,
110
+ fontSize: headlineFontSize,
111
+ fontWeight: String(headlineFontWeight),
112
+ lineHeight: headlineLineHeight,
113
+ textAlign: 'center',
114
+ width: '100%'
115
+ };
116
+ const supportingTextStyle = {
117
+ color: '#ffffff',
118
+ fontFamily: 'System',
119
+ fontSize: 12,
120
+ fontWeight: '500',
121
+ lineHeight: supportingTextLineHeight,
122
+ textAlign: 'center'
123
+ };
124
+ const buttonWrapStyle = {
125
+ width: '100%'
126
+ };
127
+ const buttonContent = useMemo(() => {
128
+ if (buttonSlot !== undefined && buttonSlot !== null) {
129
+ return cloneChildrenWithModes(buttonSlot, modes);
130
+ }
131
+ if (!showButton) {
132
+ return null;
133
+ }
134
+ return /*#__PURE__*/_jsx(Button, {
135
+ label: buttonLabel,
136
+ onPress: onButtonPress,
137
+ modes: modes,
138
+ style: buttonWrapStyle
139
+ });
140
+ // buttonWrapStyle is a literal object created above; it is intentionally
141
+ // omitted from deps because its identity changes on every render but its
142
+ // shape never does.
143
+ // eslint-disable-next-line react-hooks/exhaustive-deps
144
+ }, [buttonSlot, showButton, buttonLabel, onButtonPress, modes]);
145
+
146
+ // Sized container for the media slot. Always rendered when `media` is
147
+ // provided, so the slot has a predictable box (matches Figma frame
148
+ // 4540:7845 — 117×117 by default) even if the inner element omits its
149
+ // own width/height. `overflow: 'hidden'` mirrors the Figma frame's
150
+ // `clipsContent` so a slightly oversized illustration doesn't break
151
+ // the centered layout.
152
+ const mediaContent = useMemo(() => {
153
+ if (media === undefined || media === null) return null;
154
+ return /*#__PURE__*/_jsx(View, {
155
+ style: {
156
+ width: mediaWidth,
157
+ height: mediaHeight,
158
+ alignItems: 'center',
159
+ justifyContent: 'center',
160
+ overflow: 'hidden'
161
+ },
162
+ children: cloneChildrenWithModes(media, modes)
163
+ });
164
+ }, [media, mediaWidth, mediaHeight, modes]);
165
+ return /*#__PURE__*/_jsxs(View, {
166
+ style: [containerStyle, style],
167
+ testID: testID,
168
+ children: [mediaContent, /*#__PURE__*/_jsxs(View, {
169
+ style: textWrapStyle,
170
+ children: [eyebrow ? /*#__PURE__*/_jsx(Text, {
171
+ style: eyebrowStyle,
172
+ children: eyebrow
173
+ }) : null, headline ? /*#__PURE__*/_jsx(Text, {
174
+ style: headlineStyle,
175
+ children: headline
176
+ }) : null]
177
+ }), showSupportingText && supportingText ? /*#__PURE__*/_jsx(Text, {
178
+ style: supportingTextStyle,
179
+ children: supportingText
180
+ }) : null, buttonContent]
181
+ });
182
+ }
183
+ export default PageHero;