jfs-components 0.0.44 → 0.0.45

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 (73) hide show
  1. package/lib/commonjs/components/AmountInput/AmountInput.js +82 -0
  2. package/lib/commonjs/components/AmountInput/index.js +13 -0
  3. package/lib/commonjs/components/Button/Button.js +31 -28
  4. package/lib/commonjs/components/CardProviderInfo/CardProviderInfo.js +76 -0
  5. package/lib/commonjs/components/EmptyState/EmptyState.js +2 -1
  6. package/lib/commonjs/components/OTP/OTP.js +242 -0
  7. package/lib/commonjs/components/PortfolioHero/PortfolioHero.js +78 -0
  8. package/lib/commonjs/components/ProductLabel/ProductLabel.js +50 -0
  9. package/lib/commonjs/components/ProgressBadge/ProgressBadge.js +130 -0
  10. package/lib/commonjs/components/ProgressBadge/index.js +25 -0
  11. package/lib/commonjs/components/StatItem/StatItem.js +61 -0
  12. package/lib/commonjs/components/SwappableAmount/SwappableAmount.js +71 -0
  13. package/lib/commonjs/components/Text/Text.js +38 -0
  14. package/lib/commonjs/components/Toggle/Toggle.js +102 -0
  15. package/lib/commonjs/components/index.js +63 -0
  16. package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -0
  17. package/lib/commonjs/design-tokens/figma-variables-resolver.js +1 -1
  18. package/lib/commonjs/icons/registry.js +1 -1
  19. package/lib/module/components/AmountInput/AmountInput.js +77 -0
  20. package/lib/module/components/AmountInput/index.js +3 -0
  21. package/lib/module/components/Button/Button.js +31 -28
  22. package/lib/module/components/CardProviderInfo/CardProviderInfo.js +71 -0
  23. package/lib/module/components/EmptyState/EmptyState.js +2 -1
  24. package/lib/module/components/OTP/OTP.js +236 -0
  25. package/lib/module/components/PortfolioHero/PortfolioHero.js +73 -0
  26. package/lib/module/components/ProductLabel/ProductLabel.js +45 -0
  27. package/lib/module/components/ProgressBadge/ProgressBadge.js +125 -0
  28. package/lib/module/components/ProgressBadge/index.js +4 -0
  29. package/lib/module/components/StatItem/StatItem.js +56 -0
  30. package/lib/module/components/SwappableAmount/SwappableAmount.js +66 -0
  31. package/lib/module/components/Text/Text.js +33 -0
  32. package/lib/module/components/Toggle/Toggle.js +97 -0
  33. package/lib/module/components/index.js +10 -1
  34. package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -0
  35. package/lib/module/design-tokens/figma-variables-resolver.js +1 -1
  36. package/lib/module/icons/registry.js +1 -1
  37. package/lib/typescript/src/components/AmountInput/AmountInput.d.ts +23 -0
  38. package/lib/typescript/src/components/AmountInput/index.d.ts +3 -0
  39. package/lib/typescript/src/components/CardProviderInfo/CardProviderInfo.d.ts +24 -0
  40. package/lib/typescript/src/components/EmptyState/EmptyState.d.ts +6 -1
  41. package/lib/typescript/src/components/OTP/OTP.d.ts +36 -0
  42. package/lib/typescript/src/components/PortfolioHero/PortfolioHero.d.ts +21 -0
  43. package/lib/typescript/src/components/ProductLabel/ProductLabel.d.ts +14 -0
  44. package/lib/typescript/src/components/ProgressBadge/ProgressBadge.d.ts +36 -0
  45. package/lib/typescript/src/components/ProgressBadge/index.d.ts +3 -0
  46. package/lib/typescript/src/components/StatItem/StatItem.d.ts +21 -0
  47. package/lib/typescript/src/components/SwappableAmount/SwappableAmount.d.ts +22 -0
  48. package/lib/typescript/src/components/Text/Text.d.ts +14 -0
  49. package/lib/typescript/src/components/Toggle/Toggle.d.ts +29 -0
  50. package/lib/typescript/src/components/index.d.ts +9 -0
  51. package/lib/typescript/src/icons/registry.d.ts +1 -1
  52. package/package.json +1 -1
  53. package/src/components/AmountInput/AmountInput.tsx +81 -0
  54. package/src/components/AmountInput/index.ts +2 -0
  55. package/src/components/Button/Button.tsx +27 -20
  56. package/src/components/CardProviderInfo/CardProviderInfo.tsx +81 -0
  57. package/src/components/EmptyState/EmptyState.tsx +7 -1
  58. package/src/components/OTP/OTP.tsx +275 -0
  59. package/src/components/PortfolioHero/PortfolioHero.tsx +91 -0
  60. package/src/components/ProductLabel/ProductLabel.tsx +58 -0
  61. package/src/components/ProgressBadge/ProgressBadge.tsx +172 -0
  62. package/src/components/ProgressBadge/index.ts +2 -0
  63. package/src/components/StatItem/StatItem.tsx +71 -0
  64. package/src/components/SwappableAmount/SwappableAmount.tsx +92 -0
  65. package/src/components/Text/Text.tsx +48 -0
  66. package/src/components/Toggle/Toggle.tsx +122 -0
  67. package/src/components/index.ts +9 -0
  68. package/src/design-tokens/Coin Variables-variables-full.json +1 -0
  69. package/src/design-tokens/figma-variables-resolver.ts +1 -1
  70. package/src/icons/registry.ts +1 -1
  71. package/lib/commonjs/design-tokens/JFS Variables-variables-full.json +0 -1
  72. package/lib/module/design-tokens/JFS Variables-variables-full.json +0 -1
  73. package/src/design-tokens/JFS Variables-variables-full.json +0 -1
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ import { type ViewStyle } from 'react-native';
3
+ export type AmountInputProps = {
4
+ /**
5
+ * Slot for the MoneyValue component.
6
+ */
7
+ moneyValueSlot?: React.ReactNode;
8
+ /**
9
+ * Slot for the NoteInput component.
10
+ */
11
+ noteInputSlot?: React.ReactNode;
12
+ /** Modes for design token resolution */
13
+ modes?: Record<string, any>;
14
+ /** Optional container style */
15
+ style?: ViewStyle;
16
+ };
17
+ /**
18
+ * AmountInput component that combines MoneyValue and NoteInput from Figma design.
19
+ *
20
+ * @component
21
+ */
22
+ export default function AmountInput({ moneyValueSlot, noteInputSlot, modes: propModes, style, }: AmountInputProps): import("react/jsx-runtime").JSX.Element;
23
+ //# sourceMappingURL=AmountInput.d.ts.map
@@ -0,0 +1,3 @@
1
+ export { default } from './AmountInput';
2
+ export type { AmountInputProps } from './AmountInput';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import { type ViewStyle, type StyleProp, type ImageSourcePropType } from 'react-native';
3
+ export type CardProviderInfoProps = {
4
+ /** Product name shown in the ProductLabel header. */
5
+ label?: string;
6
+ /** Image source for the product avatar. */
7
+ imageSource?: ImageSourcePropType | string;
8
+ /** Slot content — typically StatItem components arranged in a 2-column grid. */
9
+ children?: React.ReactNode;
10
+ /** Design token modes for theming. */
11
+ modes?: Record<string, any>;
12
+ /** Override container styles. */
13
+ style?: StyleProp<ViewStyle>;
14
+ };
15
+ /**
16
+ * CardProviderInfo displays a product header (ProductLabel) followed by a
17
+ * 2-column grid of children (typically StatItem instances).
18
+ *
19
+ * @component
20
+ * @param {CardProviderInfoProps} props
21
+ */
22
+ declare function CardProviderInfo({ label, imageSource, children, modes, style, }: CardProviderInfoProps): import("react/jsx-runtime").JSX.Element;
23
+ export default CardProviderInfo;
24
+ //# sourceMappingURL=CardProviderInfo.d.ts.map
@@ -11,6 +11,11 @@ export type EmptyStateProps = {
11
11
  * @default "Start by paying bills, recharge or your friends"
12
12
  */
13
13
  description?: string;
14
+ /**
15
+ * Whether to show the description text
16
+ * @default true
17
+ */
18
+ showDescription?: boolean;
14
19
  /**
15
20
  * Custom slot for the icon area. Defaults to IconCapsule.
16
21
  * If providing a custom component, ensure it accepts `modes` if needed.
@@ -33,6 +38,6 @@ export type EmptyStateProps = {
33
38
  *
34
39
  * @component
35
40
  */
36
- declare function EmptyState({ title, description, iconSlot, buttonSlot, modes: propModes, style, testID, }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
41
+ declare function EmptyState({ title, description, showDescription, iconSlot, buttonSlot, modes: propModes, style, testID, }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
37
42
  export default EmptyState;
38
43
  //# sourceMappingURL=EmptyState.d.ts.map
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import { type ViewStyle, type StyleProp } from 'react-native';
3
+ import { type SupportTextProps } from '../SupportText/SupportText';
4
+ export type OTPProps = {
5
+ /** Number of OTP digits. Defaults to 6. */
6
+ length?: number;
7
+ /** Controlled value of the OTP input. */
8
+ value?: string;
9
+ /** Default value for uncontrolled usage. */
10
+ defaultValue?: string;
11
+ /** Called when the OTP value changes. Receives the current string of entered digits. */
12
+ onChange?: (value: string) => void;
13
+ /** Alias for onChange — called when the OTP value changes. */
14
+ onValueChange?: (value: string) => void;
15
+ /** Called when all digits have been entered. Receives the complete OTP string. */
16
+ onComplete?: (value: string) => void;
17
+ /** Whether the OTP input is disabled. */
18
+ isDisabled?: boolean;
19
+ /** Whether the OTP input is in an invalid/error state. */
20
+ isInvalid?: boolean;
21
+ /** Regex pattern to filter allowed characters. Defaults to digits only. */
22
+ allowedPattern?: RegExp;
23
+ /** Auto-focus the input on mount. */
24
+ autoFocus?: boolean;
25
+ /** Design token modes for Figma token resolution. */
26
+ modes?: Record<string, any>;
27
+ /** Container style override. */
28
+ style?: StyleProp<ViewStyle>;
29
+ /** Optional SupportText rendered below the slots. Pass a string for the label or a ReactNode for full control. */
30
+ supportText?: React.ReactNode;
31
+ /** SupportText status when using the string shorthand. */
32
+ supportTextStatus?: SupportTextProps['status'];
33
+ };
34
+ declare function OTP({ length, value: controlledValue, defaultValue, onChange, onValueChange, onComplete, isDisabled, isInvalid, allowedPattern, autoFocus, modes: propModes, style, supportText, supportTextStatus, }: OTPProps): import("react/jsx-runtime").JSX.Element;
35
+ export default OTP;
36
+ //# sourceMappingURL=OTP.d.ts.map
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import { type ViewStyle, type ImageSourcePropType } from 'react-native';
3
+ export type PortfolioHeroProps = {
4
+ /** Product label text displayed next to the avatar. */
5
+ label?: string;
6
+ /** Image source for the product avatar. */
7
+ imageSource?: ImageSourcePropType | string;
8
+ /** Monetary value to display. */
9
+ value?: string;
10
+ /** Currency symbol or ISO code. */
11
+ currency?: string;
12
+ /** Modes configuration mapped to Figma tokens. */
13
+ modes?: Record<string, any>;
14
+ /** Slot content rendered below the money value (e.g. Badge, subtitle). */
15
+ children?: React.ReactNode;
16
+ /** Container style override. */
17
+ style?: ViewStyle;
18
+ };
19
+ declare function PortfolioHero({ label, imageSource, value, currency, modes, children, style, }: PortfolioHeroProps): import("react/jsx-runtime").JSX.Element;
20
+ export default PortfolioHero;
21
+ //# sourceMappingURL=PortfolioHero.d.ts.map
@@ -0,0 +1,14 @@
1
+ import { type ViewStyle, type ImageSourcePropType } from 'react-native';
2
+ export type ProductLabelProps = {
3
+ /** The product name label text. */
4
+ label?: string;
5
+ /** Image source for the product avatar. */
6
+ imageSource?: ImageSourcePropType | string;
7
+ /** Modes configuration for design token resolution. */
8
+ modes?: Record<string, any>;
9
+ /** Container style override. */
10
+ style?: ViewStyle;
11
+ };
12
+ declare function ProductLabel({ label, imageSource, modes, style, }: ProductLabelProps): import("react/jsx-runtime").JSX.Element;
13
+ export default ProductLabel;
14
+ //# sourceMappingURL=ProductLabel.d.ts.map
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import { View, type StyleProp, type ViewStyle, type TextStyle } from 'react-native';
3
+ export type ProgressBadgeProps = {
4
+ /** The text displayed in the badge (e.g. "Live price...") */
5
+ taskName?: string;
6
+ /** The icon name to display to the left of the text */
7
+ iconName?: string;
8
+ /** The progress value between 0 and 100 */
9
+ value?: number;
10
+ /** Modes object passed to `getVariableByName` for design token resolution */
11
+ modes?: Record<string, any>;
12
+ /** Optional container style overrides */
13
+ style?: StyleProp<ViewStyle>;
14
+ /** Optional text style overrides */
15
+ textStyle?: StyleProp<TextStyle>;
16
+ /** Accessibility label for screen readers */
17
+ accessibilityLabel?: string;
18
+ } & React.ComponentProps<typeof View>;
19
+ /**
20
+ * ProgressBadge component that displays an icon, text, and an internal progress bar.
21
+ *
22
+ * All visual attributes resolve from Figma tokens via `getVariableByName` using the provided `modes`.
23
+ *
24
+ * @component
25
+ * @param {Object} props
26
+ * @param {string} [props.taskName="Live price: [price] (00:43)"] - The text displayed.
27
+ * @param {string} [props.iconName="ic_live"] - Icon name from the registry.
28
+ * @param {number} [props.value=0] - The progress value between 0 and 100.
29
+ * @param {Object} [props.modes={}] - Modes object passed to `getVariableByName` for design tokens.
30
+ * @param {Object} [props.style] - Optional container style overrides.
31
+ * @param {Object} [props.textStyle] - Optional text style overrides.
32
+ * @param {string} [props.accessibilityLabel] - Accessibility label.
33
+ */
34
+ declare function ProgressBadge({ taskName, iconName, value, modes, style, textStyle: textStyleOverride, accessibilityLabel, ...rest }: ProgressBadgeProps): import("react/jsx-runtime").JSX.Element;
35
+ export default ProgressBadge;
36
+ //# sourceMappingURL=ProgressBadge.d.ts.map
@@ -0,0 +1,3 @@
1
+ export { default } from './ProgressBadge';
2
+ export * from './ProgressBadge';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,21 @@
1
+ import { type StyleProp, type ViewStyle } from 'react-native';
2
+ export type StatItemProps = {
3
+ /** The small descriptive label above the value. */
4
+ label?: string;
5
+ /** The large prominent value to display. */
6
+ value?: string;
7
+ /** Design token modes for theming. */
8
+ modes?: Record<string, any>;
9
+ /** Override container styles. */
10
+ style?: StyleProp<ViewStyle>;
11
+ };
12
+ /**
13
+ * StatItem displays a label/value pair with the value in a large, bold style.
14
+ * Useful for metrics, product stats, or KPI callouts.
15
+ *
16
+ * @component
17
+ * @param {StatItemProps} props
18
+ */
19
+ declare function StatItem({ label, value, modes, style, }: StatItemProps): import("react/jsx-runtime").JSX.Element;
20
+ export default StatItem;
21
+ //# sourceMappingURL=StatItem.d.ts.map
@@ -0,0 +1,22 @@
1
+ import { type ViewStyle } from 'react-native';
2
+ export type SwappableAmountProps = {
3
+ /** Large display value (e.g. "49g"). */
4
+ value?: string;
5
+ /** Whether to show the schedule button above the value. */
6
+ schedule?: boolean;
7
+ /** Label text for the schedule button (e.g. "Weekly on Mondays"). */
8
+ scheduleLabel?: string;
9
+ /** Label text for the amount/swap button (e.g. "₹5100"). */
10
+ amountLabel?: string;
11
+ /** Callback when the schedule button is pressed. */
12
+ onSchedulePress?: () => void;
13
+ /** Callback when the amount/swap button is pressed. */
14
+ onAmountPress?: () => void;
15
+ /** Modes configuration for design token resolution. */
16
+ modes?: Record<string, any>;
17
+ /** Container style override. */
18
+ style?: ViewStyle;
19
+ };
20
+ declare function SwappableAmount({ value, schedule, scheduleLabel, amountLabel, onSchedulePress, onAmountPress, modes, style, }: SwappableAmountProps): import("react/jsx-runtime").JSX.Element;
21
+ export default SwappableAmount;
22
+ //# sourceMappingURL=SwappableAmount.d.ts.map
@@ -0,0 +1,14 @@
1
+ import { type TextStyle, type StyleProp } from 'react-native';
2
+ export type TextProps = {
3
+ /** The text content to display. */
4
+ text?: string;
5
+ /** Modes configuration for design token resolution. */
6
+ modes?: Record<string, any>;
7
+ /** Style override for the text. */
8
+ style?: StyleProp<TextStyle>;
9
+ /** Number of lines to limit the text to. */
10
+ numberOfLines?: number;
11
+ };
12
+ declare function Text({ text, modes, style, numberOfLines, }: TextProps): import("react/jsx-runtime").JSX.Element;
13
+ export default Text;
14
+ //# sourceMappingURL=Text.d.ts.map
@@ -0,0 +1,29 @@
1
+ import { type StyleProp, type ViewStyle } from 'react-native';
2
+ export interface ToggleProps {
3
+ /** Whether the toggle is on (controlled) */
4
+ value?: boolean;
5
+ /** Initial value (uncontrolled) */
6
+ defaultValue?: boolean;
7
+ /** Callback when the toggle state changes */
8
+ onValueChange?: (value: boolean) => void;
9
+ /** Whether the toggle is disabled */
10
+ disabled?: boolean;
11
+ /** Design token modes for theming */
12
+ modes?: Record<string, any>;
13
+ /** Override container styles */
14
+ style?: StyleProp<ViewStyle>;
15
+ /** Accessibility label for screen readers */
16
+ accessibilityLabel?: string;
17
+ }
18
+ /**
19
+ * Toggle (switch) component that maps directly to the Figma design using design tokens.
20
+ *
21
+ * Supports controlled and uncontrolled usage, on/off states, and disabled state.
22
+ * All styling is driven by design tokens with optional mode overrides.
23
+ *
24
+ * @component
25
+ * @param {ToggleProps} props
26
+ */
27
+ declare function Toggle({ value: controlledValue, defaultValue, onValueChange, disabled, modes, style, accessibilityLabel, }: ToggleProps): import("react/jsx-runtime").JSX.Element;
28
+ export default Toggle;
29
+ //# sourceMappingURL=Toggle.d.ts.map
@@ -49,6 +49,7 @@ export { default as Accordion, type AccordionProps } from './Accordion/Accordion
49
49
  export { default as ActionTile, type ActionTileProps } from './ActionTile/ActionTile';
50
50
  export { default as Balance, type BalanceProps } from './Balance/Balance';
51
51
  export { default as ButtonGroup, type ButtonGroupProps } from './ButtonGroup/ButtonGroup';
52
+ export { default as CardProviderInfo, type CardProviderInfoProps } from './CardProviderInfo/CardProviderInfo';
52
53
  export { default as ChipSelect, type ChipSelectProps } from './ChipSelect/ChipSelect';
53
54
  export { default as InputSearch, type InputSearchProps } from './InputSearch/InputSearch';
54
55
  export { default as SupportText, type SupportTextProps } from './SupportText/SupportText';
@@ -59,4 +60,12 @@ export { default as TabItem, type TabItemProps } from './Tabs/TabItem';
59
60
  export { default as Toast, type ToastProps } from './Toast/Toast';
60
61
  export { default as ToastProvider, type ToastProviderProps } from './Toast/ToastProvider';
61
62
  export { useToast, addToast, closeToast, closeAll, type ToastOptions, type ToastEntry, type ToastPlacement } from './Toast/useToast';
63
+ export { default as AmountInput, type AmountInputProps } from './AmountInput/AmountInput';
64
+ export { default as PortfolioHero, type PortfolioHeroProps } from './PortfolioHero/PortfolioHero';
65
+ export { default as ProductLabel, type ProductLabelProps } from './ProductLabel/ProductLabel';
66
+ export { default as SwappableAmount, type SwappableAmountProps } from './SwappableAmount/SwappableAmount';
67
+ export { default as OTP, type OTPProps } from './OTP/OTP';
68
+ export { default as StatItem, type StatItemProps } from './StatItem/StatItem';
69
+ export { default as Text, type TextProps } from './Text/Text';
70
+ export { default as Toggle, type ToggleProps } from './Toggle/Toggle';
62
71
  //# sourceMappingURL=index.d.ts.map
@@ -4,7 +4,7 @@
4
4
  * Auto-generated from SVG files in src/icons/
5
5
  * DO NOT EDIT MANUALLY - Run "npm run icons:generate" to regenerate
6
6
  *
7
- * Generated: 2026-02-25T22:30:05.664Z
7
+ * Generated: 2026-03-16T08:36:20.904Z
8
8
  */
9
9
  export declare const iconRegistry: Record<string, {
10
10
  path: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jfs-components",
3
- "version": "0.0.44",
3
+ "version": "0.0.45",
4
4
  "description": "React Native Jio Finance Components Library",
5
5
  "author": "sunshuaiqi@gmail.com",
6
6
  "license": "MIT",
@@ -0,0 +1,81 @@
1
+ import React from 'react'
2
+ import { View, type ViewStyle } from 'react-native'
3
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
4
+ import { useTokens } from '../../design-tokens/JFSThemeProvider'
5
+ import MoneyValue from '../MoneyValue/MoneyValue'
6
+ import NoteInput from '../NoteInput/NoteInput'
7
+
8
+ export type AmountInputProps = {
9
+ /**
10
+ * Slot for the MoneyValue component.
11
+ */
12
+ moneyValueSlot?: React.ReactNode
13
+ /**
14
+ * Slot for the NoteInput component.
15
+ */
16
+ noteInputSlot?: React.ReactNode
17
+ /** Modes for design token resolution */
18
+ modes?: Record<string, any>
19
+ /** Optional container style */
20
+ style?: ViewStyle
21
+ }
22
+
23
+ /**
24
+ * AmountInput component that combines MoneyValue and NoteInput from Figma design.
25
+ *
26
+ * @component
27
+ */
28
+ export default function AmountInput({
29
+ moneyValueSlot,
30
+ noteInputSlot,
31
+ modes: propModes = {},
32
+ style,
33
+ }: AmountInputProps) {
34
+ const { modes: globalModes } = useTokens()
35
+ const modes = { ...globalModes, ...propModes }
36
+
37
+ // Resolve tokens
38
+ const gap = Number(getVariableByName('amountInput/gap', modes)) || 16
39
+ const paddingHorizontal = Number(getVariableByName('amountInput/padding/horizontal', modes)) || 0
40
+ const paddingVertical = Number(getVariableByName('amountInput/padding/vertical', modes)) || 0
41
+
42
+ const containerStyle: ViewStyle = {
43
+ flexDirection: 'column',
44
+ alignItems: 'center',
45
+ gap,
46
+ paddingHorizontal,
47
+ paddingVertical,
48
+ ...style,
49
+ }
50
+
51
+ // Handle MoneyValue Slot
52
+ const renderMoneyValueSlot = () => {
53
+ if (React.isValidElement(moneyValueSlot)) {
54
+ return React.cloneElement(moneyValueSlot as React.ReactElement<any>, { modes })
55
+ }
56
+ // Default fallback if no slot prop is provided
57
+ if (!moneyValueSlot) {
58
+ return <MoneyValue modes={modes} />
59
+ }
60
+ return moneyValueSlot
61
+ }
62
+
63
+ // Handle NoteInput Slot
64
+ const renderNoteInputSlot = () => {
65
+ if (React.isValidElement(noteInputSlot)) {
66
+ return React.cloneElement(noteInputSlot as React.ReactElement<any>, { modes })
67
+ }
68
+ // Default fallback if no slot prop is provided
69
+ if (!noteInputSlot) {
70
+ return <NoteInput modes={modes} />
71
+ }
72
+ return noteInputSlot
73
+ }
74
+
75
+ return (
76
+ <View style={containerStyle}>
77
+ {renderMoneyValueSlot()}
78
+ {renderNoteInputSlot()}
79
+ </View>
80
+ )
81
+ }
@@ -0,0 +1,2 @@
1
+ export { default } from './AmountInput'
2
+ export type { AmountInputProps } from './AmountInput'
@@ -100,8 +100,26 @@ function Button({
100
100
  const iconColor = getVariableByName('button/icon/color', modes) ?? textColor
101
101
  const iconSize = getVariableByName('button/icon/size', modes) ?? 18
102
102
 
103
+ const [isHovered, setIsHovered] = useState(false)
104
+ const [isPressed, setIsPressed] = useState(false)
105
+
106
+ const hoverModes = { ...modes, "Button / State": "Hover" }
107
+ const hoverBg = getVariableByName('button/background', hoverModes) || backgroundColor
108
+ const hoverBorderColor = getVariableByName('button/border/color', hoverModes) || borderColor
109
+ const hoverTextColor = getVariableByName('button/foreground', hoverModes) || textColor
110
+ const hoverIconColor = getVariableByName('button/icon/color', hoverModes) ?? hoverTextColor
111
+
112
+ const pressedModes = { ...modes, "Button / State": "Pressed" }
113
+ const pressedBg = getVariableByName('button/background', pressedModes) || backgroundColor
114
+ const pressedBorderColor = getVariableByName('button/border/color', pressedModes) || borderColor
115
+ const pressedTextColor = getVariableByName('button/foreground', pressedModes) || textColor
116
+ const pressedIconColor = getVariableByName('button/icon/color', pressedModes) ?? pressedTextColor
117
+
118
+ const activeTextColor = isPressed && !disabled ? pressedTextColor : isHovered && !disabled ? hoverTextColor : textColor
119
+ const activeIconColor = isPressed && !disabled ? pressedIconColor : isHovered && !disabled ? hoverIconColor : iconColor
120
+
103
121
  const baseLabelTextStyle: TextStyle = {
104
- color: textColor,
122
+ color: activeTextColor,
105
123
  fontFamily,
106
124
  fontWeight,
107
125
  fontSize,
@@ -168,12 +186,8 @@ function Button({
168
186
  webAccessibilityProps,
169
187
  })
170
188
 
171
- // Interaction states (placeholders for visuals; tweak later)
172
- const [isFocused, setIsFocused] = useState(false)
173
- const [isHovered, setIsHovered] = useState(false)
174
- const pressedStyle = { transform: [{ scale: 0.995 }], backgroundColor: '#b88940' }
175
- const focusStyle = { borderWidth: 1, borderColor: '#222' }
176
- const hoverStyle = { opacity: 0.95 }
189
+ const hoverStyle = { backgroundColor: hoverBg, borderColor: hoverBorderColor }
190
+ const pressedStyle = { backgroundColor: pressedBg, borderColor: pressedBorderColor }
177
191
 
178
192
  if (__DEV__) {
179
193
  if (children && labelStyle) {
@@ -203,18 +217,12 @@ function Button({
203
217
  disabled={disabled}
204
218
  {...(onPress !== undefined ? { onPress } : {})}
205
219
  onPressIn={(e: any) => {
206
- ; (rest as any)?.onPressIn?.(e)
220
+ setIsPressed(true)
221
+ ;(rest as any)?.onPressIn?.(e)
207
222
  }}
208
223
  onPressOut={(e: any) => {
209
- ; (rest as any)?.onPressOut?.(e)
210
- }}
211
- onFocus={(e: any) => {
212
- setIsFocused(true)
213
- ; (rest as any)?.onFocus?.(e)
214
- }}
215
- onBlur={(e: any) => {
216
- setIsFocused(false)
217
- ; (rest as any)?.onBlur?.(e)
224
+ setIsPressed(false)
225
+ ;(rest as any)?.onPressOut?.(e)
218
226
  }}
219
227
  onHoverIn={(e: any) => {
220
228
  setIsHovered(true)
@@ -226,9 +234,8 @@ function Button({
226
234
  }}
227
235
  style={({ pressed }) => [
228
236
  containerBaseStyle,
229
- pressed && !disabled ? pressedStyle : null,
230
237
  isHovered && !disabled ? hoverStyle : null,
231
- isFocused && !disabled ? focusStyle : null,
238
+ (pressed || isPressed) && !disabled ? pressedStyle : null,
232
239
  style,
233
240
  ] as StyleProp<ViewStyle>}
234
241
  {...webProps}
@@ -241,7 +248,7 @@ function Button({
241
248
  {content}
242
249
  {icon ? (
243
250
  <View style={trailingAccessoryStyle}>
244
- <Icon name={icon} size={iconSize as number} color={iconColor as string} accessibilityElementsHidden={true} importantForAccessibility="no" />
251
+ <Icon name={icon} size={iconSize as number} color={activeIconColor as string} accessibilityElementsHidden={true} importantForAccessibility="no" />
245
252
  </View>
246
253
  ) : trailing ? (
247
254
  <View style={trailingAccessoryStyle}>
@@ -0,0 +1,81 @@
1
+ import React from 'react'
2
+ import { View, type ViewStyle, type StyleProp, type ImageSourcePropType } from 'react-native'
3
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
4
+ import ProductLabel from '../ProductLabel/ProductLabel'
5
+ import { cloneChildrenWithModes } from '../../utils/react-utils'
6
+
7
+ export type CardProviderInfoProps = {
8
+ /** Product name shown in the ProductLabel header. */
9
+ label?: string
10
+ /** Image source for the product avatar. */
11
+ imageSource?: ImageSourcePropType | string
12
+ /** Slot content — typically StatItem components arranged in a 2-column grid. */
13
+ children?: React.ReactNode
14
+ /** Design token modes for theming. */
15
+ modes?: Record<string, any>
16
+ /** Override container styles. */
17
+ style?: StyleProp<ViewStyle>
18
+ }
19
+
20
+ /**
21
+ * CardProviderInfo displays a product header (ProductLabel) followed by a
22
+ * 2-column grid of children (typically StatItem instances).
23
+ *
24
+ * @component
25
+ * @param {CardProviderInfoProps} props
26
+ */
27
+ function CardProviderInfo({
28
+ label = 'Gold',
29
+ imageSource,
30
+ children,
31
+ modes = {},
32
+ style,
33
+ }: CardProviderInfoProps) {
34
+ const background = getVariableByName('card/providerInfo/background', modes) ?? '#fef4e5'
35
+ const border = getVariableByName('card/providerInfo/border', modes) ?? '#fef4e5'
36
+ const borderWidthVal = getVariableByName('card/providerInfo/borderWidth', modes) ?? 1
37
+ const padding = getVariableByName('card/providerInfo/padding', modes) ?? 20
38
+ const gap = getVariableByName('card/providerInfo/gap', modes) ?? 20
39
+ const radius = getVariableByName('card/providerInfo/radius', modes) ?? 16
40
+ const gridGap = getVariableByName('card/providerInfo/grid/gap', modes) ?? 8
41
+
42
+ const containerStyle: ViewStyle = {
43
+ backgroundColor: background as string,
44
+ borderColor: border as string,
45
+ borderWidth: borderWidthVal as number,
46
+ borderStyle: 'solid',
47
+ padding: padding as number,
48
+ gap: gap as number,
49
+ borderRadius: radius as number,
50
+ }
51
+
52
+ const gridGapNum = gridGap as number
53
+ const clonedChildren = children ? cloneChildrenWithModes(children, modes) : []
54
+ const childArray = React.Children.toArray(clonedChildren)
55
+
56
+ const rows: React.ReactNode[][] = []
57
+ for (let i = 0; i < childArray.length; i += 2) {
58
+ rows.push(childArray.slice(i, i + 2))
59
+ }
60
+
61
+ return (
62
+ <View style={[containerStyle, style]}>
63
+ <ProductLabel label={label} imageSource={imageSource} modes={modes} />
64
+ {childArray.length > 0 && (
65
+ <View style={{ rowGap: gridGapNum }}>
66
+ {rows.map((row, i) => (
67
+ <View key={i} style={{ flexDirection: 'row', columnGap: gridGapNum }}>
68
+ {row.map((child, j) => (
69
+ <View key={j} style={{ flex: 1 }}>
70
+ {child}
71
+ </View>
72
+ ))}
73
+ </View>
74
+ ))}
75
+ </View>
76
+ )}
77
+ </View>
78
+ )
79
+ }
80
+
81
+ export default CardProviderInfo
@@ -16,6 +16,11 @@ export type EmptyStateProps = {
16
16
  * @default "Start by paying bills, recharge or your friends"
17
17
  */
18
18
  description?: string;
19
+ /**
20
+ * Whether to show the description text
21
+ * @default true
22
+ */
23
+ showDescription?: boolean;
19
24
  /**
20
25
  * Custom slot for the icon area. Defaults to IconCapsule.
21
26
  * If providing a custom component, ensure it accepts `modes` if needed.
@@ -42,6 +47,7 @@ export type EmptyStateProps = {
42
47
  function EmptyState({
43
48
  title = "No payments to show",
44
49
  description = "Start by paying bills, recharge or your friends",
50
+ showDescription = true,
45
51
  iconSlot,
46
52
  buttonSlot,
47
53
  modes: propModes = {},
@@ -140,7 +146,7 @@ function EmptyState({
140
146
 
141
147
  {/* Texts */}
142
148
  <Text style={titleStyle}>{title}</Text>
143
- {description ? <Text style={bodyStyle}>{description}</Text> : null}
149
+ {showDescription && description ? <Text style={bodyStyle}>{description}</Text> : null}
144
150
  </View>
145
151
 
146
152
  {/* Button Slot */}