jfs-components 0.0.72 → 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 (158) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/lib/commonjs/components/AccordionCheckbox/AccordionCheckbox.js +239 -0
  3. package/lib/commonjs/components/AccountCard/AccountCard.js +247 -0
  4. package/lib/commonjs/components/AppBar/AppBar.js +17 -11
  5. package/lib/commonjs/components/BrandChip/BrandChip.js +149 -0
  6. package/lib/commonjs/components/CardBankAccount/CardBankAccount.js +229 -0
  7. package/lib/commonjs/components/CardInsight/CardInsight.js +166 -0
  8. package/lib/commonjs/components/CheckboxGroup/CheckboxGroup.js +67 -0
  9. package/lib/commonjs/components/CheckboxItem/CheckboxItem.js +140 -0
  10. package/lib/commonjs/components/CircularProgressBar/CircularProgressBar.js +56 -9
  11. package/lib/commonjs/components/CoverageBarComparison/CoverageBarComparison.js +272 -0
  12. package/lib/commonjs/components/CoverageRing/CoverageRing.js +141 -0
  13. package/lib/commonjs/components/DonutChart/DonutChart.js +309 -0
  14. package/lib/commonjs/components/DonutChartSummary/DonutChartSummary.js +155 -0
  15. package/lib/commonjs/components/Dropdown/Dropdown.js +214 -0
  16. package/lib/commonjs/components/DropdownInput/DropdownInput.js +542 -0
  17. package/lib/commonjs/components/FormField/FormField.js +328 -178
  18. package/lib/commonjs/components/LinearMeter/LinearMeter.js +9 -28
  19. package/lib/commonjs/components/LinearProgress/LinearProgress.js +68 -0
  20. package/lib/commonjs/components/LottieIntroBlock/LottieIntroBlock.js +150 -0
  21. package/lib/commonjs/components/MetricLegendItem/MetricLegendItem.js +95 -0
  22. package/lib/commonjs/components/MonthlyStatusGrid/MonthlyStatusGrid.js +286 -0
  23. package/lib/commonjs/components/OTP/OTP.js +381 -37
  24. package/lib/commonjs/components/PageHero/PageHero.js +153 -0
  25. package/lib/commonjs/components/PoweredByLabel/PoweredByLabel.js +135 -0
  26. package/lib/commonjs/components/PoweredByLabel/finvu.png +0 -0
  27. package/lib/commonjs/components/ProductOverview/ProductOverview.js +147 -0
  28. package/lib/commonjs/components/RangeTrack/RangeTrack.js +269 -0
  29. package/lib/commonjs/components/SavingsGoalSummary/SavingsGoalSummary.js +181 -0
  30. package/lib/commonjs/components/SegmentedTrack/SegmentedTrack.js +171 -0
  31. package/lib/commonjs/components/StatGroup/StatGroup.js +128 -0
  32. package/lib/commonjs/components/StatItem/StatItem.js +65 -35
  33. package/lib/commonjs/components/StrengthIndicator/StrengthIndicator.js +157 -0
  34. package/lib/commonjs/components/SummaryTile/SummaryTile.js +150 -0
  35. package/lib/commonjs/components/Text/Text.js +9 -2
  36. package/lib/commonjs/components/Tooltip/Tooltip.js +34 -27
  37. package/lib/commonjs/components/index.js +231 -1
  38. package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
  39. package/lib/commonjs/icons/registry.js +1 -1
  40. package/lib/commonjs/utils/index.js +7 -0
  41. package/lib/commonjs/utils/number-utils.js +57 -0
  42. package/lib/module/components/AccordionCheckbox/AccordionCheckbox.js +233 -0
  43. package/lib/module/components/AccountCard/AccountCard.js +241 -0
  44. package/lib/module/components/AppBar/AppBar.js +17 -11
  45. package/lib/module/components/BrandChip/BrandChip.js +143 -0
  46. package/lib/module/components/CardBankAccount/CardBankAccount.js +223 -0
  47. package/lib/module/components/CardInsight/CardInsight.js +161 -0
  48. package/lib/module/components/CheckboxGroup/CheckboxGroup.js +62 -0
  49. package/lib/module/components/CheckboxItem/CheckboxItem.js +134 -0
  50. package/lib/module/components/CircularProgressBar/CircularProgressBar.js +56 -9
  51. package/lib/module/components/CoverageBarComparison/CoverageBarComparison.js +266 -0
  52. package/lib/module/components/CoverageRing/CoverageRing.js +136 -0
  53. package/lib/module/components/DonutChart/DonutChart.js +303 -0
  54. package/lib/module/components/DonutChartSummary/DonutChartSummary.js +150 -0
  55. package/lib/module/components/Dropdown/Dropdown.js +206 -0
  56. package/lib/module/components/DropdownInput/DropdownInput.js +536 -0
  57. package/lib/module/components/FormField/FormField.js +330 -180
  58. package/lib/module/components/LinearMeter/LinearMeter.js +9 -28
  59. package/lib/module/components/LinearProgress/LinearProgress.js +63 -0
  60. package/lib/module/components/LottieIntroBlock/LottieIntroBlock.js +144 -0
  61. package/lib/module/components/MetricLegendItem/MetricLegendItem.js +90 -0
  62. package/lib/module/components/MonthlyStatusGrid/MonthlyStatusGrid.js +281 -0
  63. package/lib/module/components/OTP/OTP.js +381 -38
  64. package/lib/module/components/PageHero/PageHero.js +147 -0
  65. package/lib/module/components/PoweredByLabel/PoweredByLabel.js +130 -0
  66. package/lib/module/components/PoweredByLabel/finvu.png +0 -0
  67. package/lib/module/components/ProductOverview/ProductOverview.js +142 -0
  68. package/lib/module/components/RangeTrack/RangeTrack.js +263 -0
  69. package/lib/module/components/SavingsGoalSummary/SavingsGoalSummary.js +175 -0
  70. package/lib/module/components/SegmentedTrack/SegmentedTrack.js +166 -0
  71. package/lib/module/components/StatGroup/StatGroup.js +123 -0
  72. package/lib/module/components/StatItem/StatItem.js +66 -36
  73. package/lib/module/components/StrengthIndicator/StrengthIndicator.js +152 -0
  74. package/lib/module/components/SummaryTile/SummaryTile.js +145 -0
  75. package/lib/module/components/Text/Text.js +9 -2
  76. package/lib/module/components/Tooltip/Tooltip.js +34 -27
  77. package/lib/module/components/index.js +28 -2
  78. package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
  79. package/lib/module/icons/registry.js +1 -1
  80. package/lib/module/utils/index.js +2 -1
  81. package/lib/module/utils/number-utils.js +53 -0
  82. package/lib/typescript/src/components/AccordionCheckbox/AccordionCheckbox.d.ts +71 -0
  83. package/lib/typescript/src/components/AccountCard/AccountCard.d.ts +81 -0
  84. package/lib/typescript/src/components/BrandChip/BrandChip.d.ts +43 -0
  85. package/lib/typescript/src/components/CardBankAccount/CardBankAccount.d.ts +86 -0
  86. package/lib/typescript/src/components/CardInsight/CardInsight.d.ts +48 -0
  87. package/lib/typescript/src/components/CheckboxGroup/CheckboxGroup.d.ts +41 -0
  88. package/lib/typescript/src/components/CheckboxItem/CheckboxItem.d.ts +72 -0
  89. package/lib/typescript/src/components/CircularProgressBar/CircularProgressBar.d.ts +11 -1
  90. package/lib/typescript/src/components/CoverageBarComparison/CoverageBarComparison.d.ts +105 -0
  91. package/lib/typescript/src/components/CoverageRing/CoverageRing.d.ts +90 -0
  92. package/lib/typescript/src/components/DonutChart/DonutChart.d.ts +117 -0
  93. package/lib/typescript/src/components/DonutChartSummary/DonutChartSummary.d.ts +103 -0
  94. package/lib/typescript/src/components/Dropdown/Dropdown.d.ts +62 -0
  95. package/lib/typescript/src/components/DropdownInput/DropdownInput.d.ts +107 -0
  96. package/lib/typescript/src/components/FormField/FormField.d.ts +76 -19
  97. package/lib/typescript/src/components/LinearProgress/LinearProgress.d.ts +17 -0
  98. package/lib/typescript/src/components/LottieIntroBlock/LottieIntroBlock.d.ts +58 -0
  99. package/lib/typescript/src/components/MetricLegendItem/MetricLegendItem.d.ts +37 -0
  100. package/lib/typescript/src/components/MonthlyStatusGrid/MonthlyStatusGrid.d.ts +119 -0
  101. package/lib/typescript/src/components/OTP/OTP.d.ts +88 -2
  102. package/lib/typescript/src/components/PageHero/PageHero.d.ts +53 -0
  103. package/lib/typescript/src/components/PoweredByLabel/PoweredByLabel.d.ts +70 -0
  104. package/lib/typescript/src/components/ProductOverview/ProductOverview.d.ts +39 -0
  105. package/lib/typescript/src/components/RangeTrack/RangeTrack.d.ts +173 -0
  106. package/lib/typescript/src/components/SavingsGoalSummary/SavingsGoalSummary.d.ts +95 -0
  107. package/lib/typescript/src/components/SegmentedTrack/SegmentedTrack.d.ts +108 -0
  108. package/lib/typescript/src/components/StatGroup/StatGroup.d.ts +45 -0
  109. package/lib/typescript/src/components/StatItem/StatItem.d.ts +24 -7
  110. package/lib/typescript/src/components/StrengthIndicator/StrengthIndicator.d.ts +58 -0
  111. package/lib/typescript/src/components/SummaryTile/SummaryTile.d.ts +60 -0
  112. package/lib/typescript/src/components/Text/Text.d.ts +12 -2
  113. package/lib/typescript/src/components/Tooltip/Tooltip.d.ts +13 -2
  114. package/lib/typescript/src/components/index.d.ts +29 -3
  115. package/lib/typescript/src/icons/registry.d.ts +1 -1
  116. package/lib/typescript/src/utils/index.d.ts +1 -0
  117. package/lib/typescript/src/utils/number-utils.d.ts +29 -0
  118. package/package.json +1 -3
  119. package/src/components/AccordionCheckbox/AccordionCheckbox.tsx +323 -0
  120. package/src/components/AccountCard/AccountCard.tsx +376 -0
  121. package/src/components/AppBar/AppBar.tsx +25 -14
  122. package/src/components/BrandChip/BrandChip.tsx +235 -0
  123. package/src/components/CardBankAccount/CardBankAccount.tsx +321 -0
  124. package/src/components/CardInsight/CardInsight.tsx +239 -0
  125. package/src/components/CheckboxGroup/CheckboxGroup.tsx +86 -0
  126. package/src/components/CheckboxItem/CheckboxItem.tsx +209 -0
  127. package/src/components/CircularProgressBar/CircularProgressBar.tsx +74 -9
  128. package/src/components/CoverageBarComparison/CoverageBarComparison.tsx +378 -0
  129. package/src/components/CoverageRing/CoverageRing.tsx +225 -0
  130. package/src/components/DonutChart/DonutChart.tsx +503 -0
  131. package/src/components/DonutChartSummary/DonutChartSummary.tsx +256 -0
  132. package/src/components/Dropdown/Dropdown.tsx +331 -0
  133. package/src/components/DropdownInput/DropdownInput.tsx +819 -0
  134. package/src/components/FormField/FormField.tsx +542 -215
  135. package/src/components/LinearMeter/LinearMeter.tsx +9 -39
  136. package/src/components/LinearProgress/LinearProgress.tsx +92 -0
  137. package/src/components/LottieIntroBlock/LottieIntroBlock.tsx +202 -0
  138. package/src/components/MetricLegendItem/MetricLegendItem.tsx +167 -0
  139. package/src/components/MonthlyStatusGrid/MonthlyStatusGrid.tsx +438 -0
  140. package/src/components/OTP/OTP.tsx +476 -29
  141. package/src/components/PageHero/PageHero.tsx +200 -0
  142. package/src/components/PoweredByLabel/PoweredByLabel.tsx +221 -0
  143. package/src/components/PoweredByLabel/finvu.png +0 -0
  144. package/src/components/ProductOverview/ProductOverview.tsx +236 -0
  145. package/src/components/RangeTrack/RangeTrack.tsx +394 -0
  146. package/src/components/SavingsGoalSummary/SavingsGoalSummary.tsx +269 -0
  147. package/src/components/SegmentedTrack/SegmentedTrack.tsx +268 -0
  148. package/src/components/StatGroup/StatGroup.tsx +169 -0
  149. package/src/components/StatItem/StatItem.tsx +117 -40
  150. package/src/components/StrengthIndicator/StrengthIndicator.tsx +205 -0
  151. package/src/components/SummaryTile/SummaryTile.tsx +251 -0
  152. package/src/components/Text/Text.tsx +24 -3
  153. package/src/components/Tooltip/Tooltip.tsx +50 -25
  154. package/src/components/index.ts +47 -3
  155. package/src/design-tokens/Coin Variables-variables-full.json +1 -1
  156. package/src/icons/registry.ts +1 -1
  157. package/src/utils/index.ts +1 -0
  158. package/src/utils/number-utils.ts +60 -0
