jfs-components 0.0.73 → 0.0.74

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 (63) hide show
  1. package/CHANGELOG.md +23 -6
  2. package/lib/commonjs/components/AccountCard/AccountCard.js +247 -0
  3. package/lib/commonjs/components/AppBar/AppBar.js +17 -11
  4. package/lib/commonjs/components/CardBankAccount/CardBankAccount.js +18 -2
  5. package/lib/commonjs/components/CheckboxItem/CheckboxItem.js +40 -25
  6. package/lib/commonjs/components/Dropdown/Dropdown.js +214 -0
  7. package/lib/commonjs/components/DropdownInput/DropdownInput.js +542 -0
  8. package/lib/commonjs/components/FormField/FormField.js +328 -178
  9. package/lib/commonjs/components/LottieIntroBlock/LottieIntroBlock.js +150 -0
  10. package/lib/commonjs/components/PageHero/PageHero.js +153 -0
  11. package/lib/commonjs/components/PoweredByLabel/PoweredByLabel.js +135 -0
  12. package/lib/commonjs/components/PoweredByLabel/finvu.png +0 -0
  13. package/lib/commonjs/components/Text/Text.js +9 -2
  14. package/lib/commonjs/components/Tooltip/Tooltip.js +34 -27
  15. package/lib/commonjs/components/index.js +60 -0
  16. package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
  17. package/lib/commonjs/icons/registry.js +1 -1
  18. package/lib/module/components/AccountCard/AccountCard.js +241 -0
  19. package/lib/module/components/AppBar/AppBar.js +17 -11
  20. package/lib/module/components/CardBankAccount/CardBankAccount.js +17 -2
  21. package/lib/module/components/CheckboxItem/CheckboxItem.js +41 -26
  22. package/lib/module/components/Dropdown/Dropdown.js +206 -0
  23. package/lib/module/components/DropdownInput/DropdownInput.js +536 -0
  24. package/lib/module/components/FormField/FormField.js +330 -180
  25. package/lib/module/components/LottieIntroBlock/LottieIntroBlock.js +144 -0
  26. package/lib/module/components/PageHero/PageHero.js +147 -0
  27. package/lib/module/components/PoweredByLabel/PoweredByLabel.js +130 -0
  28. package/lib/module/components/PoweredByLabel/finvu.png +0 -0
  29. package/lib/module/components/Text/Text.js +9 -2
  30. package/lib/module/components/Tooltip/Tooltip.js +34 -27
  31. package/lib/module/components/index.js +7 -1
  32. package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
  33. package/lib/module/icons/registry.js +1 -1
  34. package/lib/typescript/src/components/AccountCard/AccountCard.d.ts +81 -0
  35. package/lib/typescript/src/components/CardBankAccount/CardBankAccount.d.ts +9 -2
  36. package/lib/typescript/src/components/CheckboxItem/CheckboxItem.d.ts +18 -2
  37. package/lib/typescript/src/components/Dropdown/Dropdown.d.ts +62 -0
  38. package/lib/typescript/src/components/DropdownInput/DropdownInput.d.ts +107 -0
  39. package/lib/typescript/src/components/FormField/FormField.d.ts +76 -19
  40. package/lib/typescript/src/components/LottieIntroBlock/LottieIntroBlock.d.ts +58 -0
  41. package/lib/typescript/src/components/PageHero/PageHero.d.ts +53 -0
  42. package/lib/typescript/src/components/PoweredByLabel/PoweredByLabel.d.ts +70 -0
  43. package/lib/typescript/src/components/Text/Text.d.ts +12 -2
  44. package/lib/typescript/src/components/Tooltip/Tooltip.d.ts +13 -2
  45. package/lib/typescript/src/components/index.d.ts +7 -1
  46. package/lib/typescript/src/icons/registry.d.ts +1 -1
  47. package/package.json +1 -3
  48. package/src/components/AccountCard/AccountCard.tsx +376 -0
  49. package/src/components/AppBar/AppBar.tsx +25 -14
  50. package/src/components/CardBankAccount/CardBankAccount.tsx +29 -3
  51. package/src/components/CheckboxItem/CheckboxItem.tsx +65 -30
  52. package/src/components/Dropdown/Dropdown.tsx +331 -0
  53. package/src/components/DropdownInput/DropdownInput.tsx +819 -0
  54. package/src/components/FormField/FormField.tsx +542 -215
  55. package/src/components/LottieIntroBlock/LottieIntroBlock.tsx +202 -0
  56. package/src/components/PageHero/PageHero.tsx +200 -0
  57. package/src/components/PoweredByLabel/PoweredByLabel.tsx +221 -0
  58. package/src/components/PoweredByLabel/finvu.png +0 -0
  59. package/src/components/Text/Text.tsx +24 -3
  60. package/src/components/Tooltip/Tooltip.tsx +50 -25
  61. package/src/components/index.ts +15 -1
  62. package/src/design-tokens/Coin Variables-variables-full.json +1 -1
  63. package/src/icons/registry.ts +1 -1
