jfs-components 0.0.62 → 0.0.64
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 +59 -0
- package/lib/commonjs/components/Accordion/Accordion.js +1 -1
- package/lib/commonjs/components/ActionFooter/ActionFooter.js +1 -1
- package/lib/commonjs/components/ActionTile/ActionTile.js +2 -1
- package/lib/commonjs/components/AmountInput/AmountInput.js +2 -1
- package/lib/commonjs/components/AppBar/AppBar.js +1 -1
- package/lib/commonjs/components/Avatar/Avatar.js +184 -162
- package/lib/commonjs/components/AvatarGroup/AvatarGroup.js +1 -1
- package/lib/commonjs/components/Badge/Badge.js +2 -1
- package/lib/commonjs/components/Balance/Balance.js +2 -1
- package/lib/commonjs/components/BottomNav/BottomNav.js +2 -1
- package/lib/commonjs/components/BottomNavItem/BottomNavItem.js +106 -86
- package/lib/commonjs/components/Button/Button.js +190 -93
- package/lib/commonjs/components/ButtonGroup/ButtonGroup.js +1 -1
- package/lib/commonjs/components/Card/Card.js +2 -1
- package/lib/commonjs/components/CardCTA/CardCTA.js +1 -1
- package/lib/commonjs/components/CardProviderInfo/CardProviderInfo.js +1 -1
- package/lib/commonjs/components/Carousel/Carousel.js +3 -2
- package/lib/commonjs/components/Checkbox/Checkbox.js +2 -1
- package/lib/commonjs/components/ChipGroup/ChipGroup.js +1 -1
- package/lib/commonjs/components/ChipSelect/ChipSelect.js +2 -1
- package/lib/commonjs/components/DebitCard/DebitCard.js +1 -1
- package/lib/commonjs/components/Disclaimer/Disclaimer.js +2 -1
- package/lib/commonjs/components/Divider/Divider.js +2 -1
- package/lib/commonjs/components/Drawer/Drawer.js +109 -48
- package/lib/commonjs/components/EmptyState/EmptyState.js +2 -1
- package/lib/commonjs/components/FilterBar/FilterBar.js +1 -1
- package/lib/commonjs/components/Form/Form.js +2 -1
- package/lib/commonjs/components/FormField/FormField.js +3 -2
- package/lib/commonjs/components/HStack/HStack.js +1 -1
- package/lib/commonjs/components/HoldingsCard/HoldingsCard.js +2 -1
- package/lib/commonjs/components/IconButton/IconButton.js +118 -128
- package/lib/commonjs/components/IconCapsule/IconCapsule.js +61 -57
- package/lib/commonjs/components/InputSearch/InputSearch.js +7 -3
- package/lib/commonjs/components/LazyList/LazyList.js +1 -1
- package/lib/commonjs/components/LinearMeter/LinearMeter.js +3 -2
- package/lib/commonjs/components/ListGroup/ListGroup.js +1 -1
- package/lib/commonjs/components/ListItem/ListItem.js +190 -142
- package/lib/commonjs/components/MediaCard/MediaCard.js +3 -3
- package/lib/commonjs/components/MerchantProfile/MerchantProfile.js +2 -1
- package/lib/commonjs/components/MoneyValue/MoneyValue.js +2 -1
- package/lib/commonjs/components/NavArrow/NavArrow.js +82 -59
- package/lib/commonjs/components/NoteInput/NoteInput.js +2 -1
- package/lib/commonjs/components/Nudge/Nudge.js +1 -1
- package/lib/commonjs/components/Numpad/Numpad.js +2 -1
- package/lib/commonjs/components/OTP/OTP.js +1 -1
- package/lib/commonjs/components/PaymentFeedback/PaymentFeedback.js +2 -1
- package/lib/commonjs/components/Popup/Popup.js +2 -1
- package/lib/commonjs/components/ProductLabel/ProductLabel.js +2 -1
- package/lib/commonjs/components/ProgressBadge/ProgressBadge.js +2 -1
- package/lib/commonjs/components/RadioButton/RadioButton.js +2 -1
- package/lib/commonjs/components/RechargeCard/RechargeCard.js +2 -1
- package/lib/commonjs/components/Screen/Screen.js +1 -1
- package/lib/commonjs/components/Section/Section.js +500 -166
- package/lib/commonjs/components/SegmentedControl/SegmentedControl.js +3 -2
- package/lib/commonjs/components/StatItem/StatItem.js +2 -1
- package/lib/commonjs/components/StatusHero/StatusHero.js +2 -1
- package/lib/commonjs/components/Stepper/Step.js +2 -1
- package/lib/commonjs/components/Stepper/StepLabel.js +2 -1
- package/lib/commonjs/components/Stepper/Stepper.js +2 -1
- package/lib/commonjs/components/SupportText/SupportText.js +2 -1
- package/lib/commonjs/components/SupportText/SupportTextIcon.js +2 -1
- package/lib/commonjs/components/SwappableAmount/SwappableAmount.js +2 -1
- package/lib/commonjs/components/Tabs/TabItem.js +2 -1
- package/lib/commonjs/components/Tabs/Tabs.js +2 -1
- package/lib/commonjs/components/Text/Text.js +2 -1
- package/lib/commonjs/components/TextInput/TextInput.js +2 -2
- package/lib/commonjs/components/ThreadHero/ThreadHero.js +2 -1
- package/lib/commonjs/components/Title/Title.js +2 -1
- package/lib/commonjs/components/Toast/Toast.js +2 -1
- package/lib/commonjs/components/Toggle/Toggle.js +2 -1
- package/lib/commonjs/components/Tooltip/Tooltip.js +2 -1
- package/lib/commonjs/components/TransactionBubble/TransactionBubble.js +1 -1
- package/lib/commonjs/components/TransactionDetails/TransactionDetails.js +2 -2
- package/lib/commonjs/components/TransactionStatus/TransactionStatus.js +3 -2
- package/lib/commonjs/components/UpiHandle/UpiHandle.js +144 -110
- package/lib/commonjs/components/VStack/VStack.js +1 -1
- package/lib/commonjs/design-tokens/figma-variables-resolver.js +21 -3
- package/lib/commonjs/icons/registry.js +1 -1
- package/lib/commonjs/utils/react-utils.js +17 -0
- package/lib/module/components/Accordion/Accordion.js +2 -2
- package/lib/module/components/ActionFooter/ActionFooter.js +2 -2
- package/lib/module/components/ActionTile/ActionTile.js +2 -1
- package/lib/module/components/AmountInput/AmountInput.js +2 -1
- package/lib/module/components/AppBar/AppBar.js +2 -2
- package/lib/module/components/Avatar/Avatar.js +184 -162
- package/lib/module/components/AvatarGroup/AvatarGroup.js +2 -2
- package/lib/module/components/Badge/Badge.js +2 -1
- package/lib/module/components/Balance/Balance.js +2 -1
- package/lib/module/components/BottomNav/BottomNav.js +2 -1
- package/lib/module/components/BottomNavItem/BottomNavItem.js +108 -88
- package/lib/module/components/Button/Button.js +192 -95
- package/lib/module/components/ButtonGroup/ButtonGroup.js +2 -2
- package/lib/module/components/Card/Card.js +2 -1
- package/lib/module/components/CardCTA/CardCTA.js +2 -2
- package/lib/module/components/CardProviderInfo/CardProviderInfo.js +2 -2
- package/lib/module/components/Carousel/Carousel.js +3 -2
- package/lib/module/components/Checkbox/Checkbox.js +2 -1
- package/lib/module/components/ChipGroup/ChipGroup.js +2 -2
- package/lib/module/components/ChipSelect/ChipSelect.js +2 -1
- package/lib/module/components/DebitCard/DebitCard.js +2 -2
- package/lib/module/components/Disclaimer/Disclaimer.js +2 -1
- package/lib/module/components/Divider/Divider.js +2 -1
- package/lib/module/components/Drawer/Drawer.js +109 -48
- package/lib/module/components/EmptyState/EmptyState.js +2 -1
- package/lib/module/components/FilterBar/FilterBar.js +2 -2
- package/lib/module/components/Form/Form.js +2 -1
- package/lib/module/components/FormField/FormField.js +3 -2
- package/lib/module/components/HStack/HStack.js +2 -2
- package/lib/module/components/HoldingsCard/HoldingsCard.js +2 -1
- package/lib/module/components/IconButton/IconButton.js +120 -130
- package/lib/module/components/IconCapsule/IconCapsule.js +60 -57
- package/lib/module/components/InputSearch/InputSearch.js +7 -3
- package/lib/module/components/LazyList/LazyList.js +2 -2
- package/lib/module/components/LinearMeter/LinearMeter.js +3 -2
- package/lib/module/components/ListGroup/ListGroup.js +2 -2
- package/lib/module/components/ListItem/ListItem.js +194 -146
- package/lib/module/components/MediaCard/MediaCard.js +4 -2
- package/lib/module/components/MerchantProfile/MerchantProfile.js +2 -1
- package/lib/module/components/MoneyValue/MoneyValue.js +2 -1
- package/lib/module/components/NavArrow/NavArrow.js +82 -58
- package/lib/module/components/NoteInput/NoteInput.js +2 -1
- package/lib/module/components/Nudge/Nudge.js +2 -2
- package/lib/module/components/Numpad/Numpad.js +2 -1
- package/lib/module/components/OTP/OTP.js +2 -2
- package/lib/module/components/PaymentFeedback/PaymentFeedback.js +2 -1
- package/lib/module/components/Popup/Popup.js +2 -1
- package/lib/module/components/ProductLabel/ProductLabel.js +2 -1
- package/lib/module/components/ProgressBadge/ProgressBadge.js +2 -1
- package/lib/module/components/RadioButton/RadioButton.js +2 -1
- package/lib/module/components/RechargeCard/RechargeCard.js +2 -1
- package/lib/module/components/Screen/Screen.js +2 -2
- package/lib/module/components/Section/Section.js +503 -169
- package/lib/module/components/SegmentedControl/SegmentedControl.js +3 -2
- package/lib/module/components/StatItem/StatItem.js +2 -1
- package/lib/module/components/StatusHero/StatusHero.js +2 -1
- package/lib/module/components/Stepper/Step.js +2 -1
- package/lib/module/components/Stepper/StepLabel.js +2 -1
- package/lib/module/components/Stepper/Stepper.js +2 -1
- package/lib/module/components/SupportText/SupportText.js +2 -1
- package/lib/module/components/SupportText/SupportTextIcon.js +2 -1
- package/lib/module/components/SwappableAmount/SwappableAmount.js +2 -1
- package/lib/module/components/Tabs/TabItem.js +2 -1
- package/lib/module/components/Tabs/Tabs.js +2 -1
- package/lib/module/components/Text/Text.js +2 -1
- package/lib/module/components/TextInput/TextInput.js +3 -3
- package/lib/module/components/ThreadHero/ThreadHero.js +2 -1
- package/lib/module/components/Title/Title.js +2 -1
- package/lib/module/components/Toast/Toast.js +2 -1
- package/lib/module/components/Toggle/Toggle.js +2 -1
- package/lib/module/components/Tooltip/Tooltip.js +2 -1
- package/lib/module/components/TransactionBubble/TransactionBubble.js +2 -2
- package/lib/module/components/TransactionDetails/TransactionDetails.js +3 -3
- package/lib/module/components/TransactionStatus/TransactionStatus.js +3 -2
- package/lib/module/components/UpiHandle/UpiHandle.js +147 -113
- package/lib/module/components/VStack/VStack.js +2 -2
- package/lib/module/design-tokens/figma-variables-resolver.js +21 -3
- package/lib/module/icons/registry.js +1 -1
- package/lib/module/utils/react-utils.js +16 -0
- package/lib/typescript/src/components/Avatar/Avatar.d.ts +11 -17
- package/lib/typescript/src/components/BottomNavItem/BottomNavItem.d.ts +12 -8
- package/lib/typescript/src/components/Button/Button.d.ts +18 -1
- package/lib/typescript/src/components/IconButton/IconButton.d.ts +12 -29
- package/lib/typescript/src/components/IconCapsule/IconCapsule.d.ts +10 -18
- package/lib/typescript/src/components/InputSearch/InputSearch.d.ts +8 -3
- package/lib/typescript/src/components/ListItem/ListItem.d.ts +14 -1
- package/lib/typescript/src/components/NavArrow/NavArrow.d.ts +12 -11
- package/lib/typescript/src/components/Section/Section.d.ts +43 -48
- package/lib/typescript/src/components/UpiHandle/UpiHandle.d.ts +13 -12
- package/lib/typescript/src/icons/registry.d.ts +1 -1
- package/lib/typescript/src/utils/react-utils.d.ts +15 -0
- package/package.json +4 -6
- package/src/components/Accordion/Accordion.tsx +2 -2
- package/src/components/ActionFooter/ActionFooter.tsx +2 -2
- package/src/components/ActionTile/ActionTile.tsx +2 -1
- package/src/components/AmountInput/AmountInput.tsx +2 -1
- package/src/components/AppBar/AppBar.tsx +2 -2
- package/src/components/Avatar/Avatar.tsx +229 -158
- package/src/components/AvatarGroup/AvatarGroup.tsx +2 -2
- package/src/components/Badge/Badge.tsx +2 -1
- package/src/components/Balance/Balance.tsx +2 -1
- package/src/components/BottomNav/BottomNav.tsx +2 -1
- package/src/components/BottomNavItem/BottomNavItem.tsx +159 -88
- package/src/components/Button/Button.tsx +228 -101
- package/src/components/ButtonGroup/ButtonGroup.tsx +2 -2
- package/src/components/Card/Card.tsx +2 -1
- package/src/components/CardCTA/CardCTA.tsx +2 -2
- package/src/components/CardProviderInfo/CardProviderInfo.tsx +2 -2
- package/src/components/Carousel/Carousel.tsx +3 -2
- package/src/components/Checkbox/Checkbox.tsx +2 -1
- package/src/components/ChipGroup/ChipGroup.tsx +2 -2
- package/src/components/ChipSelect/ChipSelect.tsx +2 -1
- package/src/components/DebitCard/DebitCard.tsx +2 -2
- package/src/components/Disclaimer/Disclaimer.tsx +2 -1
- package/src/components/Divider/Divider.tsx +2 -1
- package/src/components/Drawer/Drawer.tsx +124 -58
- package/src/components/EmptyState/EmptyState.tsx +2 -1
- package/src/components/FilterBar/FilterBar.tsx +2 -2
- package/src/components/Form/Form.tsx +2 -1
- package/src/components/FormField/FormField.tsx +3 -2
- package/src/components/HStack/HStack.tsx +2 -2
- package/src/components/HoldingsCard/HoldingsCard.tsx +2 -1
- package/src/components/IconButton/IconButton.tsx +154 -126
- package/src/components/IconCapsule/IconCapsule.tsx +73 -54
- package/src/components/InputSearch/InputSearch.tsx +19 -5
- package/src/components/LazyList/LazyList.tsx +2 -2
- package/src/components/LinearMeter/LinearMeter.tsx +3 -2
- package/src/components/ListGroup/ListGroup.tsx +2 -2
- package/src/components/ListItem/ListItem.tsx +257 -187
- package/src/components/MediaCard/MediaCard.tsx +2 -1
- package/src/components/MerchantProfile/MerchantProfile.tsx +2 -1
- package/src/components/MoneyValue/MoneyValue.tsx +2 -1
- package/src/components/NavArrow/NavArrow.tsx +91 -58
- package/src/components/NoteInput/NoteInput.tsx +2 -1
- package/src/components/Nudge/Nudge.tsx +2 -2
- package/src/components/Numpad/Numpad.tsx +2 -1
- package/src/components/OTP/OTP.tsx +2 -2
- package/src/components/PaymentFeedback/PaymentFeedback.tsx +2 -1
- package/src/components/Popup/Popup.tsx +2 -1
- package/src/components/ProductLabel/ProductLabel.tsx +2 -1
- package/src/components/ProgressBadge/ProgressBadge.tsx +2 -2
- package/src/components/RadioButton/RadioButton.tsx +2 -1
- package/src/components/RechargeCard/RechargeCard.tsx +2 -1
- package/src/components/Screen/Screen.tsx +2 -2
- package/src/components/Section/Section.tsx +672 -176
- package/src/components/SegmentedControl/SegmentedControl.tsx +3 -2
- package/src/components/StatItem/StatItem.tsx +2 -1
- package/src/components/StatusHero/StatusHero.tsx +2 -1
- package/src/components/Stepper/Step.tsx +2 -1
- package/src/components/Stepper/StepLabel.tsx +2 -1
- package/src/components/Stepper/Stepper.tsx +2 -1
- package/src/components/SupportText/SupportText.tsx +2 -1
- package/src/components/SupportText/SupportTextIcon.tsx +2 -1
- package/src/components/SwappableAmount/SwappableAmount.tsx +2 -1
- package/src/components/Tabs/TabItem.tsx +2 -1
- package/src/components/Tabs/Tabs.tsx +2 -1
- package/src/components/Text/Text.tsx +2 -1
- package/src/components/TextInput/TextInput.tsx +3 -3
- package/src/components/ThreadHero/ThreadHero.tsx +2 -1
- package/src/components/Title/Title.tsx +2 -1
- package/src/components/Toast/Toast.tsx +2 -1
- package/src/components/Toggle/Toggle.tsx +2 -1
- package/src/components/Tooltip/Tooltip.tsx +2 -1
- package/src/components/TransactionBubble/TransactionBubble.tsx +2 -2
- package/src/components/TransactionDetails/TransactionDetails.tsx +3 -3
- package/src/components/TransactionStatus/TransactionStatus.tsx +3 -2
- package/src/components/UpiHandle/UpiHandle.tsx +193 -125
- package/src/components/VStack/VStack.tsx +2 -2
- package/src/design-tokens/figma-variables-resolver.ts +21 -3
- package/src/icons/registry.ts +1 -1
- package/src/utils/react-utils.ts +16 -0
- package/lib/typescript/App.d.ts +0 -2
- package/lib/typescript/index.d.ts +0 -2
- package/lib/typescript/metro.config.d.ts +0 -78
- package/lib/typescript/react-native.config.d.ts +0 -4
|
@@ -1,158 +1,163 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import React, { useState } from 'react';
|
|
4
|
-
import { Pressable, View, Text, Image } from 'react-native';
|
|
3
|
+
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { Pressable, View, Text, Image, Platform } from 'react-native';
|
|
5
5
|
import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
|
|
6
6
|
import { useTokens } from '../../design-tokens/JFSThemeProvider';
|
|
7
|
+
import { EMPTY_MODES } from '../../utils/react-utils';
|
|
7
8
|
import Icon from '../../icons/Icon';
|
|
8
9
|
|
|
9
10
|
// Default static asset from the component folder.
|
|
10
11
|
// Consumers can override the image via the `avatarSource` prop if needed.
|
|
11
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
12
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
12
13
|
const DEFAULT_AVATAR_IMAGE = require('./Image.png');
|
|
14
|
+
const IS_WEB = Platform.OS === 'web';
|
|
15
|
+
const IS_IOS = Platform.OS === 'ios';
|
|
16
|
+
const PRESS_DELAY = IS_IOS ? 130 : 0;
|
|
17
|
+
const pressedOverlayStyle = {
|
|
18
|
+
transform: [{
|
|
19
|
+
scale: 0.98
|
|
20
|
+
}]
|
|
21
|
+
};
|
|
22
|
+
const focusOverlayStyle = {
|
|
23
|
+
borderWidth: 1,
|
|
24
|
+
borderColor: '#222'
|
|
25
|
+
};
|
|
26
|
+
function resolveUpiHandleTokens(modes) {
|
|
27
|
+
const backgroundColor = getVariableByName('upiHandle/background', modes) || '#f5f5f5';
|
|
28
|
+
const radius = getVariableByName('upiHandle/radius', modes) || 99999;
|
|
29
|
+
const paddingLeft = getVariableByName('upiHandle/padding/left', modes) || 4;
|
|
30
|
+
const paddingRight = getVariableByName('upiHandle/padding/right', modes) || 14;
|
|
31
|
+
const paddingVertical = getVariableByName('upiHandle/padding/vertical', modes) || 3;
|
|
32
|
+
const gap = getVariableByName('upiHandle/gap', modes) || 6;
|
|
33
|
+
const avatarSize = getVariableByName('upiHandle/image/size', modes) || 23;
|
|
34
|
+
const avatarRadius = getVariableByName('upiHandle/image/radius', modes) || 99999;
|
|
35
|
+
const labelColor = getVariableByName('upiHandle/label/color', modes) || '#0d0d0f';
|
|
36
|
+
const labelFontSize = getVariableByName('upiHandle/label/fontSize', modes) || 12;
|
|
37
|
+
const labelLineHeight = getVariableByName('upiHandle/label/lineHeight', modes) || 23;
|
|
38
|
+
const labelFontFamily = getVariableByName('upiHandle/label/fontFamily', modes) || 'System';
|
|
39
|
+
const labelFontWeightRaw = getVariableByName('upiHandle/label/fontWeight', modes) || 500;
|
|
40
|
+
const labelFontWeight = typeof labelFontWeightRaw === 'number' ? labelFontWeightRaw.toString() : labelFontWeightRaw;
|
|
41
|
+
const iconColor = getVariableByName('upiHandle/icon/color', modes) || '#0d0d0f';
|
|
42
|
+
const iconSize = getVariableByName('upiHandle/icon/size', modes) || 12;
|
|
43
|
+
return {
|
|
44
|
+
containerStyle: {
|
|
45
|
+
flexDirection: 'row',
|
|
46
|
+
alignItems: 'center',
|
|
47
|
+
justifyContent: 'center',
|
|
48
|
+
backgroundColor,
|
|
49
|
+
paddingLeft,
|
|
50
|
+
paddingRight,
|
|
51
|
+
paddingVertical,
|
|
52
|
+
borderRadius: radius,
|
|
53
|
+
gap
|
|
54
|
+
},
|
|
55
|
+
avatarStyle: {
|
|
56
|
+
width: avatarSize,
|
|
57
|
+
height: avatarSize,
|
|
58
|
+
borderRadius: avatarRadius,
|
|
59
|
+
overflow: 'hidden'
|
|
60
|
+
},
|
|
61
|
+
labelStyle: {
|
|
62
|
+
color: labelColor,
|
|
63
|
+
fontSize: labelFontSize,
|
|
64
|
+
lineHeight: labelLineHeight,
|
|
65
|
+
fontFamily: labelFontFamily,
|
|
66
|
+
fontWeight: labelFontWeight
|
|
67
|
+
},
|
|
68
|
+
iconColor,
|
|
69
|
+
iconSize,
|
|
70
|
+
iconPlaceholderStyle: {
|
|
71
|
+
width: iconSize,
|
|
72
|
+
height: iconSize
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
13
77
|
/**
|
|
14
78
|
* UpiHandle pill that mirrors the Figma "UPI Handle" component.
|
|
15
79
|
*
|
|
16
|
-
* Layout:
|
|
17
|
-
* - Circular image/avatar on the left
|
|
18
|
-
* - Label text in the center
|
|
19
|
-
* - Optional QR-code style icon on the right
|
|
20
|
-
*
|
|
21
|
-
* All visual styling is resolved from Figma variables via `getVariableByName`
|
|
22
|
-
* using a `modes` configuration object, matching the rest of this library.
|
|
23
|
-
*
|
|
24
80
|
* @component
|
|
25
81
|
* @param {Object} props
|
|
26
82
|
* @param {string} [props.label="Label"] - UPI handle text to display.
|
|
27
83
|
* @param {Object} [props.modes={}] - Modes object passed directly to `getVariableByName`.
|
|
28
84
|
* @param {boolean} [props.showIcon=true] - Toggles the trailing icon visibility.
|
|
29
|
-
* @param {string} [props.iconName='ic_scan_qr_code'] - Icon name from the actions set
|
|
85
|
+
* @param {string} [props.iconName='ic_scan_qr_code'] - Icon name from the actions set.
|
|
30
86
|
* @param {ImageSourcePropType} [props.avatarSource] - Optional custom image source for the avatar.
|
|
31
87
|
* @param {Function} [props.onClick] - Click/tap handler. Works as an alias for `onPress`.
|
|
32
|
-
* @param {string} [props.accessibilityLabel] - Accessibility label for screen readers
|
|
88
|
+
* @param {string} [props.accessibilityLabel] - Accessibility label for screen readers
|
|
33
89
|
* @param {string} [props.accessibilityHint] - Additional accessibility hint for screen readers
|
|
90
|
+
*
|
|
91
|
+
* Performance notes:
|
|
92
|
+
* - Token reads collapsed into a single `useMemo([modes])`.
|
|
93
|
+
* - Press visual goes through Pressable's `({ pressed })` style callback so
|
|
94
|
+
* a scroll-cancelled touch never schedules a React render. iOS gets
|
|
95
|
+
* `unstable_pressDelay={130}` for additional safety inside scrollables.
|
|
96
|
+
* - Focus state is mirrored on web only (gated setter).
|
|
97
|
+
* - Wrapped in `React.memo`.
|
|
34
98
|
*/
|
|
35
99
|
function UpiHandle({
|
|
36
100
|
label = 'Label',
|
|
37
|
-
modes: propModes =
|
|
101
|
+
modes: propModes = EMPTY_MODES,
|
|
38
102
|
showIcon = true,
|
|
39
103
|
iconName = 'ic_scan_qr_code',
|
|
40
104
|
avatarSource,
|
|
41
105
|
onPress,
|
|
42
106
|
onClick,
|
|
43
107
|
disabled,
|
|
44
|
-
accessibilityLabel
|
|
108
|
+
// accessibilityLabel is accepted on the type for API back-compat; the
|
|
109
|
+
// wrapper renders `accessibilityLabel={undefined}` because the inner Text
|
|
110
|
+
// already carries the label.
|
|
111
|
+
accessibilityLabel: _accessibilityLabel,
|
|
45
112
|
accessibilityHint,
|
|
46
113
|
...rest
|
|
47
114
|
}) {
|
|
48
115
|
const {
|
|
49
116
|
modes: globalModes
|
|
50
117
|
} = useTokens();
|
|
51
|
-
const modes = {
|
|
118
|
+
const modes = useMemo(() => globalModes === EMPTY_MODES && propModes === EMPTY_MODES ? EMPTY_MODES : {
|
|
52
119
|
...globalModes,
|
|
53
120
|
...propModes
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const backgroundColor = getVariableByName('upiHandle/background', modes) || '#f5f5f5';
|
|
57
|
-
const radius = getVariableByName('upiHandle/radius', modes) || 99999;
|
|
58
|
-
const paddingLeft = getVariableByName('upiHandle/padding/left', modes) || 4;
|
|
59
|
-
const paddingRight = getVariableByName('upiHandle/padding/right', modes) || 14;
|
|
60
|
-
const paddingVertical = getVariableByName('upiHandle/padding/vertical', modes) || 3;
|
|
61
|
-
const gap = getVariableByName('upiHandle/gap', modes) || 6;
|
|
62
|
-
|
|
63
|
-
// Avatar
|
|
64
|
-
const avatarSize = getVariableByName('upiHandle/image/size', modes) || 23;
|
|
65
|
-
const avatarRadius = getVariableByName('upiHandle/image/radius', modes) || 99999;
|
|
66
|
-
|
|
67
|
-
// Label typography
|
|
68
|
-
const labelColor = getVariableByName('upiHandle/label/color', modes) || '#0d0d0f';
|
|
69
|
-
const labelFontSize = getVariableByName('upiHandle/label/fontSize', modes) || 12;
|
|
70
|
-
const labelLineHeight = getVariableByName('upiHandle/label/lineHeight', modes) || 23;
|
|
71
|
-
const labelFontFamily = getVariableByName('upiHandle/label/fontFamily', modes) || 'System';
|
|
72
|
-
const labelFontWeightRaw = getVariableByName('upiHandle/label/fontWeight', modes) || 500;
|
|
73
|
-
const labelFontWeight = typeof labelFontWeightRaw === 'number' ? labelFontWeightRaw.toString() : labelFontWeightRaw;
|
|
121
|
+
}, [globalModes, propModes]);
|
|
122
|
+
const tokens = useMemo(() => resolveUpiHandleTokens(modes), [modes]);
|
|
74
123
|
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
const iconSize = getVariableByName('upiHandle/icon/size', modes) || 12;
|
|
78
|
-
const containerStyle = {
|
|
79
|
-
flexDirection: 'row',
|
|
80
|
-
alignItems: 'center',
|
|
81
|
-
justifyContent: 'center',
|
|
82
|
-
backgroundColor,
|
|
83
|
-
paddingLeft,
|
|
84
|
-
paddingRight,
|
|
85
|
-
paddingVertical,
|
|
86
|
-
borderRadius: radius,
|
|
87
|
-
gap
|
|
88
|
-
};
|
|
89
|
-
const avatarBaseStyle = {
|
|
90
|
-
width: avatarSize,
|
|
91
|
-
height: avatarSize,
|
|
92
|
-
borderRadius: avatarRadius,
|
|
93
|
-
overflow: 'hidden'
|
|
94
|
-
};
|
|
95
|
-
const labelBaseStyle = {
|
|
96
|
-
color: labelColor,
|
|
97
|
-
fontSize: labelFontSize,
|
|
98
|
-
lineHeight: labelLineHeight,
|
|
99
|
-
fontFamily: labelFontFamily,
|
|
100
|
-
fontWeight: labelFontWeight
|
|
101
|
-
};
|
|
102
|
-
const iconPlaceholderStyle = {
|
|
103
|
-
width: iconSize,
|
|
104
|
-
height: iconSize
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
// Use provided accessibilityLabel or fall back to label
|
|
108
|
-
const defaultAccessibilityLabel = accessibilityLabel || `UPI handle ${label}`;
|
|
109
|
-
const [isPressed, setIsPressed] = useState(false);
|
|
124
|
+
// Focus is a sustained visible state (web-only). Setter is gated so it
|
|
125
|
+
// never fires on native.
|
|
110
126
|
const [isFocused, setIsFocused] = useState(false);
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
127
|
+
const userHandlersRef = useRef({});
|
|
128
|
+
userHandlersRef.current.onPressIn = rest?.onPressIn;
|
|
129
|
+
userHandlersRef.current.onPressOut = rest?.onPressOut;
|
|
130
|
+
userHandlersRef.current.onFocus = rest?.onFocus;
|
|
131
|
+
userHandlersRef.current.onBlur = rest?.onBlur;
|
|
132
|
+
const handlePressIn = useCallback(e => {
|
|
133
|
+
userHandlersRef.current.onPressIn?.(e);
|
|
134
|
+
}, []);
|
|
135
|
+
const handlePressOut = useCallback(e => {
|
|
136
|
+
userHandlersRef.current.onPressOut?.(e);
|
|
137
|
+
}, []);
|
|
138
|
+
const handleFocus = useCallback(e => {
|
|
139
|
+
if (IS_WEB) setIsFocused(true);
|
|
140
|
+
userHandlersRef.current.onFocus?.(e);
|
|
141
|
+
}, []);
|
|
142
|
+
const handleBlur = useCallback(e => {
|
|
143
|
+
if (IS_WEB) setIsFocused(false);
|
|
144
|
+
userHandlersRef.current.onBlur?.(e);
|
|
145
|
+
}, []);
|
|
120
146
|
const handlePress = onPress || onClick;
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
accessibilityHint
|
|
128
|
-
} : {}),
|
|
129
|
-
onPress: handlePress,
|
|
130
|
-
disabled: rest?.disabled ?? disabled,
|
|
131
|
-
onPressIn: e => {
|
|
132
|
-
setIsPressed(true);
|
|
133
|
-
rest?.onPressIn?.(e);
|
|
134
|
-
},
|
|
135
|
-
onPressOut: e => {
|
|
136
|
-
setIsPressed(false);
|
|
137
|
-
rest?.onPressOut?.(e);
|
|
138
|
-
},
|
|
139
|
-
onFocus: e => {
|
|
140
|
-
setIsFocused(true);
|
|
141
|
-
rest?.onFocus?.(e);
|
|
142
|
-
},
|
|
143
|
-
onBlur: e => {
|
|
144
|
-
setIsFocused(false);
|
|
145
|
-
rest?.onBlur?.(e);
|
|
146
|
-
},
|
|
147
|
-
...rest,
|
|
147
|
+
const isPressable = !!(rest?.onPress || handlePress);
|
|
148
|
+
const pressableStyle = useCallback(({
|
|
149
|
+
pressed
|
|
150
|
+
}) => [tokens.containerStyle, pressed ? pressedOverlayStyle : null, isFocused ? focusOverlayStyle : null], [tokens.containerStyle, isFocused]);
|
|
151
|
+
const staticContainerStyle = useMemo(() => [tokens.containerStyle, isFocused ? focusOverlayStyle : null], [tokens.containerStyle, isFocused]);
|
|
152
|
+
const innerContent = /*#__PURE__*/_jsxs(_Fragment, {
|
|
148
153
|
children: [/*#__PURE__*/_jsx(Image, {
|
|
149
154
|
source: avatarSource || DEFAULT_AVATAR_IMAGE,
|
|
150
|
-
style:
|
|
155
|
+
style: tokens.avatarStyle,
|
|
151
156
|
resizeMode: "cover",
|
|
152
157
|
accessibilityElementsHidden: true,
|
|
153
158
|
importantForAccessibility: "no"
|
|
154
159
|
}), /*#__PURE__*/_jsx(Text, {
|
|
155
|
-
style:
|
|
160
|
+
style: tokens.labelStyle,
|
|
156
161
|
numberOfLines: 1,
|
|
157
162
|
ellipsizeMode: "tail",
|
|
158
163
|
accessibilityElementsHidden: true,
|
|
@@ -160,12 +165,41 @@ function UpiHandle({
|
|
|
160
165
|
children: label
|
|
161
166
|
}), showIcon && /*#__PURE__*/_jsx(Icon, {
|
|
162
167
|
name: iconName,
|
|
163
|
-
size: iconSize,
|
|
164
|
-
color: iconColor,
|
|
165
|
-
style: iconPlaceholderStyle,
|
|
168
|
+
size: tokens.iconSize,
|
|
169
|
+
color: tokens.iconColor,
|
|
170
|
+
style: tokens.iconPlaceholderStyle,
|
|
166
171
|
accessibilityElementsHidden: true,
|
|
167
172
|
importantForAccessibility: "no"
|
|
168
173
|
})]
|
|
169
174
|
});
|
|
175
|
+
if (isPressable) {
|
|
176
|
+
return /*#__PURE__*/_jsx(Pressable, {
|
|
177
|
+
style: pressableStyle,
|
|
178
|
+
accessibilityRole: "text",
|
|
179
|
+
accessibilityLabel: undefined,
|
|
180
|
+
...(accessibilityHint !== undefined ? {
|
|
181
|
+
accessibilityHint
|
|
182
|
+
} : {}),
|
|
183
|
+
onPress: handlePress,
|
|
184
|
+
disabled: rest?.disabled ?? disabled,
|
|
185
|
+
onPressIn: handlePressIn,
|
|
186
|
+
onPressOut: handlePressOut,
|
|
187
|
+
onFocus: handleFocus,
|
|
188
|
+
onBlur: handleBlur,
|
|
189
|
+
unstable_pressDelay: PRESS_DELAY,
|
|
190
|
+
...rest,
|
|
191
|
+
children: innerContent
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
return /*#__PURE__*/_jsx(View, {
|
|
195
|
+
style: staticContainerStyle,
|
|
196
|
+
accessibilityRole: "text",
|
|
197
|
+
accessibilityLabel: undefined,
|
|
198
|
+
...(accessibilityHint !== undefined ? {
|
|
199
|
+
accessibilityHint
|
|
200
|
+
} : {}),
|
|
201
|
+
...rest,
|
|
202
|
+
children: innerContent
|
|
203
|
+
});
|
|
170
204
|
}
|
|
171
|
-
export default UpiHandle;
|
|
205
|
+
export default /*#__PURE__*/React.memo(UpiHandle);
|
|
@@ -4,7 +4,7 @@ import React from 'react';
|
|
|
4
4
|
import { View } from 'react-native';
|
|
5
5
|
import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
|
|
6
6
|
import { useTokens } from '../../design-tokens/JFSThemeProvider';
|
|
7
|
-
import { cloneChildrenWithModes } from '../../utils/react-utils';
|
|
7
|
+
import { cloneChildrenWithModes, EMPTY_MODES } from '../../utils/react-utils';
|
|
8
8
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
9
9
|
/**
|
|
10
10
|
* VStack component for vertical layout using design token spacing.
|
|
@@ -16,7 +16,7 @@ export const VStack = ({
|
|
|
16
16
|
wrap,
|
|
17
17
|
reverse = false,
|
|
18
18
|
as,
|
|
19
|
-
modes: propModes =
|
|
19
|
+
modes: propModes = EMPTY_MODES,
|
|
20
20
|
style,
|
|
21
21
|
...rest
|
|
22
22
|
}) => {
|
|
@@ -187,14 +187,32 @@ function resolveVariable(variableId, modesByCollectionName = {}) {
|
|
|
187
187
|
return value;
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
// Per-object serialization cache. Most callers pass the same `modes` object
|
|
191
|
+
// many times in a single render (e.g. one Button does ~21 token lookups with
|
|
192
|
+
// the same `modes`); with a stable identity from the caller (see
|
|
193
|
+
// `EMPTY_MODES` in `utils/react-utils.ts`) this collapses to a single
|
|
194
|
+
// sort+join per modes object across the whole app.
|
|
195
|
+
const serializedModesCache = new WeakMap();
|
|
196
|
+
|
|
190
197
|
// Serialize modes object to create a stable cache key
|
|
191
198
|
function serializeModes(modes) {
|
|
192
|
-
if (!modes ||
|
|
199
|
+
if (!modes || typeof modes !== 'object') {
|
|
200
|
+
return '';
|
|
201
|
+
}
|
|
202
|
+
const cached = serializedModesCache.get(modes);
|
|
203
|
+
if (cached !== undefined) {
|
|
204
|
+
return cached;
|
|
205
|
+
}
|
|
206
|
+
const keys = Object.keys(modes);
|
|
207
|
+
if (keys.length === 0) {
|
|
208
|
+
serializedModesCache.set(modes, '');
|
|
193
209
|
return '';
|
|
194
210
|
}
|
|
195
211
|
// Sort keys for consistent serialization
|
|
196
|
-
|
|
197
|
-
|
|
212
|
+
keys.sort();
|
|
213
|
+
const result = keys.map(key => `${key}:${modes[key]}`).join('|');
|
|
214
|
+
serializedModesCache.set(modes, result);
|
|
215
|
+
return result;
|
|
198
216
|
}
|
|
199
217
|
|
|
200
218
|
// Get variable by name with dynamic mode resolution (optimized with O(1) lookup)
|