@@ -7,223 +7,373 @@ exports.default = void 0;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
10
- var _reactUtils = require("../../utils/react-utils");
11
10
  var _JFSThemeProvider = require("../../design-tokens/JFSThemeProvider");
12
- var _TextInput = _interopRequireDefault(require("../TextInput/TextInput"));
11
+ var _reactUtils = require("../../utils/react-utils");
13
12
  var _SupportText = _interopRequireDefault(require("../SupportText/SupportText"));
13
+ var _Icon = _interopRequireDefault(require("../../icons/Icon"));
14
+ var _Form = require("../Form/Form");
14
15
  var _jsxRuntime = require("react/jsx-runtime");
15
16
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
16
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); }
17
- function useFormField(props) {
18
- const {
19
- type = 'text',
20
- isDisabled = false,
21
- isInvalid = false,
22
- supportText,
23
- errorMessage,
24
- modes: propModes = _reactUtils.EMPTY_MODES,
25
- onFocus,
26
- onBlur
27
- } = props;
28
- const {
29
- modes: globalModes
30
- } = (0, _JFSThemeProvider.useTokens)();
31
- const baseModes = (0, _react.useMemo)(() => ({
32
- ...globalModes,
33
- ...propModes
34
- }), [globalModes, propModes]);
35
- const [isFocused, setIsFocused] = (0, _react.useState)(false);
18
+ // ---------------------------------------------------------------------------
19
+ // Token resolution
20
+ // ---------------------------------------------------------------------------
36
21
 
37
- // Merge FormField States collection based on focus
38
- const modes = (0, _react.useMemo)(() => ({
39
- ...baseModes,
40
- 'FormField States': isFocused ? 'Active' : 'Idle'
41
- }), [baseModes, isFocused]);
42
-
43
- // -- Label tokens (from "FormField / Output" collection) --
44
- const labelColor = (0, _figmaVariablesResolver.getVariableByName)('formField/label/color', modes) || '#0c0d10';
45
- const labelFontFamily = (0, _figmaVariablesResolver.getVariableByName)('formField/label/fontFamily', modes) || 'JioType Var';
46
- const labelFontSize = parseInt((0, _figmaVariablesResolver.getVariableByName)('formField/label/fontSize', modes), 10) || 14;
47
- const labelLineHeight = parseInt((0, _figmaVariablesResolver.getVariableByName)('formField/label/lineHeight', modes), 10) || 17;
48
- const labelFontWeight = (0, _figmaVariablesResolver.getVariableByName)('formField/label/fontWeight', modes) || '500';
49
- const gap = parseInt((0, _figmaVariablesResolver.getVariableByName)('formField/gap', modes), 10) || 8;
50
-
51
- // -- Input tokens (from "FormField / Output" + "FormField States" collections) --
52
- const inputPaddingH = parseInt((0, _figmaVariablesResolver.getVariableByName)('formField/input/padding/horizontal', modes), 10) || 12;
53
- const inputGap = parseInt((0, _figmaVariablesResolver.getVariableByName)('formField/input/gap', modes), 10) || 8;
54
- const inputRadius = parseInt((0, _figmaVariablesResolver.getVariableByName)('formField/input/radius', modes), 10) || 8;
55
- const inputBackground = (0, _figmaVariablesResolver.getVariableByName)('formField/input/background', modes) || '#ffffff';
56
- const inputFontSize = parseInt((0, _figmaVariablesResolver.getVariableByName)('formField/input/label/fontSize', modes), 10) || 16;
57
- const inputLineHeight = parseInt((0, _figmaVariablesResolver.getVariableByName)('formField/input/label/lineHeight', modes), 10) || 45;
58
- const inputFontFamily = (0, _figmaVariablesResolver.getVariableByName)('formField/input/label/fontFamily', modes) || 'JioType Var';
59
- const inputFontWeight = (0, _figmaVariablesResolver.getVariableByName)('formField/input/label/fontWeight', modes) || '400';
60
- const inputTextColor = (0, _figmaVariablesResolver.getVariableByName)('states/formField/input/label/color', modes) || (0, _figmaVariablesResolver.getVariableByName)('formField/input/label/color', modes) || '#24262b';
61
- const inputBorderColor = (0, _figmaVariablesResolver.getVariableByName)('states/formField/input/border/color', modes) || (0, _figmaVariablesResolver.getVariableByName)('formField/input/border/color', modes) || '#b5b6b7';
62
- const inputBorderSize = parseInt((0, _figmaVariablesResolver.getVariableByName)('formField/input/border/size', modes), 10) || 1;
63
-
64
- // -- Styles --
65
- const labelStyle = (0, _react.useMemo)(() => ({
66
- color: labelColor,
67
- fontFamily: labelFontFamily,
68
- fontSize: labelFontSize,
69
- lineHeight: labelLineHeight,
70
- fontWeight: labelFontWeight
71
- }), [labelColor, labelFontFamily, labelFontSize, labelLineHeight, labelFontWeight]);
72
- const wrapperStyle = (0, _react.useMemo)(() => ({
73
- gap,
74
- opacity: isDisabled ? 0.5 : 1
75
- }), [gap, isDisabled]);
76
- const requiredIndicatorStyle = (0, _react.useMemo)(() => ({
77
- color: '#d93d3d',
78
- fontFamily: labelFontFamily,
79
- fontSize: labelFontSize,
80
- lineHeight: labelLineHeight,
81
- fontWeight: labelFontWeight
82
- }), [labelFontFamily, labelFontSize, labelLineHeight, labelFontWeight]);
83
-
84
- // Style overrides for the input row, sourced from formField/input/* tokens
85
- const inputContainerStyle = (0, _react.useMemo)(() => ({
86
- backgroundColor: inputBackground,
87
- borderColor: inputBorderColor,
88
- borderWidth: inputBorderSize,
89
- borderRadius: inputRadius,
90
- paddingHorizontal: inputPaddingH,
91
- paddingVertical: 0,
92
- gap: inputGap
93
- }), [inputBackground, inputBorderColor, inputBorderSize, inputRadius, inputPaddingH, inputGap]);
94
- const inputTextStyle = (0, _react.useMemo)(() => ({
95
- color: inputTextColor,
96
- fontSize: inputFontSize,
97
- lineHeight: inputLineHeight,
98
- fontFamily: inputFontFamily,
99
- fontWeight: inputFontWeight
100
- }), [inputTextColor, inputFontSize, inputLineHeight, inputFontFamily, inputFontWeight]);
101
-
102
- // -- Support text logic --
103
- const supportStatus = isInvalid ? 'Error' : 'Neutral';
104
- const supportLabel = isInvalid && errorMessage ? errorMessage : supportText;
105
-
106
- // -- Input type derived props --
107
- const secureTextEntry = type === 'password';
108
- const keyboardType = type === 'email' ? 'email-address' : 'default';
109
- const autoCapitalize = type === 'email' || type === 'password' ? 'none' : 'sentences';
110
-
111
- // -- Event handlers --
112
- const handleFocus = (0, _react.useCallback)(e => {
113
- setIsFocused(true);
114
- onFocus?.(e);
115
- }, [onFocus]);
116
- const handleBlur = (0, _react.useCallback)(e => {
117
- setIsFocused(false);
118
- onBlur?.(e);
119
- }, [onBlur]);
120
- return {
121
- modes,
122
- labelStyle,
123
- wrapperStyle,
124
- requiredIndicatorStyle,
125
- inputContainerStyle,
126
- inputTextStyle,
127
- supportStatus,
128
- supportLabel,
129
- secureTextEntry,
130
- keyboardType,
131
- autoCapitalize,
132
- handleFocus,
133
- handleBlur
134
- };
22
+ function toNumber(value, fallback) {
23
+ if (typeof value === 'number' && Number.isFinite(value)) return value;
24
+ if (typeof value === 'string') {
25
+ const parsed = parseFloat(value);
26
+ if (Number.isFinite(parsed)) return parsed;
27
+ }
28
+ return fallback;
29
+ }
30
+ function toFontWeight(value, fallback) {
31
+ if (typeof value === 'number') return value.toString();
32
+ if (typeof value === 'string' && value.length > 0) return value;
33
+ return fallback;
34
+ }
35
+ function useFormFieldTokens(modes) {
36
+ return (0, _react.useMemo)(() => {
37
+ // Wrapper
38
+ const gap = toNumber((0, _figmaVariablesResolver.getVariableByName)('formField/gap', modes), 8);
39
+
40
+ // Label (Figma: 14/17 medium, color #0c0d10)
41
+ const labelColor = (0, _figmaVariablesResolver.getVariableByName)('formField/label/color', modes) || '#0c0d10';
42
+ const labelFontFamily = (0, _figmaVariablesResolver.getVariableByName)('formField/label/fontFamily', modes) || 'JioType Var';
43
+ const labelFontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('formField/label/fontSize', modes), 14);
44
+ const labelLineHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('formField/label/lineHeight', modes), 17);
45
+ const labelFontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('formField/label/fontWeight', modes), '500');
46
+
47
+ // Input row (Figma: 12 px padding-h, 8 px gap, 8 px radius, 1 px border)
48
+ const inputPaddingH = toNumber((0, _figmaVariablesResolver.getVariableByName)('formField/input/padding/horizontal', modes), 12);
49
+ const inputGap = toNumber((0, _figmaVariablesResolver.getVariableByName)('formField/input/gap', modes), 8);
50
+ const inputRadius = toNumber((0, _figmaVariablesResolver.getVariableByName)('formField/input/radius', modes), 8);
51
+ const inputBorderSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('formField/input/border/size', modes), 1);
52
+
53
+ // Input text (Figma: 16/45 regular)
54
+ const inputFontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('formField/input/label/fontSize', modes), 16);
55
+ const inputLineHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('formField/input/label/lineHeight', modes), 45);
56
+ const inputFontFamily = (0, _figmaVariablesResolver.getVariableByName)('formField/input/label/fontFamily', modes) || 'JioType Var';
57
+ const inputFontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('formField/input/label/fontWeight', modes), '400');
58
+ const inputBackground = (0, _figmaVariablesResolver.getVariableByName)('formField/input/background', modes) || '#ffffff';
59
+ const inputBorderColor = (0, _figmaVariablesResolver.getVariableByName)('formField/input/border/color', modes) || '#b5b6b7';
60
+ if (__DEV__) {
61
+ console.warn('[FormField] border color (modes changed)', {
62
+ 'FormField States': modes['FormField States'],
63
+ inputBorderColor,
64
+ 'formField/input/border/color': (0, _figmaVariablesResolver.getVariableByName)('formField/input/border/color', modes)
65
+ });
66
+ }
67
+ const inputTextColor = (0, _figmaVariablesResolver.getVariableByName)('formField/input/label/color', modes) || '#24262b';
68
+ return {
69
+ gap,
70
+ labelColor,
71
+ labelFontFamily,
72
+ labelFontSize,
73
+ labelLineHeight,
74
+ labelFontWeight,
75
+ inputPaddingH,
76
+ inputGap,
77
+ inputRadius,
78
+ inputBorderSize,
79
+ inputFontSize,
80
+ inputLineHeight,
81
+ inputFontFamily,
82
+ inputFontWeight,
83
+ inputBackground,
84
+ inputBorderColor,
85
+ inputTextColor
86
+ };
87
+ }, [modes]);
88
+ }
89
+
90
+ // ---------------------------------------------------------------------------
91
+ // Helpers
92
+ // ---------------------------------------------------------------------------
93
+
94
+ function deriveTypeProps(type) {
95
+ switch (type) {
96
+ case 'password':
97
+ return {
98
+ secureTextEntry: true,
99
+ keyboardType: 'default',
100
+ autoCapitalize: 'none',
101
+ autoComplete: 'password',
102
+ textContentType: 'password'
103
+ };
104
+ case 'email':
105
+ return {
106
+ secureTextEntry: false,
107
+ keyboardType: 'email-address',
108
+ autoCapitalize: 'none',
109
+ autoComplete: 'email',
110
+ textContentType: 'emailAddress'
111
+ };
112
+ case 'number':
113
+ return {
114
+ secureTextEntry: false,
115
+ keyboardType: 'numeric',
116
+ autoCapitalize: 'none',
117
+ autoComplete: 'off',
118
+ textContentType: 'none'
119
+ };
120
+ case 'phone':
121
+ return {
122
+ secureTextEntry: false,
123
+ keyboardType: 'phone-pad',
124
+ autoCapitalize: 'none',
125
+ autoComplete: 'tel',
126
+ textContentType: 'telephoneNumber'
127
+ };
128
+ case 'url':
129
+ return {
130
+ secureTextEntry: false,
131
+ keyboardType: 'url',
132
+ autoCapitalize: 'none',
133
+ autoComplete: 'url',
134
+ textContentType: 'URL'
135
+ };
136
+ case 'search':
137
+ return {
138
+ secureTextEntry: false,
139
+ keyboardType: 'default',
140
+ autoCapitalize: 'none',
141
+ autoComplete: 'off',
142
+ textContentType: 'none'
143
+ };
144
+ case 'text':
145
+ default:
146
+ return {
147
+ secureTextEntry: false,
148
+ keyboardType: 'default',
149
+ autoCapitalize: 'sentences',
150
+ autoComplete: 'off',
151
+ textContentType: 'none'
152
+ };
153
+ }
154
+ }
155
+ function firstError(error) {
156
+ if (!error) return undefined;
157
+ if (Array.isArray(error)) return error[0];
158
+ return error;
135
159
  }