package/CHANGELOG.md CHANGED
@@ -4,14 +4,31 @@ All notable changes to this project are documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
+ ## [0.0.74] - 2026-05-19
8
+
9
+ - Added new account and onboarding components: `AccountCard` (connected/add variants), `PageHero`, `LottieIntroBlock`, and `PoweredByLabel`.
10
+ - Added new selection primitives: `Dropdown` + `DropdownItem` (compound API) and `DropdownInput` (options-based form control).
11
+ - Added Storybook coverage for the existing `Icon` primitive (no API change).
12
+ - Major `FormField` rewrite — re-bound directly to React Native `TextInput` (no longer wraps `TextInput` component), gained `number` / `phone` / `url` types, `Form` context integration, and improved Figma/token alignment.
13
+ - Compound `Tooltip` upgrade — `TooltipContent` now acts as a vertical slot with `gap` and `alignItems` props, and exports `TooltipPlacement` / trigger / content types from the package barrel.
14
+ - `Text` now accepts JSX `children` (drop-in `<Text>label</Text>` works) in addition to the `text` prop; `AppBar` middle slot lays out via `flex: 1` with `space-between` fallback when absent.
15
+ - `CheckboxItem` gained a `control` prop (`leading` / `trailing`) that swaps the checkbox and the end slot to either edge of the row.
16
+ - `CardBankAccount` ships sensible default `Button / Size` + Appearance modes so the footer button matches Figma out of the box.
17
+ - Figma/token sync pass across `FormField`, `CardBankAccount`, `CardFinancialCondition`, `CheckboxItem`, `CircularProgressBar`, `CoverageBarComparison`, `DonutChart`, `DonutChartSummary`, `Gauge`, `LinearProgress`, `MetricLegendItem`, `MonthlyStatusGrid`, `Nudge`, `RangeTrack`, `SavingsGoalSummary`, and `SegmentedTrack`; refreshed Coin Variables tokens, `.token-metadata.json`, and icons registry.
18
+ - Repo cleanup: removed the legacy `example/` app, `.expo/` artifacts, and the `example` / `example:install` scripts; updated `tsconfig.build.json` and `scripts/generate-component-docs.js`; added `.tgz` and `.expo/` to `.gitignore`.
19
+
20
+ ---
21
+
7
22
  ## [0.0.73] - 2026-05-15
8
23
 
