jfs-components 0.0.73 → 0.0.77

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/CHANGELOG.md +115 -6
  2. package/lib/commonjs/components/AccountCard/AccountCard.js +247 -0
  3. package/lib/commonjs/components/ActionFooter/ActionFooter.js +147 -82
  4. package/lib/commonjs/components/AppBar/AppBar.js +17 -11
  5. package/lib/commonjs/components/Avatar/Avatar.js +20 -0
  6. package/lib/commonjs/components/Badge/Badge.js +23 -0
  7. package/lib/commonjs/components/Button/Button.js +37 -0
  8. package/lib/commonjs/components/CardBankAccount/CardBankAccount.js +18 -2
  9. package/lib/commonjs/components/CheckboxItem/CheckboxItem.js +40 -25
  10. package/lib/commonjs/components/Dropdown/Dropdown.js +214 -0
  11. package/lib/commonjs/components/DropdownInput/DropdownInput.js +542 -0
  12. package/lib/commonjs/components/FormField/FormField.js +328 -178
  13. package/lib/commonjs/components/IconButton/IconButton.js +20 -0
  14. package/lib/commonjs/components/Image/Image.js +26 -1
  15. package/lib/commonjs/components/LottieIntroBlock/LottieIntroBlock.js +150 -0
  16. package/lib/commonjs/components/LottiePlayer/LottiePlayer.js +116 -0
  17. package/lib/commonjs/components/LottiePlayer/LottiePlayer.web.js +82 -0
  18. package/lib/commonjs/components/LottiePlayer/loadNativeLottieView.js +74 -0
  19. package/lib/commonjs/components/LottiePlayer/loadWebLottieView.js +50 -0
  20. package/lib/commonjs/components/PageHero/PageHero.js +189 -0
  21. package/lib/commonjs/components/PoweredByLabel/PoweredByLabel.js +135 -0
  22. package/lib/commonjs/components/PoweredByLabel/finvu.png +0 -0
  23. package/lib/commonjs/components/RechargeCard/RechargeCard.js +32 -17
  24. package/lib/commonjs/components/Text/Text.js +40 -3
  25. package/lib/commonjs/components/Tooltip/Tooltip.js +34 -27
  26. package/lib/commonjs/components/index.js +67 -0
  27. package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
  28. package/lib/commonjs/icons/Icon.js +16 -0
  29. package/lib/commonjs/icons/registry.js +1 -1
  30. package/lib/commonjs/index.js +12 -0
  31. package/lib/commonjs/skeleton/Skeleton.js +234 -0
  32. package/lib/commonjs/skeleton/SkeletonGroup.js +140 -0
  33. package/lib/commonjs/skeleton/index.js +58 -0
  34. package/lib/commonjs/skeleton/shimmer-tokens.js +189 -0
  35. package/lib/commonjs/skeleton/useReducedMotion.js +64 -0
  36. package/lib/module/components/AccountCard/AccountCard.js +241 -0
  37. package/lib/module/components/ActionFooter/ActionFooter.js +146 -82
  38. package/lib/module/components/AppBar/AppBar.js +17 -11
  39. package/lib/module/components/Avatar/Avatar.js +19 -0
  40. package/lib/module/components/Badge/Badge.js +23 -0
  41. package/lib/module/components/Button/Button.js +37 -0
  42. package/lib/module/components/CardBankAccount/CardBankAccount.js +17 -2
  43. package/lib/module/components/CheckboxItem/CheckboxItem.js +41 -26
  44. package/lib/module/components/Dropdown/Dropdown.js +206 -0
  45. package/lib/module/components/DropdownInput/DropdownInput.js +536 -0
  46. package/lib/module/components/FormField/FormField.js +330 -180
  47. package/lib/module/components/IconButton/IconButton.js +20 -0
  48. package/lib/module/components/Image/Image.js +25 -1
  49. package/lib/module/components/LottieIntroBlock/LottieIntroBlock.js +144 -0
  50. package/lib/module/components/LottiePlayer/LottiePlayer.js +111 -0
  51. package/lib/module/components/LottiePlayer/LottiePlayer.web.js +77 -0
  52. package/lib/module/components/LottiePlayer/loadNativeLottieView.js +69 -0
  53. package/lib/module/components/LottiePlayer/loadWebLottieView.js +45 -0
  54. package/lib/module/components/PageHero/PageHero.js +183 -0
  55. package/lib/module/components/PoweredByLabel/PoweredByLabel.js +130 -0
  56. package/lib/module/components/PoweredByLabel/finvu.png +0 -0
  57. package/lib/module/components/RechargeCard/RechargeCard.js +33 -17
  58. package/lib/module/components/Text/Text.js +40 -3
  59. package/lib/module/components/Tooltip/Tooltip.js +34 -27
  60. package/lib/module/components/index.js +8 -1
  61. package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
  62. package/lib/module/icons/Icon.js +16 -0
  63. package/lib/module/icons/registry.js +1 -1
  64. package/lib/module/index.js +2 -1
  65. package/lib/module/skeleton/Skeleton.js +229 -0
  66. package/lib/module/skeleton/SkeletonGroup.js +133 -0
  67. package/lib/module/skeleton/index.js +6 -0
  68. package/lib/module/skeleton/shimmer-tokens.js +181 -0
  69. package/lib/module/skeleton/useReducedMotion.js +61 -0
  70. package/lib/typescript/src/components/AccountCard/AccountCard.d.ts +81 -0
  71. package/lib/typescript/src/components/ActionFooter/ActionFooter.d.ts +26 -21
  72. package/lib/typescript/src/components/Avatar/Avatar.d.ts +7 -1
  73. package/lib/typescript/src/components/Badge/Badge.d.ts +7 -1
  74. package/lib/typescript/src/components/Button/Button.d.ts +8 -1
  75. package/lib/typescript/src/components/CardBankAccount/CardBankAccount.d.ts +9 -2
  76. package/lib/typescript/src/components/CheckboxItem/CheckboxItem.d.ts +18 -2
  77. package/lib/typescript/src/components/Dropdown/Dropdown.d.ts +62 -0
  78. package/lib/typescript/src/components/DropdownInput/DropdownInput.d.ts +107 -0
  79. package/lib/typescript/src/components/FormField/FormField.d.ts +76 -19
  80. package/lib/typescript/src/components/IconButton/IconButton.d.ts +7 -1
  81. package/lib/typescript/src/components/Image/Image.d.ts +8 -1
  82. package/lib/typescript/src/components/LottieIntroBlock/LottieIntroBlock.d.ts +58 -0
  83. package/lib/typescript/src/components/LottiePlayer/LottiePlayer.d.ts +85 -0
  84. package/lib/typescript/src/components/LottiePlayer/LottiePlayer.web.d.ts +28 -0
  85. package/lib/typescript/src/components/LottiePlayer/loadNativeLottieView.d.ts +11 -0
  86. package/lib/typescript/src/components/LottiePlayer/loadWebLottieView.d.ts +11 -0
  87. package/lib/typescript/src/components/PageHero/PageHero.d.ts +79 -0
  88. package/lib/typescript/src/components/PoweredByLabel/PoweredByLabel.d.ts +70 -0
  89. package/lib/typescript/src/components/Text/Text.d.ts +31 -2
  90. package/lib/typescript/src/components/Tooltip/Tooltip.d.ts +13 -2
  91. package/lib/typescript/src/components/index.d.ts +8 -1
  92. package/lib/typescript/src/icons/Icon.d.ts +7 -1
  93. package/lib/typescript/src/icons/registry.d.ts +1 -1
  94. package/lib/typescript/src/index.d.ts +1 -0
  95. package/lib/typescript/src/skeleton/Skeleton.d.ts +60 -0
  96. package/lib/typescript/src/skeleton/SkeletonGroup.d.ts +78 -0
  97. package/lib/typescript/src/skeleton/index.d.ts +5 -0
  98. package/lib/typescript/src/skeleton/shimmer-tokens.d.ts +160 -0
  99. package/lib/typescript/src/skeleton/useReducedMotion.d.ts +15 -0
  100. package/package.json +11 -3
  101. package/src/components/AccountCard/AccountCard.tsx +376 -0
  102. package/src/components/ActionFooter/ActionFooter.tsx +152 -86
  103. package/src/components/AppBar/AppBar.tsx +25 -14
  104. package/src/components/Avatar/Avatar.tsx +26 -0
  105. package/src/components/Badge/Badge.tsx +27 -0
  106. package/src/components/Button/Button.tsx +40 -0
  107. package/src/components/CardBankAccount/CardBankAccount.tsx +29 -3
  108. package/src/components/CheckboxItem/CheckboxItem.tsx +65 -30
  109. package/src/components/Dropdown/Dropdown.tsx +331 -0
  110. package/src/components/DropdownInput/DropdownInput.tsx +819 -0
  111. package/src/components/FormField/FormField.tsx +542 -215
  112. package/src/components/IconButton/IconButton.tsx +27 -0
  113. package/src/components/Image/Image.tsx +25 -0
  114. package/src/components/LottieIntroBlock/LottieIntroBlock.tsx +202 -0
  115. package/src/components/LottiePlayer/LottiePlayer.tsx +145 -0
  116. package/src/components/LottiePlayer/LottiePlayer.web.tsx +94 -0
  117. package/src/components/LottiePlayer/loadNativeLottieView.tsx +87 -0
  118. package/src/components/LottiePlayer/loadWebLottieView.tsx +64 -0
  119. package/src/components/PageHero/PageHero.tsx +257 -0
  120. package/src/components/PoweredByLabel/PoweredByLabel.tsx +221 -0
  121. package/src/components/PoweredByLabel/finvu.png +0 -0
  122. package/src/components/RechargeCard/RechargeCard.tsx +32 -24
  123. package/src/components/Text/Text.tsx +78 -3
  124. package/src/components/Tooltip/Tooltip.tsx +50 -25
  125. package/src/components/index.ts +16 -1
  126. package/src/design-tokens/Coin Variables-variables-full.json +1 -1
  127. package/src/icons/Icon.tsx +17 -0
  128. package/src/icons/registry.ts +1 -1
  129. package/src/index.ts +1 -0
  130. package/src/skeleton/Skeleton.tsx +298 -0
  131. package/src/skeleton/SkeletonGroup.tsx +193 -0
  132. package/src/skeleton/index.ts +10 -0
  133. package/src/skeleton/shimmer-tokens.ts +221 -0
  134. package/src/skeleton/useReducedMotion.ts +72 -0