160
+
161
+ // ---------------------------------------------------------------------------
162
+ // Component
163
+ // ---------------------------------------------------------------------------
164
+
136
165
  function FormField({
137
166
  label,
138
167
  placeholder,
139
- value = '',
168
+ value,
140
169
  onChangeText,
141
170
  type = 'text',
171
+ name,
142
172
  leading,
143
173
  trailing,
144
174
  leadingIconName,
145
175
  isRequired = false,
146
176
  isDisabled = false,
147
177
  isInvalid = false,
178
+ isReadOnly = false,
148
179
  supportText,
149
180
  errorMessage,
150
- modes = _reactUtils.EMPTY_MODES,
181
+ maxLength,
182
+ autoFocus = false,
183
+ modes: propModes = _reactUtils.EMPTY_MODES,
151
184
  style,
185
+ inputStyle,
186
+ inputTextStyle,
152
187
  onFocus,
153
188
  onBlur,
189
+ onSubmitEditing,
154
190
  accessibilityLabel,
155
- accessibilityHint
191
+ accessibilityHint,
192
+ testID
156
193
  }) {
194
+ // -- Form context integration -------------------------------------------
195
+ const formCtx = (0, _Form.useFormContext)();
196
+ const formError = name && formCtx ? firstError(formCtx.validationErrors[name]) : undefined;
197
+ const resolvedIsInvalid = isInvalid || Boolean(formError);
198
+ const resolvedErrorMessage = errorMessage ?? formError;
199
+
200
+ // -- Mode resolution ----------------------------------------------------
157
201
  const {
158
- modes: resolvedModes,
159
- labelStyle,
160
- wrapperStyle,
161
- requiredIndicatorStyle,
162
- inputContainerStyle,
163
- inputTextStyle,
164
- supportStatus,
165
- supportLabel,
166
- secureTextEntry,
167
- keyboardType,
168
- autoCapitalize,
169
- handleFocus,
170
- handleBlur
171
- } = useFormField({
172
- type,
173
- isDisabled,
174
- isInvalid,
175
- supportText,
176
- errorMessage,
177
- modes,
178
- onFocus,
179
- onBlur
180
- });
202
+ modes: globalModes
203
+ } = (0, _JFSThemeProvider.useTokens)();
204
+ const baseModes = (0, _react.useMemo)(() => ({
205
+ ...globalModes,
206
+ ...propModes
207
+ }), [globalModes, propModes]);
208
+ const [isFocused, setIsFocused] = (0, _react.useState)(false);
209
+ const interactive = !isDisabled && !isReadOnly;
210
+
211
+ // FormField States cascade — error > read only/disabled > active (focused) > idle.
212
+ // Disabled maps to "Read Only" since there is no dedicated disabled mode and
213
+ // the visual treatment is closest. This is only the DEFAULT — an explicit
214
+ // `modes['FormField States']` passed in via props or the global theme
215
+ // always wins so consumers can force a state (e.g. for documentation).
216
+ const derivedStateMode = (0, _react.useMemo)(() => {
217
+ if (resolvedIsInvalid) return 'Error';
218
+ if (isReadOnly || isDisabled) return 'Read Only';
219
+ if (isFocused) return 'Active';
220
+ return 'Idle';
221
+ }, [resolvedIsInvalid, isReadOnly, isDisabled, isFocused]);
222
+ const modes = (0, _react.useMemo)(() => {
223
+ const explicitStateMode = baseModes['FormField States'];
224
+ const stateMode = explicitStateMode ?? derivedStateMode;
225
+ const explicitStatus = baseModes.Status;
226
+ // Default SupportText token mode is Auto (Figma resolves foreground from
227
+ // context). Pass modes={{ Status: 'Error' }} etc. to override.
228
+ const status = explicitStatus ?? 'Auto';
229
+ return {
230
+ ...baseModes,
231
+ 'FormField States': stateMode,
232
+ Status: status
233
+ };
234
+ }, [baseModes, derivedStateMode]);
235
+ const tokens = useFormFieldTokens(modes);
236
+
237
+ // -- Type-derived input props ------------------------------------------
238
+ const typeProps = (0, _react.useMemo)(() => deriveTypeProps(type), [type]);
239
+
240
+ // -- Event handlers ----------------------------------------------------
241
+ const handleFocus = (0, _react.useCallback)(e => {
242
+ setIsFocused(true);
243
+ onFocus?.(e);
244
+ }, [onFocus]);
245
+ const handleBlur = (0, _react.useCallback)(e => {
246
+ setIsFocused(false);
247
+ onBlur?.(e);
248
+ }, [onBlur]);
249
+ const handleChangeText = (0, _react.useCallback)(next => {
250
+ onChangeText?.(next);
251
+ if (name && formCtx) formCtx.onFieldChange(name);
252
+ }, [onChangeText, name, formCtx]);
253
+
254
+ // -- Styles ------------------------------------------------------------
255
+ const wrapperStyle = (0, _react.useMemo)(() => ({
256
+ gap: tokens.gap,
257
+ opacity: isDisabled ? 0.5 : 1
258
+ }), [tokens.gap, isDisabled]);
259
+ const labelRowStyle = (0, _react.useMemo)(() => ({
260
+ flexDirection: 'row',
261
+ alignItems: 'baseline'
262
+ }), []);
263
+ const labelTextStyle = (0, _react.useMemo)(() => ({
264
+ color: tokens.labelColor,
265
+ fontFamily: tokens.labelFontFamily,
266
+ fontSize: tokens.labelFontSize,
267
+ lineHeight: tokens.labelLineHeight,
268
+ fontWeight: tokens.labelFontWeight
269
+ }), [tokens.labelColor, tokens.labelFontFamily, tokens.labelFontSize, tokens.labelLineHeight, tokens.labelFontWeight]);
270
+ const requiredIndicatorStyle = (0, _react.useMemo)(() => ({
271
+ ...labelTextStyle,
272
+ color: '#d93d3d'
273
+ }), [labelTextStyle]);
274
+ const inputRowStyle = (0, _react.useMemo)(() => ({
275
+ flexDirection: 'row',
276
+ alignItems: 'center',
277
+ backgroundColor: tokens.inputBackground,
278
+ borderColor: tokens.inputBorderColor,
279
+ borderWidth: tokens.inputBorderSize,
280
+ borderStyle: 'solid',
281
+ borderRadius: tokens.inputRadius,
282
+ paddingHorizontal: tokens.inputPaddingH,
283
+ paddingVertical: 0,
284
+ gap: tokens.inputGap,
285
+ minHeight: tokens.inputLineHeight,
286
+ width: '100%'
287
+ }), [tokens.inputBackground, tokens.inputBorderColor, tokens.inputBorderSize, tokens.inputRadius, tokens.inputPaddingH, tokens.inputGap, tokens.inputLineHeight]);
288
+ const inputTextStyles = (0, _react.useMemo)(() => ({
289
+ flex: 1,
290
+ color: tokens.inputTextColor,
291
+ fontFamily: tokens.inputFontFamily,
292
+ fontSize: tokens.inputFontSize,
293
+ lineHeight: tokens.inputLineHeight,
294
+ fontWeight: tokens.inputFontWeight,
295
+ padding: 0,
296
+ margin: 0,
297
+ // Remove the default web focus ring; the input row's border acts as the
298
+ // focus indicator via the FormField States cascade.
299
+ outlineStyle: 'none',
300
+ outlineWidth: 0,
301
+ outlineColor: 'transparent'
302
+ }), [tokens.inputTextColor, tokens.inputFontFamily, tokens.inputFontSize, tokens.inputLineHeight, tokens.inputFontWeight]);
303
+ const placeholderColor = (0, _react.useMemo)(() => {
304
+ // Slightly muted version of the resolved text color, mirroring the
305
+ // sibling TextInput behavior.
306
+ const c = tokens.inputTextColor;
307
+ if (typeof c !== 'string') return undefined;
308
+ if (c.startsWith('rgb(')) {
309
+ return c.replace('rgb(', 'rgba(').replace(')', ', 0.55)');
310
+ }
311
+ return '#888a8d';
312
+ }, [tokens.inputTextColor]);
313
+
314
+ // -- Slots --------------------------------------------------------------
315
+ const leadingElement = leading ?? (leadingIconName ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.default, {
316
+ name: leadingIconName,
317
+ size: 20,
318
+ color: tokens.inputTextColor
319
+ }) : null);
320
+ const processedLeading = leadingElement ? (0, _reactUtils.cloneChildrenWithModes)(leadingElement, modes) : null;
321
+ const processedTrailing = trailing ? (0, _reactUtils.cloneChildrenWithModes)(trailing, modes) : null;
322
+
323
+ // -- Support text -------------------------------------------------------
324
+ const supportStatus = resolvedIsInvalid ? 'Error' : 'Neutral';
325
+ const supportLabel = resolvedIsInvalid && resolvedErrorMessage ? resolvedErrorMessage : supportText;
326
+
327
+ // -- Accessibility ------------------------------------------------------
181
328
  const resolvedA11yLabel = accessibilityLabel || label || placeholder || 'Form field';