9
- - Added new coverage and tracking components: `CoverageRing`, `CoverageBarComparison`, and `MonthlyStatusGrid` (with exported `CalendarGlyph`).
10
- - Enhanced `CircularProgressBar` with an in-ring `supportText` caption (driven by `circularProgressBar/supportText/*` tokens) and a centered text stack.
11
- - Refreshed `LinearProgress` and `SavingsGoalSummary` token surface: split `Appearance / DataViz` into `Appearance Type` + `AppearanceBrand` + `AppearanceSystem`, and renamed `Emphasis / DataViz` to `Emphasis`.
12
- - Expanded `SupportText`, `SupportTextIcon`, and `InputSearch` with an `Auto` status mode and a new `FormField States` collection (Idle / Active / Read Only / Error).
13
- - Added `Error` state and `Color Mode` support to `FormField`, and a new `Page type` (MainPage / SubPage) collection on `Title`.
14
- - Refreshed component token metadata and updated Storybook/MDX coverage for all changed components.
24
+ - Added new chart, progress, and coverage components: `DonutChart`, `DonutChartSummary`, `LinearProgress`, `SavingsGoalSummary`, `CoverageRing`, `CoverageBarComparison`, `MonthlyStatusGrid`, `MetricLegendItem`, `RangeTrack`, `SegmentedTrack`, `StatGroup`, `StrengthIndicator`, and `SummaryTile`.
25
+ - Added new form/selection primitives: `AccordionCheckbox`, `CheckboxGroup`, `CheckboxItem`, and `Radio` (renamed from `RadioButton`; the old name is kept as a deprecated re-export).
26
+ - Added new card and badge components: `CardBankAccount`, `CardInsight`, `ProductOverview`, and `BrandChip`.
27
+ - Major `OTP` overhaul (new API, stories, and MDX) and `LinearMeter` refactor; `Carousel` pagination/maxHeight refresh and `HoldingsCard` migration to `Radio`.
28
+ - Enhanced `CircularProgressBar` with an in-ring `supportText` caption (driven by `circularProgressBar/supportText/*` tokens) and a centered text stack; reworked `StatItem` API and stories.
29
+ - Token surface refresh: added `XS` to `Button / Size` (surfaced on `Button`, `CardCTA`, `IconButton`); split `LinearProgress` / `SavingsGoalSummary` `Appearance / DataViz` into `Appearance Type` + `AppearanceBrand` + `AppearanceSystem` and renamed `Emphasis / DataViz` `Emphasis`; added `Auto` status + `FormField States` to `SupportText`, `SupportTextIcon`, `InputSearch`; added `Error` state and `Color Mode` to `FormField`; added `Page type` (MainPage / SubPage) to `Title`.
30
+ - New `number-utils` (+ tests) exported from `src/utils`; refreshed icons registry, Coin Variables tokens, and `.token-metadata.json`.
31
+ - Expanded Storybook and MDX coverage for all new and updated components, plus docs for `HStack`, `VStack`, and `Section`.
15
32
 
16
33
  ---
17
34
 