@@ -47,12 +47,13 @@ function AppBar({
47
47
  const containerStyle = {
48
48
  flexDirection: 'row',
49
49
  alignItems: 'center',
50
- justifyContent: 'space-between',
50
+ // No `justifyContent` here: with the inline middle slot using `flex: 1`
51
+ // the three sections lay out naturally (leading | middle | actions).
52
+ // When middleSlot is absent we fall back to `space-between` at the wrapper
53
+ // level so leading & actions still anchor to the edges.
51
54
  paddingHorizontal: paddingHorizontal ?? 16,
52
55
  paddingVertical: paddingVertical ?? (isMain ? 16 : 10),
53
56
  backgroundColor: backgroundColor ?? '#FFFFFF'
54
- // We can set minHeight if we want to enforce consistency, but padding should dictate it mostly.
55
- // Figma shows specific heights implicitly via padding + content.
56
57
  // MainPage: h=68 (16 top/bot padding? 36 height content?)
57
58
  // SubPage: h=52
58
59
  };
@@ -115,8 +116,17 @@ function AppBar({
115
116
  style: actionsStyle,
116
117
  children: (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(actionsSlot), modes)
117
118
  }) : null;
119
+
120
+ // When there is no middleSlot we want leading & actions pinned to the
121
+ // outer edges, so we apply `space-between` at the wrapper. With a middle
122
+ // slot present, the middle (flex: 1) absorbs the remaining space, so
123
+ // `space-between` is a no-op.
124
+ const wrapperStyle = {
125
+ ...containerStyle,
126
+ justifyContent: processedMiddle ? 'flex-start' : 'space-between'
127
+ };
118
128
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
119
- style: [containerStyle, style],
129
+ style: [wrapperStyle, style],
120
130
  accessibilityRole: "header",
121
131
  accessibilityLabel: undefined,
122
132
  ...(accessibilityHint ? {
@@ -131,15 +141,11 @@ function AppBar({
131
141
  children: processedLeading
132
142
  }), processedMiddle && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
133
143
  style: {
134
- position: 'absolute',
135
- left: 0,
136
- right: 0,
137
- top: 0,
138
- bottom: 0,
144
+ flex: 1,
145
+ minWidth: 0,
139
146
  alignItems: 'center',
140
147
  justifyContent: 'center',
141
- zIndex: -1 // Behind actions if overlap? Or should be on top?
142
- // Usually middle title shouldn't block actions. `pointerEvents="box-none"` is safer.
148
+ paddingHorizontal: 8
143
149
  },
144
150
  pointerEvents: "box-none",
145
151
  children: processedMiddle
@@ -8,7 +8,10 @@ var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
10
10
  var _reactUtils = require("../../utils/react-utils");
11
+ var _Skeleton = _interopRequireDefault(require("../../skeleton/Skeleton"));
12
+ var _SkeletonGroup = require("../../skeleton/SkeletonGroup");
11
13
  var _jsxRuntime = require("react/jsx-runtime");
14
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
15
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
13
16
  const avatarImage = require('./31595e70c4181263f9971590224b12934b280c9b.png');
14
17
 
@@ -128,11 +131,19 @@ function Avatar({
128
131
  // component intentionally renders `accessibilityLabel={undefined}` on the
129
132
  // wrapper (the inner Text/Image carry the label instead).
130
133
  accessibilityLabel: _accessibilityLabel,
134
+ loading,
131
135
  ...rest
132
136
  }) {
133
137
  const isMonogram = style === 'Monogram';
134
138
  const tokens = (0, _react.useMemo)(() => resolveAvatarTokens(modes, isMonogram), [modes, isMonogram]);
135
139
 
140
+ // Skeleton context — read unconditionally; the actual short-circuit
141
+ // happens AFTER all remaining hooks below.
142
+ const {
143
+ active: groupActive
144
+ } = (0, _SkeletonGroup.useSkeleton)();
145
+ const isLoading = loading ?? groupActive;
146
+
136
147
  // Focus is a sustained visible state — keep mirroring on web; gate the
137
148
  // setter so it never fires on native (where focus events don't fire on
138
149
  // these elements anyway).
@@ -163,6 +174,15 @@ function Avatar({
163
174
  pressed
164
175
  }) => [tokens.containerStyle, pressed ? pressedOverlayStyle : null, isFocused ? focusOverlayStyle : null], [tokens.containerStyle, isFocused]);
165
176
  const staticContainerStyle = (0, _react.useMemo)(() => [tokens.containerStyle, isFocused ? focusOverlayStyle : null], [tokens.containerStyle, isFocused]);
177
+ if (isLoading) {
178
+ const size = tokens.containerStyle.width;
179
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Skeleton.default, {
180
+ kind: "other",
181
+ width: size,
182
+ height: size,
183
+ modes: modes
184
+ });
185
+ }
166
186
 
167
187
  // The inner content varies; everything else (wrapper, handlers, style) is shared.
168
188
  const innerContent = isMonogram ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
@@ -8,6 +8,8 @@ var _react = _interopRequireDefault(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
10
10
  var _reactUtils = require("../../utils/react-utils");
11
+ var _Skeleton = _interopRequireDefault(require("../../skeleton/Skeleton"));
12
+ var _SkeletonGroup = require("../../skeleton/SkeletonGroup");
11
13
  var _jsxRuntime = require("react/jsx-runtime");
12
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
15
  function Badge({
@@ -17,6 +19,7 @@ function Badge({
17
19
  accessibilityLabel,
18
20
  style,
19
21
  labelStyle,
22
+ loading,
20
23
  ...rest
21
24
  }) {
22
25
  // Resolve token values (fall back to sensible defaults)
@@ -29,6 +32,26 @@ function Badge({
29
32
  const paddingVertical = Number((0, _figmaVariablesResolver.getVariableByName)('badge/padding/vertical', modes)) || 4;
30
33
  const borderRadius = Number((0, _figmaVariablesResolver.getVariableByName)('badge/radius', modes)) || 4;
31
34
  const lineHeight = Number((0, _figmaVariablesResolver.getVariableByName)('badge/label/lineHeight', modes)) || Math.round(fontSize * 1.2);
35
+
36
+ // Skeleton short-circuit. Size derived from the same tokens the loaded
37
+ // badge would use so the placeholder occupies the same box.
38
+ const {
39
+ active: groupActive
40
+ } = (0, _SkeletonGroup.useSkeleton)();
41
+ const isLoading = loading ?? groupActive;
42
+ if (isLoading) {
43
+ const charWidth = fontSize * 0.55;
44
+ const labelWidth = Math.max(label.length, 3) * charWidth;
45
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Skeleton.default, {
46
+ kind: "badge",
47
+ width: paddingHorizontal * 2 + labelWidth,
48
+ height: paddingVertical * 2 + lineHeight,
49
+ style: {
50
+ alignSelf: 'flex-start'
51
+ },
52
+ modes: modes
53
+ });
54
+ }
32
55
  const Container = onPress ? _reactNative.Pressable : _reactNative.View;
33
56
  const containerStyle = {
34
57
  backgroundColor,
@@ -10,6 +10,8 @@ var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resol
10
10
  var _webPlatformUtils = require("../../utils/web-platform-utils");
11
11
  var _reactUtils = require("../../utils/react-utils");
12
12
  var _Icon = _interopRequireDefault(require("../../icons/Icon"));
13
+ var _Skeleton = _interopRequireDefault(require("../../skeleton/Skeleton"));
14
+ var _SkeletonGroup = require("../../skeleton/SkeletonGroup");
13
15
  var _jsxRuntime = require("react/jsx-runtime");
14
16
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
17
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
@@ -173,6 +175,7 @@ function ButtonImpl({
173
175
  accessibilityHint,
174
176
  accessibilityState,
175
177
  webAccessibilityProps,
178
+ loading,
176
179
  ...rest
177
180
  }) {
178
181
  // Hover state is web-only in practice; the setter is gated so native taps
@@ -188,6 +191,14 @@ function ButtonImpl({
188
191
  userHandlersRef.current.onHoverOut = rest?.onHoverOut;
189
192
  const tokens = (0, _react.useMemo)(() => resolveButtonTokens(modes, disabled), [modes, disabled]);
190
193
 
194
+ // Skeleton context — read unconditionally so React's hook order stays
195
+ // stable. The actual short-circuit return happens AFTER all remaining
196
+ // hooks have been called below.
197
+ const {
198
+ active: groupActive
199
+ } = (0, _SkeletonGroup.useSkeleton)();
200
+ const isLoading = loading ?? groupActive;
201
+
191
202
  // Active label color: base by default; hover override (web-only) when hovered.
192
203
  // Press color is intentionally NOT applied to the label on native — applying
193
204
  // it would require a React render per touch and re-introduce the flicker.
@@ -265,6 +276,32 @@ function ButtonImpl({
265
276
  console.warn('[Button] Custom content is used without an explicit `accessibilityLabel` or string `label`. ' + 'Screen readers may not announce this button correctly.');
266
277
  }
267
278
  }
279
+ if (isLoading) {
280
+ const {
281
+ container,
282
+ baseLabel,
283
+ iconSize,
284
+ accessoryOffset
285
+ } = tokens;
286
+ const paddingHorizontal = container.paddingHorizontal ?? 20;
287
+ const paddingVertical = container.paddingVertical ?? 12;
288
+ const lineHeight = baseLabel.lineHeight ?? 19;
289
+ const fontSize = baseLabel.fontSize ?? 16;
290
+ const labelText = typeof label === 'string' ? label : 'Button';
291
+ const charWidth = fontSize * 0.55;
292
+ const labelWidth = Math.max(labelText.length, 4) * charWidth;
293
+ const hasAccessory = !!(leading || trailing || icon);
294
+ const accessoryWidth = hasAccessory ? iconSize + accessoryOffset * 2 : 0;
295
+ const skeletonWidth = paddingHorizontal * 2 + labelWidth + accessoryWidth;
296
+ const skeletonHeight = paddingVertical * 2 + lineHeight;
297
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Skeleton.default, {
298
+ kind: "other",
299
+ width: skeletonWidth,
300
+ height: skeletonHeight,
301
+ style: style,
302
+ modes: modes
303
+ });
304
+ }
268
305
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
269
306
  accessibilityRole: "button",
270
307
  accessibilityLabel: undefined,
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _react = _interopRequireDefault(require("react"));
7
+ var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
10
10
  var _reactUtils = require("../../utils/react-utils");
@@ -13,6 +13,7 @@ var _Button = _interopRequireDefault(require("../Button/Button"));
13
13
  var _InstitutionBadge = _interopRequireDefault(require("../InstitutionBadge/InstitutionBadge"));
14
14
  var _jsxRuntime = require("react/jsx-runtime");
15
15
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
16
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
16
17
  const DEFAULT_ITEMS = [{
17
18
  label: 'Account type',
18
19
  value: 'Korem ipsum'
@@ -23,6 +24,14 @@ const DEFAULT_ITEMS = [{
23
24
  label: 'Last updated',
24
25
  value: 'Korem ipsum'
25
26
  }];
27
+
28
+ // Component-level defaults that match the Figma reference. Caller-provided
29
+ // `modes` are merged on top so every key here can be overridden per-instance.
30
+ const DEFAULT_MODES = Object.freeze({
31
+ 'Button / Size': 'S',
32
+ AppearanceBrand: 'Secondary',
33
+ Emphasis: 'Medium'
34
+ });
26
35
  const toNumber = (value, fallback) => {
27
36
  if (typeof value === 'number') return Number.isFinite(value) ? value : fallback;
28
37
  if (typeof value === 'string') {
@@ -61,10 +70,17 @@ function CardBankAccount({
61
70
  buttonLabel = 'Button',
62
71
  onButtonPress,
63
72
  footer,
64
- modes = _reactUtils.EMPTY_MODES,
73
+ modes: propModes = _reactUtils.EMPTY_MODES,
65
74
  style,
66
75
  accessibilityLabel
67
76
  }) {
77
+ // Merge caller modes on top of `DEFAULT_MODES` so every default key
78
+ // (e.g. `Button / Size`, `AppearanceBrand`, `Emphasis`) can be overridden
79
+ // per-instance while still applying out of the box.
80
+ const modes = (0, _react.useMemo)(() => propModes === _reactUtils.EMPTY_MODES ? DEFAULT_MODES : {
81
+ ...DEFAULT_MODES,
82
+ ...propModes
83
+ }, [propModes]);
68
84
  const background = (0, _figmaVariablesResolver.getVariableByName)('bankAccountCard/background', modes) ?? '#ffffff';
69
85
  const radius = toNumber((0, _figmaVariablesResolver.getVariableByName)('bankAccountCard/radius', modes), 16);
70
86
  const paddingHorizontal = toNumber((0, _figmaVariablesResolver.getVariableByName)('bankAccountCard/padding/horizontal', modes), 12);
@@ -17,6 +17,9 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
17
17
  * single horizontal pressable row. Pressing anywhere on the row (outside of the
18
18
  * `endSlot`) toggles the checkbox, mirroring the typical native form pattern.
19
19
  *
20
+ * Use the `control` prop to swap the checkbox between the leading (left, default)
21
+ * and trailing (right) edge of the row. The `endSlot` flips to the opposite edge.
22
+ *
20
23
  * Mirrors the Figma "Checkbox Item" component and uses the `checkboxItem/*`
21
24
  * design tokens for typography and spacing.
22
25
  *
@@ -31,6 +34,7 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
31
34
  * label="Fixed deposit • 0245"
32
35
  * checked={checked}
33
36
  * onValueChange={setChecked}
37
+ * control="leading"
34
38
  * modes={{ 'Color Mode': 'Light' }}
35
39
  * />
36
40
  * ```
@@ -41,6 +45,7 @@ function CheckboxItem({
41
45
  onValueChange,
42
46
  disabled = false,
43
47
  label = 'Fixed deposit • 0245',
48
+ control = 'leading',
44
49
  endSlot,
45
50
  endSlotWidth = 80,
46
51
  modes = _reactUtils.EMPTY_MODES,
@@ -48,6 +53,7 @@ function CheckboxItem({
48
53
  labelStyle,
49
54
  accessibilityLabel
50
55
  }) {
56
+ const isTrailing = control === 'trailing';
51
57
  const isControlled = controlledChecked !== undefined;
52
58
  const [internalChecked, setInternalChecked] = (0, _react.useState)(defaultChecked);
53
59
  const isChecked = isControlled ? controlledChecked : internalChecked;
@@ -86,7 +92,35 @@ function CheckboxItem({
86
92
  fontWeight: labelFontWeight
87
93
  };
88
94
  const a11yLabel = accessibilityLabel ?? (typeof label === 'string' ? label : undefined);
89
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
95
+ const checkboxNode = /*#__PURE__*/(0, _jsxRuntime.jsx)(_Checkbox.default, {
96
+ checked: isChecked,
97
+ disabled: disabled,
98
+ onValueChange: handleToggle,
99
+ modes: modes,
100
+ ...(a11yLabel !== undefined ? {
101
+ accessibilityLabel: a11yLabel
102
+ } : {})
103
+ });
104
+ const labelNode = label != null && label !== false ? typeof label === 'string' || typeof label === 'number' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
105
+ style: [resolvedLabelStyle, labelStyle],
106
+ selectable: false,
107
+ children: label
108
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
109
+ style: {
110
+ flex: 1,
111
+ minWidth: 0
112
+ },
113
+ children: label
114
+ }) : null;
115
+ const endSlotNode = endSlot ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
116
+ style: {
117
+ width: endSlotWidth,
118
+ flexShrink: 0,
119
+ alignItems: 'stretch'
120
+ },
121
+ children: (0, _reactUtils.cloneChildrenWithModes)(endSlot, modes)
122
+ }) : null;
123
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
90
124
  style: [containerStyle, style],
91
125
  onPress: handleToggle,
92
126
  disabled: disabled,
@@ -96,30 +130,11 @@ function CheckboxItem({
96
130
  disabled
97
131
  },
98
132
  accessibilityLabel: a11yLabel,
99
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Checkbox.default, {
100
- checked: isChecked,
101
- disabled: disabled,
102
- onValueChange: handleToggle,
103
- modes: modes,
104
- accessibilityLabel: a11yLabel
105
- }), label != null && label !== false ? typeof label === 'string' || typeof label === 'number' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
106
- style: [resolvedLabelStyle, labelStyle],
107
- selectable: false,
108
- children: label
109
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
110
- style: {
111
- flex: 1,
112
- minWidth: 0
113
- },
114
- children: label
115
- }) : null, endSlot ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
116
- style: {
117
- width: endSlotWidth,
118
- flexShrink: 0,
119
- alignItems: 'stretch'
120
- },
121
- children: (0, _reactUtils.cloneChildrenWithModes)(endSlot, modes)
122
- }) : null]
133
+ children: isTrailing ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
134
+ children: [endSlotNode, labelNode, checkboxNode]
135
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
136
+ children: [checkboxNode, labelNode, endSlotNode]
137
+ })
123
138
  });
124
139
  }
125
140
  var _default = exports.default = CheckboxItem;
@@ -0,0 +1,214 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.Dropdown = Dropdown;
7
+ exports.DropdownItem = DropdownItem;
8
+ exports.default = void 0;
9
+ var _react = _interopRequireWildcard(require("react"));
10
+ var _reactNative = require("react-native");
11
+ var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
12
+ var _JFSThemeProvider = require("../../design-tokens/JFSThemeProvider");
13
+ var _reactUtils = require("../../utils/react-utils");
14
+ var _Icon = _interopRequireDefault(require("../../icons/Icon"));
15
+ var _jsxRuntime = require("react/jsx-runtime");
16
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
18
+ const IS_WEB = _reactNative.Platform.OS === 'web';
19
+
20
+ // ---------------------------------------------------------------------------
21
+ // DropdownItem
22
+ // ---------------------------------------------------------------------------
23
+
24
+ function useDropdownItemTokens(modes) {
25
+ return (0, _react.useMemo)(() => {
26
+ // The `dropdownItem/background` token aliases through the
27
+ // `Dropdown Item State` collection (Idle | Selected), so we resolve
28
+ // both possibilities up-front and pick at render time.
29
+ const idleBackground = (0, _figmaVariablesResolver.getVariableByName)('dropdownItem/background', {
30
+ ...modes,
31
+ 'Dropdown Item State': 'Idle'
32
+ }) || '#ffffff';
33
+ const selectedBackground = (0, _figmaVariablesResolver.getVariableByName)('dropdownItem/background', {
34
+ ...modes,
35
+ 'Dropdown Item State': 'Selected'
36
+ }) || '#f5f5f5';
37
+ const foreground = (0, _figmaVariablesResolver.getVariableByName)('dropdownItem/foreground', modes) || '#000000';
38
+ const fontFamily = (0, _figmaVariablesResolver.getVariableByName)('dropdownItem/fontFamily', modes) || 'JioType Var';
39
+ const fontSize = parseInt((0, _figmaVariablesResolver.getVariableByName)('dropdownItem/fontSize', modes), 10) || 16;
40
+ const fontWeight = (0, _figmaVariablesResolver.getVariableByName)('dropdownItem/fontWeight', modes) || '400';
41
+ const lineHeight = parseInt((0, _figmaVariablesResolver.getVariableByName)('dropdownItem/lineHeight', modes), 10) || 19;
42
+ const gap = parseInt((0, _figmaVariablesResolver.getVariableByName)('dropdownItem/gap', modes), 10) || 8;
43
+ const paddingHorizontal = parseInt((0, _figmaVariablesResolver.getVariableByName)('dropdownItem/padding/horizontal', modes), 10) || 12;
44
+ const paddingVertical = parseInt((0, _figmaVariablesResolver.getVariableByName)('dropdownItem/padding/vertical', modes), 10) || 12;
45
+ return {
46
+ idleBackground,
47
+ selectedBackground,
48
+ foreground,
49
+ fontFamily,
50
+ fontSize,
51
+ fontWeight,
52
+ lineHeight,
53
+ gap,
54
+ paddingHorizontal,
55
+ paddingVertical
56
+ };
57
+ }, [modes]);
58
+ }
59
+ function DropdownItem({
60
+ label,
61
+ value = null,
62
+ selected = false,
63
+ disabled = false,
64
+ leading,
65
+ trailing,
66
+ onPress,
67
+ children,
68
+ modes: propModes = _reactUtils.EMPTY_MODES,
69
+ style,
70
+ labelStyle,
71
+ accessibilityLabel,
72
+ accessibilityHint
73
+ }) {
74
+ const {
75
+ modes: globalModes
76
+ } = (0, _JFSThemeProvider.useTokens)();
77
+ const modes = (0, _react.useMemo)(() => ({
78
+ ...globalModes,
79
+ ...propModes
80
+ }), [globalModes, propModes]);
81
+ const tokens = useDropdownItemTokens(modes);
82
+ const [isHovered, setIsHovered] = (0, _react.useState)(false);
83
+ const handlePress = (0, _react.useCallback)(() => {
84
+ if (disabled) return;
85
+ onPress?.(value);
86
+ }, [disabled, onPress, value]);
87
+ const containerStyle = (0, _react.useCallback)(({
88
+ pressed
89
+ }) => {
90
+ const showSelected = pressed || isHovered && IS_WEB || selected;
91
+ const base = {
92
+ flexDirection: 'row',
93
+ alignItems: 'center',
94
+ gap: tokens.gap,
95
+ paddingHorizontal: tokens.paddingHorizontal,
96
+ paddingVertical: tokens.paddingVertical,
97
+ backgroundColor: showSelected ? tokens.selectedBackground : tokens.idleBackground,
98
+ opacity: disabled ? 0.4 : 1,
99
+ width: '100%'
100
+ };
101
+ return [base, style];
102
+ }, [tokens.gap, tokens.paddingHorizontal, tokens.paddingVertical, tokens.idleBackground, tokens.selectedBackground, isHovered, selected, disabled, style]);
103
+ const textStyle = {
104
+ color: tokens.foreground,
105
+ fontFamily: tokens.fontFamily,
106
+ fontSize: tokens.fontSize,
107
+ fontWeight: tokens.fontWeight,
108
+ lineHeight: tokens.lineHeight,
109
+ flexShrink: 1
110
+ };
111
+ const processedLeading = leading ? (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(leading), modes) : null;
112
+ const customTrailing = trailing ? (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(trailing), modes) : null;
113
+ const showDefaultCheck = !trailing && selected;
114
+ const fallbackA11yLabel = accessibilityLabel || (typeof label === 'string' ? label : 'Dropdown item');
115
+ const a11yProps = {
116
+ accessibilityRole: 'menuitem',
117
+ accessibilityLabel: fallbackA11yLabel,
118
+ accessibilityState: {
119
+ selected,
120
+ disabled
121
+ }
122
+ };
123
+ if (accessibilityHint) {
124
+ a11yProps.accessibilityHint = accessibilityHint;
125
+ }
126
+ const handleHoverIn = (0, _react.useCallback)(() => {
127
+ if (IS_WEB && !disabled) setIsHovered(true);
128
+ }, [disabled]);
129
+ const handleHoverOut = (0, _react.useCallback)(() => {
130
+ if (IS_WEB) setIsHovered(false);
131
+ }, []);
132
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
133
+ onPress: handlePress,
134
+ disabled: disabled,
135
+ onHoverIn: handleHoverIn,
136
+ onHoverOut: handleHoverOut,
137
+ style: containerStyle,
138
+ ...a11yProps,
139
+ children: [processedLeading, children != null ? children : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
140
+ style: [textStyle, labelStyle],
141
+ numberOfLines: 1,
142
+ children: label
143
+ }), customTrailing, showDefaultCheck && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.default, {
144
+ name: "ic_confirm",
145
+ size: 16,
146
+ color: tokens.foreground
147
+ })]
148
+ });
149
+ }
150
+
151
+ // ---------------------------------------------------------------------------
152
+ // Dropdown (popup surface)
153
+ // ---------------------------------------------------------------------------
154
+
155
+ /**
156
+ * `Dropdown` is the visual surface (popup) that contains a list of
157
+ * `DropdownItem`s. It is responsible for the background, rounded corners,
158
+ * elevation/shadow, and clipping. Use it standalone for menu UIs, or rely on
159
+ * `DropdownInput` which composes it into a form-field experience.
160
+ */
161
+ function Dropdown({
162
+ children,
163
+ maxHeight,
164
+ modes: propModes = _reactUtils.EMPTY_MODES,
165
+ style,
166
+ accessibilityLabel
167
+ }) {
168
+ const {
169
+ modes: globalModes
170
+ } = (0, _JFSThemeProvider.useTokens)();
171
+ const modes = (0, _react.useMemo)(() => ({
172
+ ...globalModes,
173
+ ...propModes
174
+ }), [globalModes, propModes]);
175
+ const radius = parseInt((0, _figmaVariablesResolver.getVariableByName)('dropdown/radius', modes), 10) || 8;
176
+ const background = (0, _figmaVariablesResolver.getVariableByName)('dropdown/background', modes) || '#ffffff';
177
+ const shadowColor = (0, _figmaVariablesResolver.getVariableByName)('dropdown/shadow/color', modes) || 'rgba(0, 0, 0, 0.08)';
178
+ const shadowOffsetX = parseInt((0, _figmaVariablesResolver.getVariableByName)('dropdown/shadow/offsetX', modes), 10) || 0;
179
+ const shadowOffsetY = parseInt((0, _figmaVariablesResolver.getVariableByName)('dropdown/shadow/offsetY', modes), 10) || 4;
180
+ const shadowBlur = parseInt((0, _figmaVariablesResolver.getVariableByName)('dropdown/shadow/blur', modes), 10) || 16;
181
+ const containerStyle = {
182
+ backgroundColor: background,
183
+ borderRadius: radius,
184
+ overflow: 'hidden',
185
+ shadowColor,
186
+ shadowOffset: {
187
+ width: shadowOffsetX,
188
+ height: shadowOffsetY
189
+ },
190
+ shadowOpacity: 1,
191
+ shadowRadius: shadowBlur / 2,
192
+ elevation: 4
193
+ };
194
+ const content = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
195
+ style: {
196
+ flexDirection: 'column'
197
+ },
198
+ children: (0, _reactUtils.cloneChildrenWithModes)(children, modes)
199
+ });
200
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
201
+ style: [containerStyle, style],
202
+ accessibilityRole: "menu",
203
+ accessibilityLabel: accessibilityLabel || 'Dropdown menu',
204
+ children: maxHeight != null ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
205
+ style: {
206
+ maxHeight
207
+ },
208
+ showsVerticalScrollIndicator: true,
209
+ keyboardShouldPersistTaps: "handled",
210
+ children: content
211
+ }) : content
212
+ });
213
+ }
214
+ var _default = exports.default = Dropdown;