182
329
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
183
330
  style: [wrapperStyle, style],
184
331
  pointerEvents: isDisabled ? 'none' : 'auto',
185
- accessible: true,
186
- accessibilityRole: "none",
187
- accessibilityLabel: resolvedA11yLabel,
188
- accessibilityState: {
189
- disabled: isDisabled
190
- },
332
+ testID: testID,
333
+ accessible: false,
191
334
  children: [label != null && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
192
- style: {
193
- flexDirection: 'row',
194
- alignItems: 'baseline'
195
- },
335
+ style: labelRowStyle,
196
336
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
197
- style: labelStyle,
337
+ style: labelTextStyle,
198
338
  children: label
199
339
  }), isRequired && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
200
340
  style: requiredIndicatorStyle,
201
341
  children: " *"
202
342
  })]
203
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_TextInput.default, {
204
- placeholder: placeholder || '',
205
- value: value,
206
- ...(onChangeText ? {
207
- onChangeText
208
- } : {}),
209
- leading: leading,
210
- trailing: trailing,
211
- leadingIconName: leadingIconName || 'ic_search',
212
- modes: resolvedModes,
213
- style: inputContainerStyle,
214
- inputStyle: inputTextStyle,
215
- onFocus: handleFocus,
216
- onBlur: handleBlur,
217
- secureTextEntry: secureTextEntry,
218
- keyboardType: keyboardType,
219
- autoCapitalize: autoCapitalize,
220
- editable: !isDisabled,
221
- accessibilityLabel: resolvedA11yLabel,
222
- accessibilityHint: accessibilityHint || ''
223
- }), supportLabel != null && /*#__PURE__*/(0, _jsxRuntime.jsx)(_SupportText.default, {
343
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
344
+ style: [inputRowStyle, inputStyle],
345
+ children: [processedLeading != null && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
346
+ accessibilityElementsHidden: true,
347
+ importantForAccessibility: "no",
348
+ children: processedLeading
349
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
350
+ style: [inputTextStyles, inputTextStyle],
351
+ value: value ?? '',
352
+ onChangeText: handleChangeText,
353
+ onFocus: handleFocus,
354
+ onBlur: handleBlur,
355
+ onSubmitEditing: onSubmitEditing,
356
+ placeholder: placeholder ?? '',
357
+ placeholderTextColor: placeholderColor,
358
+ editable: interactive,
359
+ maxLength: maxLength,
360
+ autoFocus: autoFocus,
361
+ secureTextEntry: typeProps.secureTextEntry,
362
+ keyboardType: typeProps.keyboardType,
363
+ autoCapitalize: typeProps.autoCapitalize,
364
+ autoComplete: typeProps.autoComplete,
365
+ textContentType: typeProps.textContentType,
366
+ accessibilityLabel: resolvedA11yLabel,
367
+ accessibilityHint: accessibilityHint
368
+ }), processedTrailing != null && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
369
+ accessibilityElementsHidden: true,
370
+ importantForAccessibility: "no",
371
+ children: processedTrailing
372
+ })]
373
+ }), supportLabel != null && supportLabel !== '' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_SupportText.default, {
224
374
  label: supportLabel,
225
375
  status: supportStatus,
226
- modes: resolvedModes
376
+ modes: modes
227
377
  })]
