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.
- package/CHANGELOG.md +115 -6
- package/lib/commonjs/components/AccountCard/AccountCard.js +247 -0
- package/lib/commonjs/components/ActionFooter/ActionFooter.js +147 -82
- package/lib/commonjs/components/AppBar/AppBar.js +17 -11
- package/lib/commonjs/components/Avatar/Avatar.js +20 -0
- package/lib/commonjs/components/Badge/Badge.js +23 -0
- package/lib/commonjs/components/Button/Button.js +37 -0
- package/lib/commonjs/components/CardBankAccount/CardBankAccount.js +18 -2
- package/lib/commonjs/components/CheckboxItem/CheckboxItem.js +40 -25
- package/lib/commonjs/components/Dropdown/Dropdown.js +214 -0
- package/lib/commonjs/components/DropdownInput/DropdownInput.js +542 -0
- package/lib/commonjs/components/FormField/FormField.js +328 -178
- package/lib/commonjs/components/IconButton/IconButton.js +20 -0
- package/lib/commonjs/components/Image/Image.js +26 -1
- package/lib/commonjs/components/LottieIntroBlock/LottieIntroBlock.js +150 -0
- package/lib/commonjs/components/LottiePlayer/LottiePlayer.js +116 -0
- package/lib/commonjs/components/LottiePlayer/LottiePlayer.web.js +82 -0
- package/lib/commonjs/components/LottiePlayer/loadNativeLottieView.js +74 -0
- package/lib/commonjs/components/LottiePlayer/loadWebLottieView.js +50 -0
- package/lib/commonjs/components/PageHero/PageHero.js +189 -0
- package/lib/commonjs/components/PoweredByLabel/PoweredByLabel.js +135 -0
- package/lib/commonjs/components/PoweredByLabel/finvu.png +0 -0
- package/lib/commonjs/components/RechargeCard/RechargeCard.js +32 -17
- package/lib/commonjs/components/Text/Text.js +40 -3
- package/lib/commonjs/components/Tooltip/Tooltip.js +34 -27
- package/lib/commonjs/components/index.js +67 -0
- package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
- package/lib/commonjs/icons/Icon.js +16 -0
- package/lib/commonjs/icons/registry.js +1 -1
- package/lib/commonjs/index.js +12 -0
- package/lib/commonjs/skeleton/Skeleton.js +234 -0
- package/lib/commonjs/skeleton/SkeletonGroup.js +140 -0
- package/lib/commonjs/skeleton/index.js +58 -0
- package/lib/commonjs/skeleton/shimmer-tokens.js +189 -0
- package/lib/commonjs/skeleton/useReducedMotion.js +64 -0
- package/lib/module/components/AccountCard/AccountCard.js +241 -0
- package/lib/module/components/ActionFooter/ActionFooter.js +146 -82
- package/lib/module/components/AppBar/AppBar.js +17 -11
- package/lib/module/components/Avatar/Avatar.js +19 -0
- package/lib/module/components/Badge/Badge.js +23 -0
- package/lib/module/components/Button/Button.js +37 -0
- package/lib/module/components/CardBankAccount/CardBankAccount.js +17 -2
- package/lib/module/components/CheckboxItem/CheckboxItem.js +41 -26
- package/lib/module/components/Dropdown/Dropdown.js +206 -0
- package/lib/module/components/DropdownInput/DropdownInput.js +536 -0
- package/lib/module/components/FormField/FormField.js +330 -180
- package/lib/module/components/IconButton/IconButton.js +20 -0
- package/lib/module/components/Image/Image.js +25 -1
- package/lib/module/components/LottieIntroBlock/LottieIntroBlock.js +144 -0
- package/lib/module/components/LottiePlayer/LottiePlayer.js +111 -0
- package/lib/module/components/LottiePlayer/LottiePlayer.web.js +77 -0
- package/lib/module/components/LottiePlayer/loadNativeLottieView.js +69 -0
- package/lib/module/components/LottiePlayer/loadWebLottieView.js +45 -0
- package/lib/module/components/PageHero/PageHero.js +183 -0
- package/lib/module/components/PoweredByLabel/PoweredByLabel.js +130 -0
- package/lib/module/components/PoweredByLabel/finvu.png +0 -0
- package/lib/module/components/RechargeCard/RechargeCard.js +33 -17
- package/lib/module/components/Text/Text.js +40 -3
- package/lib/module/components/Tooltip/Tooltip.js +34 -27
- package/lib/module/components/index.js +8 -1
- package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
- package/lib/module/icons/Icon.js +16 -0
- package/lib/module/icons/registry.js +1 -1
- package/lib/module/index.js +2 -1
- package/lib/module/skeleton/Skeleton.js +229 -0
- package/lib/module/skeleton/SkeletonGroup.js +133 -0
- package/lib/module/skeleton/index.js +6 -0
- package/lib/module/skeleton/shimmer-tokens.js +181 -0
- package/lib/module/skeleton/useReducedMotion.js +61 -0
- package/lib/typescript/src/components/AccountCard/AccountCard.d.ts +81 -0
- package/lib/typescript/src/components/ActionFooter/ActionFooter.d.ts +26 -21
- package/lib/typescript/src/components/Avatar/Avatar.d.ts +7 -1
- package/lib/typescript/src/components/Badge/Badge.d.ts +7 -1
- package/lib/typescript/src/components/Button/Button.d.ts +8 -1
- package/lib/typescript/src/components/CardBankAccount/CardBankAccount.d.ts +9 -2
- package/lib/typescript/src/components/CheckboxItem/CheckboxItem.d.ts +18 -2
- package/lib/typescript/src/components/Dropdown/Dropdown.d.ts +62 -0
- package/lib/typescript/src/components/DropdownInput/DropdownInput.d.ts +107 -0
- package/lib/typescript/src/components/FormField/FormField.d.ts +76 -19
- package/lib/typescript/src/components/IconButton/IconButton.d.ts +7 -1
- package/lib/typescript/src/components/Image/Image.d.ts +8 -1
- package/lib/typescript/src/components/LottieIntroBlock/LottieIntroBlock.d.ts +58 -0
- package/lib/typescript/src/components/LottiePlayer/LottiePlayer.d.ts +85 -0
- package/lib/typescript/src/components/LottiePlayer/LottiePlayer.web.d.ts +28 -0
- package/lib/typescript/src/components/LottiePlayer/loadNativeLottieView.d.ts +11 -0
- package/lib/typescript/src/components/LottiePlayer/loadWebLottieView.d.ts +11 -0
- package/lib/typescript/src/components/PageHero/PageHero.d.ts +79 -0
- package/lib/typescript/src/components/PoweredByLabel/PoweredByLabel.d.ts +70 -0
- package/lib/typescript/src/components/Text/Text.d.ts +31 -2
- package/lib/typescript/src/components/Tooltip/Tooltip.d.ts +13 -2
- package/lib/typescript/src/components/index.d.ts +8 -1
- package/lib/typescript/src/icons/Icon.d.ts +7 -1
- package/lib/typescript/src/icons/registry.d.ts +1 -1
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/skeleton/Skeleton.d.ts +60 -0
- package/lib/typescript/src/skeleton/SkeletonGroup.d.ts +78 -0
- package/lib/typescript/src/skeleton/index.d.ts +5 -0
- package/lib/typescript/src/skeleton/shimmer-tokens.d.ts +160 -0
- package/lib/typescript/src/skeleton/useReducedMotion.d.ts +15 -0
- package/package.json +11 -3
- package/src/components/AccountCard/AccountCard.tsx +376 -0
- package/src/components/ActionFooter/ActionFooter.tsx +152 -86
- package/src/components/AppBar/AppBar.tsx +25 -14
- package/src/components/Avatar/Avatar.tsx +26 -0
- package/src/components/Badge/Badge.tsx +27 -0
- package/src/components/Button/Button.tsx +40 -0
- package/src/components/CardBankAccount/CardBankAccount.tsx +29 -3
- package/src/components/CheckboxItem/CheckboxItem.tsx +65 -30
- package/src/components/Dropdown/Dropdown.tsx +331 -0
- package/src/components/DropdownInput/DropdownInput.tsx +819 -0
- package/src/components/FormField/FormField.tsx +542 -215
- package/src/components/IconButton/IconButton.tsx +27 -0
- package/src/components/Image/Image.tsx +25 -0
- package/src/components/LottieIntroBlock/LottieIntroBlock.tsx +202 -0
- package/src/components/LottiePlayer/LottiePlayer.tsx +145 -0
- package/src/components/LottiePlayer/LottiePlayer.web.tsx +94 -0
- package/src/components/LottiePlayer/loadNativeLottieView.tsx +87 -0
- package/src/components/LottiePlayer/loadWebLottieView.tsx +64 -0
- package/src/components/PageHero/PageHero.tsx +257 -0
- package/src/components/PoweredByLabel/PoweredByLabel.tsx +221 -0
- package/src/components/PoweredByLabel/finvu.png +0 -0
- package/src/components/RechargeCard/RechargeCard.tsx +32 -24
- package/src/components/Text/Text.tsx +78 -3
- package/src/components/Tooltip/Tooltip.tsx +50 -25
- package/src/components/index.ts +16 -1
- package/src/design-tokens/Coin Variables-variables-full.json +1 -1
- package/src/icons/Icon.tsx +17 -0
- package/src/icons/registry.ts +1 -1
- package/src/index.ts +1 -0
- package/src/skeleton/Skeleton.tsx +298 -0
- package/src/skeleton/SkeletonGroup.tsx +193 -0
- package/src/skeleton/index.ts +10 -0
- package/src/skeleton/shimmer-tokens.ts +221 -0
- package/src/skeleton/useReducedMotion.ts +72 -0
|
@@ -4,6 +4,8 @@ import React from 'react';
|
|
|
4
4
|
import { View, Text, Pressable } from 'react-native';
|
|
5
5
|
import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
|
|
6
6
|
import { EMPTY_MODES } from '../../utils/react-utils';
|
|
7
|
+
import Skeleton from '../../skeleton/Skeleton';
|
|
8
|
+
import { useSkeleton } from '../../skeleton/SkeletonGroup';
|
|
7
9
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
8
10
|
function Badge({
|
|
9
11
|
label = 'Label',
|
|
@@ -12,6 +14,7 @@ function Badge({
|
|
|
12
14
|
accessibilityLabel,
|
|
13
15
|
style,
|
|
14
16
|
labelStyle,
|
|
17
|
+
loading,
|
|
15
18
|
...rest
|
|
16
19
|
}) {
|
|
17
20
|
// Resolve token values (fall back to sensible defaults)
|
|
@@ -24,6 +27,26 @@ function Badge({
|
|
|
24
27
|
const paddingVertical = Number(getVariableByName('badge/padding/vertical', modes)) || 4;
|
|
25
28
|
const borderRadius = Number(getVariableByName('badge/radius', modes)) || 4;
|
|
26
29
|
const lineHeight = Number(getVariableByName('badge/label/lineHeight', modes)) || Math.round(fontSize * 1.2);
|
|
30
|
+
|
|
31
|
+
// Skeleton short-circuit. Size derived from the same tokens the loaded
|
|
32
|
+
// badge would use so the placeholder occupies the same box.
|
|
33
|
+
const {
|
|
34
|
+
active: groupActive
|
|
35
|
+
} = useSkeleton();
|
|
36
|
+
const isLoading = loading ?? groupActive;
|
|
37
|
+
if (isLoading) {
|
|
38
|
+
const charWidth = fontSize * 0.55;
|
|
39
|
+
const labelWidth = Math.max(label.length, 3) * charWidth;
|
|
40
|
+
return /*#__PURE__*/_jsx(Skeleton, {
|
|
41
|
+
kind: "badge",
|
|
42
|
+
width: paddingHorizontal * 2 + labelWidth,
|
|
43
|
+
height: paddingVertical * 2 + lineHeight,
|
|
44
|
+
style: {
|
|
45
|
+
alignSelf: 'flex-start'
|
|
46
|
+
},
|
|
47
|
+
modes: modes
|
|
48
|
+
});
|
|
49
|
+
}
|
|
27
50
|
const Container = onPress ? Pressable : View;
|
|
28
51
|
const containerStyle = {
|
|
29
52
|
backgroundColor,
|
|
@@ -6,6 +6,8 @@ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
|
|
|
6
6
|
import { usePressableWebSupport } from '../../utils/web-platform-utils';
|
|
7
7
|
import { EMPTY_MODES } from '../../utils/react-utils';
|
|
8
8
|
import Icon from '../../icons/Icon';
|
|
9
|
+
import Skeleton from '../../skeleton/Skeleton';
|
|
10
|
+
import { useSkeleton } from '../../skeleton/SkeletonGroup';
|
|
9
11
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
12
|
// ---------------------------------------------------------------------------
|
|
11
13
|
// Module-scope constants — never re-allocated per render.
|
|
@@ -167,6 +169,7 @@ function ButtonImpl({
|
|
|
167
169
|
accessibilityHint,
|
|
168
170
|
accessibilityState,
|
|
169
171
|
webAccessibilityProps,
|
|
172
|
+
loading,
|
|
170
173
|
...rest
|
|
171
174
|
}) {
|
|
172
175
|
// Hover state is web-only in practice; the setter is gated so native taps
|
|
@@ -182,6 +185,14 @@ function ButtonImpl({
|
|
|
182
185
|
userHandlersRef.current.onHoverOut = rest?.onHoverOut;
|
|
183
186
|
const tokens = useMemo(() => resolveButtonTokens(modes, disabled), [modes, disabled]);
|
|
184
187
|
|
|
188
|
+
// Skeleton context — read unconditionally so React's hook order stays
|
|
189
|
+
// stable. The actual short-circuit return happens AFTER all remaining
|
|
190
|
+
// hooks have been called below.
|
|
191
|
+
const {
|
|
192
|
+
active: groupActive
|
|
193
|
+
} = useSkeleton();
|
|
194
|
+
const isLoading = loading ?? groupActive;
|
|
195
|
+
|
|
185
196
|
// Active label color: base by default; hover override (web-only) when hovered.
|
|
186
197
|
// Press color is intentionally NOT applied to the label on native — applying
|
|
187
198
|
// it would require a React render per touch and re-introduce the flicker.
|
|
@@ -259,6 +270,32 @@ function ButtonImpl({
|
|
|
259
270
|
console.warn('[Button] Custom content is used without an explicit `accessibilityLabel` or string `label`. ' + 'Screen readers may not announce this button correctly.');
|
|
260
271
|
}
|
|
261
272
|
}
|
|
273
|
+
if (isLoading) {
|
|
274
|
+
const {
|
|
275
|
+
container,
|
|
276
|
+
baseLabel,
|
|
277
|
+
iconSize,
|
|
278
|
+
accessoryOffset
|
|
279
|
+
} = tokens;
|
|
280
|
+
const paddingHorizontal = container.paddingHorizontal ?? 20;
|
|
281
|
+
const paddingVertical = container.paddingVertical ?? 12;
|
|
282
|
+
const lineHeight = baseLabel.lineHeight ?? 19;
|
|
283
|
+
const fontSize = baseLabel.fontSize ?? 16;
|
|
284
|
+
const labelText = typeof label === 'string' ? label : 'Button';
|
|
285
|
+
const charWidth = fontSize * 0.55;
|
|
286
|
+
const labelWidth = Math.max(labelText.length, 4) * charWidth;
|
|
287
|
+
const hasAccessory = !!(leading || trailing || icon);
|
|
288
|
+
const accessoryWidth = hasAccessory ? iconSize + accessoryOffset * 2 : 0;
|
|
289
|
+
const skeletonWidth = paddingHorizontal * 2 + labelWidth + accessoryWidth;
|
|
290
|
+
const skeletonHeight = paddingVertical * 2 + lineHeight;
|
|
291
|
+
return /*#__PURE__*/_jsx(Skeleton, {
|
|
292
|
+
kind: "other",
|
|
293
|
+
width: skeletonWidth,
|
|
294
|
+
height: skeletonHeight,
|
|
295
|
+
style: style,
|
|
296
|
+
modes: modes
|
|
297
|
+
});
|
|
298
|
+
}
|
|
262
299
|
return /*#__PURE__*/_jsxs(Pressable, {
|
|
263
300
|
accessibilityRole: "button",
|
|
264
301
|
accessibilityLabel: undefined,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import React from 'react';
|
|
3
|
+
import React, { useMemo } from 'react';
|
|
4
4
|
import { View, Text } from 'react-native';
|
|
5
5
|
import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
|
|
6
6
|
import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils';
|
|
@@ -18,6 +18,14 @@ const DEFAULT_ITEMS = [{
|
|
|
18
18
|
label: 'Last updated',
|
|
19
19
|
value: 'Korem ipsum'
|
|
20
20
|
}];
|
|
21
|
+
|
|
22
|
+
// Component-level defaults that match the Figma reference. Caller-provided
|
|
23
|
+
// `modes` are merged on top so every key here can be overridden per-instance.
|
|
24
|
+
const DEFAULT_MODES = Object.freeze({
|
|
25
|
+
'Button / Size': 'S',
|
|
26
|
+
AppearanceBrand: 'Secondary',
|
|
27
|
+
Emphasis: 'Medium'
|
|
28
|
+
});
|
|
21
29
|
const toNumber = (value, fallback) => {
|
|
22
30
|
if (typeof value === 'number') return Number.isFinite(value) ? value : fallback;
|
|
23
31
|
if (typeof value === 'string') {
|
|
@@ -56,10 +64,17 @@ function CardBankAccount({
|
|
|
56
64
|
buttonLabel = 'Button',
|
|
57
65
|
onButtonPress,
|
|
58
66
|
footer,
|
|
59
|
-
modes = EMPTY_MODES,
|
|
67
|
+
modes: propModes = EMPTY_MODES,
|
|
60
68
|
style,
|
|
61
69
|
accessibilityLabel
|
|
62
70
|
}) {
|
|
71
|
+
// Merge caller modes on top of `DEFAULT_MODES` so every default key
|
|
72
|
+
// (e.g. `Button / Size`, `AppearanceBrand`, `Emphasis`) can be overridden
|
|
73
|
+
// per-instance while still applying out of the box.
|
|
74
|
+
const modes = useMemo(() => propModes === EMPTY_MODES ? DEFAULT_MODES : {
|
|
75
|
+
...DEFAULT_MODES,
|
|
76
|
+
...propModes
|
|
77
|
+
}, [propModes]);
|
|
63
78
|
const background = getVariableByName('bankAccountCard/background', modes) ?? '#ffffff';
|
|
64
79
|
const radius = toNumber(getVariableByName('bankAccountCard/radius', modes), 16);
|
|
65
80
|
const paddingHorizontal = toNumber(getVariableByName('bankAccountCard/padding/horizontal', modes), 12);
|
|
@@ -5,12 +5,15 @@ import { View, Text, Pressable } from 'react-native';
|
|
|
5
5
|
import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
|
|
6
6
|
import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils';
|
|
7
7
|
import Checkbox from '../Checkbox/Checkbox';
|
|
8
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
9
9
|
/**
|
|
10
10
|
* CheckboxItem composes a `Checkbox`, a label and an optional `endSlot` into a
|
|
11
11
|
* single horizontal pressable row. Pressing anywhere on the row (outside of the
|
|
12
12
|
* `endSlot`) toggles the checkbox, mirroring the typical native form pattern.
|
|
13
13
|
*
|
|
14
|
+
* Use the `control` prop to swap the checkbox between the leading (left, default)
|
|
15
|
+
* and trailing (right) edge of the row. The `endSlot` flips to the opposite edge.
|
|
16
|
+
*
|
|
14
17
|
* Mirrors the Figma "Checkbox Item" component and uses the `checkboxItem/*`
|
|
15
18
|
* design tokens for typography and spacing.
|
|
16
19
|
*
|
|
@@ -25,6 +28,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
25
28
|
* label="Fixed deposit • 0245"
|
|
26
29
|
* checked={checked}
|
|
27
30
|
* onValueChange={setChecked}
|
|
31
|
+
* control="leading"
|
|
28
32
|
* modes={{ 'Color Mode': 'Light' }}
|
|
29
33
|
* />
|
|
30
34
|
* ```
|
|
@@ -35,6 +39,7 @@ function CheckboxItem({
|
|
|
35
39
|
onValueChange,
|
|
36
40
|
disabled = false,
|
|
37
41
|
label = 'Fixed deposit • 0245',
|
|
42
|
+
control = 'leading',
|
|
38
43
|
endSlot,
|
|
39
44
|
endSlotWidth = 80,
|
|
40
45
|
modes = EMPTY_MODES,
|
|
@@ -42,6 +47,7 @@ function CheckboxItem({
|
|
|
42
47
|
labelStyle,
|
|
43
48
|
accessibilityLabel
|
|
44
49
|
}) {
|
|
50
|
+
const isTrailing = control === 'trailing';
|
|
45
51
|
const isControlled = controlledChecked !== undefined;
|
|
46
52
|
const [internalChecked, setInternalChecked] = useState(defaultChecked);
|
|
47
53
|
const isChecked = isControlled ? controlledChecked : internalChecked;
|
|
@@ -80,7 +86,35 @@ function CheckboxItem({
|
|
|
80
86
|
fontWeight: labelFontWeight
|
|
81
87
|
};
|
|
82
88
|
const a11yLabel = accessibilityLabel ?? (typeof label === 'string' ? label : undefined);
|
|
83
|
-
|
|
89
|
+
const checkboxNode = /*#__PURE__*/_jsx(Checkbox, {
|
|
90
|
+
checked: isChecked,
|
|
91
|
+
disabled: disabled,
|
|
92
|
+
onValueChange: handleToggle,
|
|
93
|
+
modes: modes,
|
|
94
|
+
...(a11yLabel !== undefined ? {
|
|
95
|
+
accessibilityLabel: a11yLabel
|
|
96
|
+
} : {})
|
|
97
|
+
});
|
|
98
|
+
const labelNode = label != null && label !== false ? typeof label === 'string' || typeof label === 'number' ? /*#__PURE__*/_jsx(Text, {
|
|
99
|
+
style: [resolvedLabelStyle, labelStyle],
|
|
100
|
+
selectable: false,
|
|
101
|
+
children: label
|
|
102
|
+
}) : /*#__PURE__*/_jsx(View, {
|
|
103
|
+
style: {
|
|
104
|
+
flex: 1,
|
|
105
|
+
minWidth: 0
|
|
106
|
+
},
|
|
107
|
+
children: label
|
|
108
|
+
}) : null;
|
|
109
|
+
const endSlotNode = endSlot ? /*#__PURE__*/_jsx(View, {
|
|
110
|
+
style: {
|
|
111
|
+
width: endSlotWidth,
|
|
112
|
+
flexShrink: 0,
|
|
113
|
+
alignItems: 'stretch'
|
|
114
|
+
},
|
|
115
|
+
children: cloneChildrenWithModes(endSlot, modes)
|
|
116
|
+
}) : null;
|
|
117
|
+
return /*#__PURE__*/_jsx(Pressable, {
|
|
84
118
|
style: [containerStyle, style],
|
|
85
119
|
onPress: handleToggle,
|
|
86
120
|
disabled: disabled,
|
|
@@ -90,30 +124,11 @@ function CheckboxItem({
|
|
|
90
124
|
disabled
|
|
91
125
|
},
|
|
92
126
|
accessibilityLabel: a11yLabel,
|
|
93
|
-
children:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
accessibilityLabel: a11yLabel
|
|
99
|
-
}), label != null && label !== false ? typeof label === 'string' || typeof label === 'number' ? /*#__PURE__*/_jsx(Text, {
|
|
100
|
-
style: [resolvedLabelStyle, labelStyle],
|
|
101
|
-
selectable: false,
|
|
102
|
-
children: label
|
|
103
|
-
}) : /*#__PURE__*/_jsx(View, {
|
|
104
|
-
style: {
|
|
105
|
-
flex: 1,
|
|
106
|
-
minWidth: 0
|
|
107
|
-
},
|
|
108
|
-
children: label
|
|
109
|
-
}) : null, endSlot ? /*#__PURE__*/_jsx(View, {
|
|
110
|
-
style: {
|
|
111
|
-
width: endSlotWidth,
|
|
112
|
-
flexShrink: 0,
|
|
113
|
-
alignItems: 'stretch'
|
|
114
|
-
},
|
|
115
|
-
children: cloneChildrenWithModes(endSlot, modes)
|
|
116
|
-
}) : null]
|
|
127
|
+
children: isTrailing ? /*#__PURE__*/_jsxs(_Fragment, {
|
|
128
|
+
children: [endSlotNode, labelNode, checkboxNode]
|
|
129
|
+
}) : /*#__PURE__*/_jsxs(_Fragment, {
|
|
130
|
+
children: [checkboxNode, labelNode, endSlotNode]
|
|
131
|
+
})
|
|
117
132
|
});
|
|
118
133
|
}
|
|
119
134
|
export default CheckboxItem;
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React, { useCallback, useMemo, useState } from 'react';
|
|
4
|
+
import { Platform, Pressable, ScrollView, Text, View } from 'react-native';
|
|
5
|
+
import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
|
|
6
|
+
import { useTokens } from '../../design-tokens/JFSThemeProvider';
|
|
7
|
+
import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils';
|
|
8
|
+
import Icon from '../../icons/Icon';
|
|
9
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
|
+
const IS_WEB = Platform.OS === 'web';
|
|
11
|
+
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// DropdownItem
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
function useDropdownItemTokens(modes) {
|
|
17
|
+
return useMemo(() => {
|
|
18
|
+
// The `dropdownItem/background` token aliases through the
|
|
19
|
+
// `Dropdown Item State` collection (Idle | Selected), so we resolve
|
|
20
|
+
// both possibilities up-front and pick at render time.
|
|
21
|
+
const idleBackground = getVariableByName('dropdownItem/background', {
|
|
22
|
+
...modes,
|
|
23
|
+
'Dropdown Item State': 'Idle'
|
|
24
|
+
}) || '#ffffff';
|
|
25
|
+
const selectedBackground = getVariableByName('dropdownItem/background', {
|
|
26
|
+
...modes,
|
|
27
|
+
'Dropdown Item State': 'Selected'
|
|
28
|
+
}) || '#f5f5f5';
|
|
29
|
+
const foreground = getVariableByName('dropdownItem/foreground', modes) || '#000000';
|
|
30
|
+
const fontFamily = getVariableByName('dropdownItem/fontFamily', modes) || 'JioType Var';
|
|
31
|
+
const fontSize = parseInt(getVariableByName('dropdownItem/fontSize', modes), 10) || 16;
|
|
32
|
+
const fontWeight = getVariableByName('dropdownItem/fontWeight', modes) || '400';
|
|
33
|
+
const lineHeight = parseInt(getVariableByName('dropdownItem/lineHeight', modes), 10) || 19;
|
|
34
|
+
const gap = parseInt(getVariableByName('dropdownItem/gap', modes), 10) || 8;
|
|
35
|
+
const paddingHorizontal = parseInt(getVariableByName('dropdownItem/padding/horizontal', modes), 10) || 12;
|
|
36
|
+
const paddingVertical = parseInt(getVariableByName('dropdownItem/padding/vertical', modes), 10) || 12;
|
|
37
|
+
return {
|
|
38
|
+
idleBackground,
|
|
39
|
+
selectedBackground,
|
|
40
|
+
foreground,
|
|
41
|
+
fontFamily,
|
|
42
|
+
fontSize,
|
|
43
|
+
fontWeight,
|
|
44
|
+
lineHeight,
|
|
45
|
+
gap,
|
|
46
|
+
paddingHorizontal,
|
|
47
|
+
paddingVertical
|
|
48
|
+
};
|
|
49
|
+
}, [modes]);
|
|
50
|
+
}
|
|
51
|
+
export function DropdownItem({
|
|
52
|
+
label,
|
|
53
|
+
value = null,
|
|
54
|
+
selected = false,
|
|
55
|
+
disabled = false,
|
|
56
|
+
leading,
|
|
57
|
+
trailing,
|
|
58
|
+
onPress,
|
|
59
|
+
children,
|
|
60
|
+
modes: propModes = EMPTY_MODES,
|
|
61
|
+
style,
|
|
62
|
+
labelStyle,
|
|
63
|
+
accessibilityLabel,
|
|
64
|
+
accessibilityHint
|
|
65
|
+
}) {
|
|
66
|
+
const {
|
|
67
|
+
modes: globalModes
|
|
68
|
+
} = useTokens();
|
|
69
|
+
const modes = useMemo(() => ({
|
|
70
|
+
...globalModes,
|
|
71
|
+
...propModes
|
|
72
|
+
}), [globalModes, propModes]);
|
|
73
|
+
const tokens = useDropdownItemTokens(modes);
|
|
74
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
75
|
+
const handlePress = useCallback(() => {
|
|
76
|
+
if (disabled) return;
|
|
77
|
+
onPress?.(value);
|
|
78
|
+
}, [disabled, onPress, value]);
|
|
79
|
+
const containerStyle = useCallback(({
|
|
80
|
+
pressed
|
|
81
|
+
}) => {
|
|
82
|
+
const showSelected = pressed || isHovered && IS_WEB || selected;
|
|
83
|
+
const base = {
|
|
84
|
+
flexDirection: 'row',
|
|
85
|
+
alignItems: 'center',
|
|
86
|
+
gap: tokens.gap,
|
|
87
|
+
paddingHorizontal: tokens.paddingHorizontal,
|
|
88
|
+
paddingVertical: tokens.paddingVertical,
|
|
89
|
+
backgroundColor: showSelected ? tokens.selectedBackground : tokens.idleBackground,
|
|
90
|
+
opacity: disabled ? 0.4 : 1,
|
|
91
|
+
width: '100%'
|
|
92
|
+
};
|
|
93
|
+
return [base, style];
|
|
94
|
+
}, [tokens.gap, tokens.paddingHorizontal, tokens.paddingVertical, tokens.idleBackground, tokens.selectedBackground, isHovered, selected, disabled, style]);
|
|
95
|
+
const textStyle = {
|
|
96
|
+
color: tokens.foreground,
|
|
97
|
+
fontFamily: tokens.fontFamily,
|
|
98
|
+
fontSize: tokens.fontSize,
|
|
99
|
+
fontWeight: tokens.fontWeight,
|
|
100
|
+
lineHeight: tokens.lineHeight,
|
|
101
|
+
flexShrink: 1
|
|
102
|
+
};
|
|
103
|
+
const processedLeading = leading ? cloneChildrenWithModes(React.Children.toArray(leading), modes) : null;
|
|
104
|
+
const customTrailing = trailing ? cloneChildrenWithModes(React.Children.toArray(trailing), modes) : null;
|
|
105
|
+
const showDefaultCheck = !trailing && selected;
|
|
106
|
+
const fallbackA11yLabel = accessibilityLabel || (typeof label === 'string' ? label : 'Dropdown item');
|
|
107
|
+
const a11yProps = {
|
|
108
|
+
accessibilityRole: 'menuitem',
|
|
109
|
+
accessibilityLabel: fallbackA11yLabel,
|
|
110
|
+
accessibilityState: {
|
|
111
|
+
selected,
|
|
112
|
+
disabled
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
if (accessibilityHint) {
|
|
116
|
+
a11yProps.accessibilityHint = accessibilityHint;
|
|
117
|
+
}
|
|
118
|
+
const handleHoverIn = useCallback(() => {
|
|
119
|
+
if (IS_WEB && !disabled) setIsHovered(true);
|
|
120
|
+
}, [disabled]);
|
|
121
|
+
const handleHoverOut = useCallback(() => {
|
|
122
|
+
if (IS_WEB) setIsHovered(false);
|
|
123
|
+
}, []);
|
|
124
|
+
return /*#__PURE__*/_jsxs(Pressable, {
|
|
125
|
+
onPress: handlePress,
|
|
126
|
+
disabled: disabled,
|
|
127
|
+
onHoverIn: handleHoverIn,
|
|
128
|
+
onHoverOut: handleHoverOut,
|
|
129
|
+
style: containerStyle,
|
|
130
|
+
...a11yProps,
|
|
131
|
+
children: [processedLeading, children != null ? children : /*#__PURE__*/_jsx(Text, {
|
|
132
|
+
style: [textStyle, labelStyle],
|
|
133
|
+
numberOfLines: 1,
|
|
134
|
+
children: label
|
|
135
|
+
}), customTrailing, showDefaultCheck && /*#__PURE__*/_jsx(Icon, {
|
|
136
|
+
name: "ic_confirm",
|
|
137
|
+
size: 16,
|
|
138
|
+
color: tokens.foreground
|
|
139
|
+
})]
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
// Dropdown (popup surface)
|
|
145
|
+
// ---------------------------------------------------------------------------
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* `Dropdown` is the visual surface (popup) that contains a list of
|
|
149
|
+
* `DropdownItem`s. It is responsible for the background, rounded corners,
|
|
150
|
+
* elevation/shadow, and clipping. Use it standalone for menu UIs, or rely on
|
|
151
|
+
* `DropdownInput` which composes it into a form-field experience.
|
|
152
|
+
*/
|
|
153
|
+
export function Dropdown({
|
|
154
|
+
children,
|
|
155
|
+
maxHeight,
|
|
156
|
+
modes: propModes = EMPTY_MODES,
|
|
157
|
+
style,
|
|
158
|
+
accessibilityLabel
|
|
159
|
+
}) {
|
|
160
|
+
const {
|
|
161
|
+
modes: globalModes
|
|
162
|
+
} = useTokens();
|
|
163
|
+
const modes = useMemo(() => ({
|
|
164
|
+
...globalModes,
|
|
165
|
+
...propModes
|
|
166
|
+
}), [globalModes, propModes]);
|
|
167
|
+
const radius = parseInt(getVariableByName('dropdown/radius', modes), 10) || 8;
|
|
168
|
+
const background = getVariableByName('dropdown/background', modes) || '#ffffff';
|
|
169
|
+
const shadowColor = getVariableByName('dropdown/shadow/color', modes) || 'rgba(0, 0, 0, 0.08)';
|
|
170
|
+
const shadowOffsetX = parseInt(getVariableByName('dropdown/shadow/offsetX', modes), 10) || 0;
|
|
171
|
+
const shadowOffsetY = parseInt(getVariableByName('dropdown/shadow/offsetY', modes), 10) || 4;
|
|
172
|
+
const shadowBlur = parseInt(getVariableByName('dropdown/shadow/blur', modes), 10) || 16;
|
|
173
|
+
const containerStyle = {
|
|
174
|
+
backgroundColor: background,
|
|
175
|
+
borderRadius: radius,
|
|
176
|
+
overflow: 'hidden',
|
|
177
|
+
shadowColor,
|
|
178
|
+
shadowOffset: {
|
|
179
|
+
width: shadowOffsetX,
|
|
180
|
+
height: shadowOffsetY
|
|
181
|
+
},
|
|
182
|
+
shadowOpacity: 1,
|
|
183
|
+
shadowRadius: shadowBlur / 2,
|
|
184
|
+
elevation: 4
|
|
185
|
+
};
|
|
186
|
+
const content = /*#__PURE__*/_jsx(View, {
|
|
187
|
+
style: {
|
|
188
|
+
flexDirection: 'column'
|
|
189
|
+
},
|
|
190
|
+
children: cloneChildrenWithModes(children, modes)
|
|
191
|
+
});
|
|
192
|
+
return /*#__PURE__*/_jsx(View, {
|
|
193
|
+
style: [containerStyle, style],
|
|
194
|
+
accessibilityRole: "menu",
|
|
195
|
+
accessibilityLabel: accessibilityLabel || 'Dropdown menu',
|
|
196
|
+
children: maxHeight != null ? /*#__PURE__*/_jsx(ScrollView, {
|
|
197
|
+
style: {
|
|
198
|
+
maxHeight
|
|
199
|
+
},
|
|
200
|
+
showsVerticalScrollIndicator: true,
|
|
201
|
+
keyboardShouldPersistTaps: "handled",
|
|
202
|
+
children: content
|
|
203
|
+
}) : content
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
export default Dropdown;
|