@@ -0,0 +1,247 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
10
+ var _reactUtils = require("../../utils/react-utils");
11
+ var _Icon = _interopRequireDefault(require("../../icons/Icon"));
12
+ var _jsxRuntime = require("react/jsx-runtime");
13
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
+ 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); }
15
+ const IS_IOS = _reactNative.Platform.OS === 'ios';
16
+ const PRESS_DELAY = IS_IOS ? 130 : 0;
17
+ const DEFAULT_IMAGE_RATIO = 125 / 82;
18
+ const pressedOverlayStyle = {
19
+ opacity: 0.7
20
+ };
21
+
22
+ // Default modes for the "Add" placeholder icon (`iconButton/*` tokens).
23
+ // Caller-supplied `modes` are merged on top so every key here can be overridden.
24
+ const ADD_ICON_DEFAULT_MODES = Object.freeze({
25
+ AppearanceBrand: 'Secondary',
26
+ Emphasis: 'Low',
27
+ "Button / Size": "M"
28
+ });
29
+ const toNumber = (value, fallback) => {
30
+ if (typeof value === 'number') return Number.isFinite(value) ? value : fallback;
31
+ if (typeof value === 'string') {
32
+ const parsed = Number(value);
33
+ return Number.isFinite(parsed) ? parsed : fallback;
34
+ }
35
+ return fallback;
36
+ };
37
+ const toFontWeight = (value, fallback) => {
38
+ if (typeof value === 'number') return String(value);
39
+ if (typeof value === 'string') return value;
40
+ return fallback;
41
+ };
42
+ const normalizeImageSource = src => {
43
+ if (src == null) return undefined;
44
+ if (typeof src === 'string') return {
45
+ uri: src
46
+ };
47
+ return src;
48
+ };
49
+
50
+ /**
51
+ * `AccountCard` — a compact card preview used to represent a linked
52
+ * financial account in lists / grids.
53
+ *
54
+ * Two visual states are supported via the `state` prop:
55
+ *
56
+ * 1. `'connected'` (default): renders a small card-art preview, a bold
57
+ * `title` and a regular-weight `subtitle` (e.g. masked account number).
58
+ * 2. `'add'`: renders a soft-tinted placeholder field with a centred `+`
59
+ * icon and the `title` underneath, intended as the "add new account"
60
+ * entry-point at the end of a list of connected accounts.
61
+ *
62
+ * All values resolve through the `accountCard/*` design tokens with
63
+ * sensible Figma defaults so the card renders correctly out of the box.
64
+ *
65
+ * @component
66
+ * @param {AccountCardProps} props
67
+ */
68
+ function AccountCard({
69
+ state = 'connected',
70
+ title = 'Personal account',
71
+ subtitle = '**** 5651',
72
+ imageSource,
73
+ imageRatio = DEFAULT_IMAGE_RATIO,
74
+ cardSlot,
75
+ addIcon = 'ic_add',
76
+ onPress,
77
+ disabled = false,
78
+ modes = _reactUtils.EMPTY_MODES,
79
+ style,
80
+ accessibilityLabel,
81
+ accessibilityHint
82
+ }) {
83
+ const iconModes = (0, _react.useMemo)(() => modes === _reactUtils.EMPTY_MODES ? ADD_ICON_DEFAULT_MODES : {
84
+ ...ADD_ICON_DEFAULT_MODES,
85
+ ...modes
86
+ }, [modes]);
87
+
88
+ // ---- Tokens ---------------------------------------------------------
89
+ const gap = toNumber((0, _figmaVariablesResolver.getVariableByName)('accountCard/gap', modes), 8);
90
+ const textWrapGap = toNumber((0, _figmaVariablesResolver.getVariableByName)('accountCard/textWrap/gap', modes), 0);
91
+ const titleColor = (0, _figmaVariablesResolver.getVariableByName)('accountCard/title/foreground', modes) ?? '#0d0d0f';
92
+ const titleFontFamily = (0, _figmaVariablesResolver.getVariableByName)('accountCard/title/fontFamily', modes) ?? 'JioType Var';
93
+ const titleFontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('accountCard/title/fontSize', modes), 12);
94
+ const titleLineHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('accountCard/title/lineHeight', modes), 16);
95
+ const titleFontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('accountCard/title/fontWeight', modes), '700');
96
+ const subtitleColor = (0, _figmaVariablesResolver.getVariableByName)('accountCard/subtitle/foreground', modes) ?? '#24262b';
97
+ const subtitleFontFamily = (0, _figmaVariablesResolver.getVariableByName)('accountCard/subtitle/fontFamily', modes) ?? 'JioType Var';
98
+ const subtitleFontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('accountCard/subtitle/fontSize', modes), 12);
99
+ const subtitleLineHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('accountCard/subtitle/lineHeight', modes), 16);
100
+ const subtitleFontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('accountCard/subtitle/fontWeight', modes), '400');
101
+ const addFieldRadius = toNumber((0, _figmaVariablesResolver.getVariableByName)('accountCard/addItemField/radius', modes), 8);
102
+ const addFieldBg = (0, _figmaVariablesResolver.getVariableByName)('accountCard/addItemField/bg', modes) ?? '#ede8ff';
103
+ const addIconColor = (0, _figmaVariablesResolver.getVariableByName)('iconButton/icon/color', iconModes) ?? '#5d00b5';
104
+ const addIconSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('iconButton/icon/size', iconModes), 16);
105
+
106
+ // ---- Styles ---------------------------------------------------------
107
+ const titleStyle = {
108
+ color: titleColor,
109
+ fontFamily: titleFontFamily,
110
+ fontSize: titleFontSize,
111
+ lineHeight: titleLineHeight,
112
+ fontWeight: titleFontWeight,
113
+ width: '100%'
114
+ };
115
+ const subtitleStyle = {
116
+ color: subtitleColor,
117
+ fontFamily: subtitleFontFamily,
118
+ fontSize: subtitleFontSize,
119
+ lineHeight: subtitleLineHeight,
120
+ fontWeight: subtitleFontWeight,
121
+ width: '100%'
122
+ };
123
+ const imageBoxStyle = {
124
+ width: '100%',
125
+ aspectRatio: imageRatio,
126
+ overflow: 'hidden'
127
+ };
128
+
129
+ // RN's `<Image>` accepts `ImageStyle`, which has a narrower `overflow`
130
+ // union than `ViewStyle`. Build the image-only style separately so the
131
+ // shared box dimensions can be reused without a cast.
132
+ const imageStyle = {
133
+ width: '100%',
134
+ aspectRatio: imageRatio
135
+ };
136
+ const addFieldStyle = {
137
+ ...imageBoxStyle,
138
+ backgroundColor: addFieldBg,
139
+ borderRadius: addFieldRadius,
140
+ alignItems: 'center',
141
+ justifyContent: 'center'
142
+ };
143
+
144
+ // ---- Image / placeholder area --------------------------------------
145
+ const renderCardArea = () => {
146
+ if (cardSlot !== undefined && cardSlot !== null) {
147
+ const processed = (0, _reactUtils.cloneChildrenWithModes)(cardSlot, modes);
148
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
149
+ style: imageBoxStyle,
150
+ pointerEvents: "box-none",
151
+ children: processed.length === 1 ? processed[0] : processed
152
+ });
153
+ }
154
+ if (state === 'add') {
155
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
156
+ style: addFieldStyle,
157
+ accessibilityElementsHidden: true,
158
+ importantForAccessibility: "no",
159
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.default, {
160
+ name: addIcon,
161
+ size: addIconSize,
162
+ color: addIconColor
163
+ })
164
+ });
165
+ }
166
+ const normalized = normalizeImageSource(imageSource);
167
+ if (normalized) {
168
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
169
+ source: normalized,
170
+ style: imageStyle,
171
+ resizeMode: "cover",
172
+ accessibilityElementsHidden: true,
173
+ importantForAccessibility: "no"
174
+ });
175
+ }
176
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
177
+ style: imageBoxStyle
178
+ });
179
+ };
180
+
181
+ // ---- Pressable wiring ----------------------------------------------
182
+ // Keep React state out of the press path. `Pressable`'s style callback
183
+ // applies the pressed visual without a re-render.
184
+ const userHandlersRef = (0, _react.useRef)({});
185
+ const handlePressIn = (0, _react.useCallback)(e => {
186
+ userHandlersRef.current.onPressIn?.(e);
187
+ }, []);
188
+ const handlePressOut = (0, _react.useCallback)(e => {
189
+ userHandlersRef.current.onPressOut?.(e);
190
+ }, []);
191
+ const containerStyle = (0, _react.useMemo)(() => ({
192
+ width: '100%',
193
+ flexDirection: 'column',
194
+ alignItems: 'flex-start',
195
+ gap,
196
+ opacity: disabled ? 0.5 : 1
197
+ }), [gap, disabled]);
198
+ const pressableStyle = (0, _react.useCallback)(({
199
+ pressed
200
+ }) => [containerStyle, style, pressed && !disabled && onPress ? pressedOverlayStyle : null], [containerStyle, style, disabled, onPress]);
201
+ const showSubtitle = state === 'connected' && subtitle != null && subtitle !== '';
202
+ const a11yRole = onPress ? 'button' : undefined;
203
+ const a11yLabel = accessibilityLabel ?? title;
204
+ const content = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
205
+ children: [renderCardArea(), title != null && title !== '' || showSubtitle ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
206
+ style: {
207
+ width: '100%',
208
+ flexDirection: 'column',
209
+ alignItems: 'flex-start',
210
+ gap: textWrapGap
211
+ },
212
+ children: [title != null && title !== '' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
213
+ style: titleStyle,
214
+ numberOfLines: 1,
215
+ children: title
216
+ }) : null, showSubtitle ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
217
+ style: subtitleStyle,
218
+ numberOfLines: 1,
219
+ children: subtitle
220
+ }) : null]
221
+ }) : null]
222
+ });
223
+ if (!onPress) {
224
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
225
+ accessibilityLabel: a11yLabel,
226
+ accessibilityHint: accessibilityHint,
227
+ style: [containerStyle, style],
228
+ children: content
229
+ });
230
+ }
231
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
232
+ accessibilityRole: a11yRole,
233
+ accessibilityLabel: a11yLabel,
234
+ accessibilityHint: accessibilityHint,
235
+ accessibilityState: {
236
+ disabled
237
+ },
238
+ onPress: disabled ? undefined : onPress,
239
+ disabled: disabled,
240
+ onPressIn: handlePressIn,
241
+ onPressOut: handlePressOut,
242
+ unstable_pressDelay: PRESS_DELAY,
243
+ style: pressableStyle,
244
+ children: content
245
+ });
246
+ }
247
+ var _default = exports.default = /*#__PURE__*/_react.default.memo(AccountCard);
@@ -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
@@ -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;