228
378
  });
229
379
  }
@@ -9,6 +9,7 @@ var _reactNative = require("react-native");
9
9
  var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
10
10
  var _reactUtils = require("../../utils/react-utils");
11
11
  var _MoneyValue = _interopRequireDefault(require("../MoneyValue/MoneyValue"));
12
+ var _LinearProgress = _interopRequireDefault(require("../LinearProgress/LinearProgress"));
12
13
  var _jsxRuntime = require("react/jsx-runtime");
13
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
15
  const LinearMeterLabel = ({
@@ -46,14 +47,6 @@ const LinearMeter = ({
46
47
  ...rest
47
48
  }) => {
48
49
  const gap = (0, _figmaVariablesResolver.getVariableByName)('linearMeter/gap', modes);
49
- // Track tokens
50
- const trackBg = (0, _figmaVariablesResolver.getVariableByName)('linearMeter/track/background', modes);
51
- const trackHeight = (0, _figmaVariablesResolver.getVariableByName)('linearMeter/track/height', modes);
52
- const trackRadius = (0, _figmaVariablesResolver.getVariableByName)('linearMeter/track/radius', modes);
53
-
54
- // Indicator tokens
55
- const indicatorBg = (0, _figmaVariablesResolver.getVariableByName)('linearMeter/indicator/background', modes);
56
- const indicatorRadius = (0, _figmaVariablesResolver.getVariableByName)('linearMeter/indicator/radius', modes);
57
50
 
58
51
  // Wrap tokens
59
52
  const wrapGap = (0, _figmaVariablesResolver.getVariableByName)('linearMeter/wrap/gap', modes);
@@ -91,10 +84,6 @@ const LinearMeter = ({
91
84
  })]
92
85
  });
93
86
  const content = children ? childrenWithModes : defaultContent;
94
-
95
- // Calculate width percentage
96
- const clampedValue = Math.min(Math.max(value, 0), 1);
97
- const widthPercent = `${clampedValue * 100}%`;
98
87
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
99
88
  style: [{
100
89
  flexDirection: 'row',
@@ -102,22 +91,14 @@ const LinearMeter = ({
102
91
  gap
103
92
  }, style],
104
93
  ...rest,
105
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
106
- style: [{
107
- flex: 1,
108
- height: trackHeight,
109
- backgroundColor: trackBg,
110
- borderRadius: trackRadius,
111
- overflow: 'hidden' // Ensure indicator stays inside
112
- }, trackStyle],
113
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
114
- style: [{
115
- width: widthPercent,
116
- height: '100%',
117
- backgroundColor: indicatorBg,
118
- borderRadius: indicatorRadius
119
- }, indicatorStyle]
120
- })
94
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_LinearProgress.default, {
95
+ value: value,
96
+ modes: modes,
97
+ style: {
98
+ flex: 1
99
+ },
100
+ trackStyle: trackStyle,
101
+ indicatorStyle: indicatorStyle
121
102
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
122
103
  style: {
123
104
  flexDirection: 'row',