jfs-components 0.0.74 → 0.0.78

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 (146) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/lib/commonjs/components/Accordion/Accordion.js +55 -55
  3. package/lib/commonjs/components/ActionFooter/ActionFooter.js +193 -82
  4. package/lib/commonjs/components/Avatar/Avatar.js +20 -0
  5. package/lib/commonjs/components/Badge/Badge.js +23 -0
  6. package/lib/commonjs/components/Button/Button.js +37 -0
  7. package/lib/commonjs/components/Checkbox/Checkbox.js +21 -9
  8. package/lib/commonjs/components/DropdownInput/DropdownInput.js +30 -16
  9. package/lib/commonjs/components/ExpandableCheckbox/ExpandableCheckbox.js +167 -0
  10. package/lib/commonjs/components/FormField/FormField.js +14 -1
  11. package/lib/commonjs/components/FullscreenModal/FullscreenModal.js +355 -0
  12. package/lib/commonjs/components/IconButton/IconButton.js +20 -0
  13. package/lib/commonjs/components/Image/Image.js +26 -1
  14. package/lib/commonjs/components/ListItem/ListItem.js +25 -10
  15. package/lib/commonjs/components/LottiePlayer/LottiePlayer.js +116 -0
  16. package/lib/commonjs/components/LottiePlayer/LottiePlayer.web.js +82 -0
  17. package/lib/commonjs/components/LottiePlayer/loadNativeLottieView.js +74 -0
  18. package/lib/commonjs/components/LottiePlayer/loadWebLottieView.js +50 -0
  19. package/lib/commonjs/components/MessageField/MessageField.js +318 -0
  20. package/lib/commonjs/components/NavArrow/NavArrow.js +58 -17
  21. package/lib/commonjs/components/PageHero/PageHero.js +41 -5
  22. package/lib/commonjs/components/RechargeCard/RechargeCard.js +32 -17
  23. package/lib/commonjs/components/Stepper/Step.js +47 -60
  24. package/lib/commonjs/components/Stepper/StepLabel.js +40 -10
  25. package/lib/commonjs/components/Stepper/Stepper.js +15 -17
  26. package/lib/commonjs/components/SuggestiveSearch/SuggestiveSearch.js +487 -0
  27. package/lib/commonjs/components/Text/Text.js +31 -1
  28. package/lib/commonjs/components/TextInput/TextInput.js +16 -1
  29. package/lib/commonjs/components/Title/Title.js +10 -2
  30. package/lib/commonjs/components/index.js +35 -0
  31. package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
  32. package/lib/commonjs/icons/Icon.js +16 -0
  33. package/lib/commonjs/icons/registry.js +1 -1
  34. package/lib/commonjs/index.js +12 -0
  35. package/lib/commonjs/skeleton/Skeleton.js +234 -0
  36. package/lib/commonjs/skeleton/SkeletonGroup.js +140 -0
  37. package/lib/commonjs/skeleton/index.js +58 -0
  38. package/lib/commonjs/skeleton/shimmer-tokens.js +189 -0
  39. package/lib/commonjs/skeleton/useReducedMotion.js +64 -0
  40. package/lib/module/components/Accordion/Accordion.js +56 -56
  41. package/lib/module/components/ActionFooter/ActionFooter.js +193 -83
  42. package/lib/module/components/Avatar/Avatar.js +19 -0
  43. package/lib/module/components/Badge/Badge.js +23 -0
  44. package/lib/module/components/Button/Button.js +37 -0
  45. package/lib/module/components/Checkbox/Checkbox.js +22 -10
  46. package/lib/module/components/DropdownInput/DropdownInput.js +30 -16
  47. package/lib/module/components/ExpandableCheckbox/ExpandableCheckbox.js +161 -0
  48. package/lib/module/components/FormField/FormField.js +16 -3
  49. package/lib/module/components/FullscreenModal/FullscreenModal.js +350 -0
  50. package/lib/module/components/IconButton/IconButton.js +20 -0
  51. package/lib/module/components/Image/Image.js +25 -1
  52. package/lib/module/components/ListItem/ListItem.js +25 -10
  53. package/lib/module/components/LottiePlayer/LottiePlayer.js +111 -0
  54. package/lib/module/components/LottiePlayer/LottiePlayer.web.js +77 -0
  55. package/lib/module/components/LottiePlayer/loadNativeLottieView.js +69 -0
  56. package/lib/module/components/LottiePlayer/loadWebLottieView.js +45 -0
  57. package/lib/module/components/MessageField/MessageField.js +313 -0
  58. package/lib/module/components/NavArrow/NavArrow.js +59 -18
  59. package/lib/module/components/PageHero/PageHero.js +41 -5
  60. package/lib/module/components/RechargeCard/RechargeCard.js +33 -17
  61. package/lib/module/components/Stepper/Step.js +48 -61
  62. package/lib/module/components/Stepper/StepLabel.js +40 -10
  63. package/lib/module/components/Stepper/Stepper.js +15 -17
  64. package/lib/module/components/SuggestiveSearch/SuggestiveSearch.js +481 -0
  65. package/lib/module/components/Text/Text.js +31 -1
  66. package/lib/module/components/TextInput/TextInput.js +17 -2
  67. package/lib/module/components/Title/Title.js +10 -2
  68. package/lib/module/components/index.js +5 -0
  69. package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
  70. package/lib/module/icons/Icon.js +16 -0
  71. package/lib/module/icons/registry.js +1 -1
  72. package/lib/module/index.js +2 -1
  73. package/lib/module/skeleton/Skeleton.js +229 -0
  74. package/lib/module/skeleton/SkeletonGroup.js +133 -0
  75. package/lib/module/skeleton/index.js +6 -0
  76. package/lib/module/skeleton/shimmer-tokens.js +181 -0
  77. package/lib/module/skeleton/useReducedMotion.js +61 -0
  78. package/lib/typescript/src/components/Accordion/Accordion.d.ts +14 -20
  79. package/lib/typescript/src/components/ActionFooter/ActionFooter.d.ts +26 -21
  80. package/lib/typescript/src/components/Avatar/Avatar.d.ts +7 -1
  81. package/lib/typescript/src/components/Badge/Badge.d.ts +7 -1
  82. package/lib/typescript/src/components/Button/Button.d.ts +8 -1
  83. package/lib/typescript/src/components/ExpandableCheckbox/ExpandableCheckbox.d.ts +63 -0
  84. package/lib/typescript/src/components/FullscreenModal/FullscreenModal.d.ts +99 -0
  85. package/lib/typescript/src/components/IconButton/IconButton.d.ts +7 -1
  86. package/lib/typescript/src/components/Image/Image.d.ts +8 -1
  87. package/lib/typescript/src/components/LottiePlayer/LottiePlayer.d.ts +85 -0
  88. package/lib/typescript/src/components/LottiePlayer/LottiePlayer.web.d.ts +28 -0
  89. package/lib/typescript/src/components/LottiePlayer/loadNativeLottieView.d.ts +11 -0
  90. package/lib/typescript/src/components/LottiePlayer/loadWebLottieView.d.ts +11 -0
  91. package/lib/typescript/src/components/MessageField/MessageField.d.ts +81 -0
  92. package/lib/typescript/src/components/NavArrow/NavArrow.d.ts +10 -5
  93. package/lib/typescript/src/components/PageHero/PageHero.d.ts +31 -5
  94. package/lib/typescript/src/components/Stepper/Step.d.ts +4 -1
  95. package/lib/typescript/src/components/Stepper/StepLabel.d.ts +4 -1
  96. package/lib/typescript/src/components/Stepper/Stepper.d.ts +3 -1
  97. package/lib/typescript/src/components/SuggestiveSearch/SuggestiveSearch.d.ts +123 -0
  98. package/lib/typescript/src/components/Text/Text.d.ts +20 -1
  99. package/lib/typescript/src/components/index.d.ts +8 -3
  100. package/lib/typescript/src/icons/Icon.d.ts +7 -1
  101. package/lib/typescript/src/icons/registry.d.ts +1 -1
  102. package/lib/typescript/src/index.d.ts +1 -0
  103. package/lib/typescript/src/skeleton/Skeleton.d.ts +60 -0
  104. package/lib/typescript/src/skeleton/SkeletonGroup.d.ts +78 -0
  105. package/lib/typescript/src/skeleton/index.d.ts +5 -0
  106. package/lib/typescript/src/skeleton/shimmer-tokens.d.ts +160 -0
  107. package/lib/typescript/src/skeleton/useReducedMotion.d.ts +15 -0
  108. package/package.json +11 -1
  109. package/src/components/Accordion/Accordion.tsx +113 -73
  110. package/src/components/ActionFooter/ActionFooter.tsx +210 -92
  111. package/src/components/Avatar/Avatar.tsx +26 -0
  112. package/src/components/Badge/Badge.tsx +27 -0
  113. package/src/components/Button/Button.tsx +40 -0
  114. package/src/components/Checkbox/Checkbox.tsx +22 -9
  115. package/src/components/DropdownInput/DropdownInput.tsx +67 -39
  116. package/src/components/ExpandableCheckbox/ExpandableCheckbox.tsx +237 -0
  117. package/src/components/FormField/FormField.tsx +19 -3
  118. package/src/components/FullscreenModal/FullscreenModal.tsx +414 -0
  119. package/src/components/IconButton/IconButton.tsx +27 -0
  120. package/src/components/Image/Image.tsx +25 -0
  121. package/src/components/ListItem/ListItem.tsx +21 -10
  122. package/src/components/LottiePlayer/LottiePlayer.tsx +145 -0
  123. package/src/components/LottiePlayer/LottiePlayer.web.tsx +94 -0
  124. package/src/components/LottiePlayer/loadNativeLottieView.tsx +87 -0
  125. package/src/components/LottiePlayer/loadWebLottieView.tsx +64 -0
  126. package/src/components/MessageField/MessageField.tsx +543 -0
  127. package/src/components/NavArrow/NavArrow.tsx +81 -17
  128. package/src/components/PageHero/PageHero.tsx +61 -4
  129. package/src/components/RechargeCard/RechargeCard.tsx +32 -24
  130. package/src/components/Stepper/Step.tsx +52 -51
  131. package/src/components/Stepper/StepLabel.tsx +46 -9
  132. package/src/components/Stepper/Stepper.tsx +20 -15
  133. package/src/components/SuggestiveSearch/SuggestiveSearch.tsx +756 -0
  134. package/src/components/Text/Text.tsx +54 -0
  135. package/src/components/TextInput/TextInput.tsx +14 -1
  136. package/src/components/Title/Title.tsx +13 -2
  137. package/src/components/index.ts +8 -3
  138. package/src/design-tokens/Coin Variables-variables-full.json +1 -1
  139. package/src/icons/Icon.tsx +17 -0
  140. package/src/icons/registry.ts +1 -1
  141. package/src/index.ts +1 -0
  142. package/src/skeleton/Skeleton.tsx +298 -0
  143. package/src/skeleton/SkeletonGroup.tsx +193 -0
  144. package/src/skeleton/index.ts +10 -0
  145. package/src/skeleton/shimmer-tokens.ts +221 -0
  146. package/src/skeleton/useReducedMotion.ts +72 -0
@@ -0,0 +1,82 @@
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 _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
9
+ var _JFSThemeProvider = require("../../design-tokens/JFSThemeProvider");
10
+ var _reactUtils = require("../../utils/react-utils");
11
+ var _loadWebLottieView = require("./loadWebLottieView");
12
+ var _jsxRuntime = require("react/jsx-runtime");
13
+ 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); }
14
+ const DEFAULT_SIZE = 117;
15
+ function resolveSize(size, modes) {
16
+ if (typeof size === 'number') return {
17
+ width: size,
18
+ height: size
19
+ };
20
+ if (size && typeof size === 'object') return size;
21
+ const width = Number((0, _figmaVariablesResolver.getVariableByName)('media/width', modes)) || DEFAULT_SIZE;
22
+ const height = Number((0, _figmaVariablesResolver.getVariableByName)('media/height', modes)) || DEFAULT_SIZE;
23
+ return {
24
+ width,
25
+ height
26
+ };
27
+ }
28
+
29
+ /**
30
+ * Web build of `LottiePlayer` — picked automatically by webpack /
31
+ * Metro-for-web via the `.web.tsx` platform extension. Uses `lottie-react`
32
+ * (which wraps `lottie-web`) and renders a plain DOM container.
33
+ *
34
+ * Public API mirrors `LottiePlayer.tsx` (native). See that file for the
35
+ * documented prop reference and usage patterns.
36
+ */
37
+ function LottiePlayer({
38
+ source,
39
+ size,
40
+ autoPlay = true,
41
+ loop = true,
42
+ modes: propModes = _reactUtils.EMPTY_MODES,
43
+ style,
44
+ accessibilityLabel,
45
+ testID
46
+ }) {
47
+ const {
48
+ modes: globalModes
49
+ } = (0, _JFSThemeProvider.useTokens)();
50
+ const modes = (0, _react.useMemo)(() => globalModes === _reactUtils.EMPTY_MODES && propModes === _reactUtils.EMPTY_MODES ? _reactUtils.EMPTY_MODES : {
51
+ ...globalModes,
52
+ ...propModes
53
+ }, [globalModes, propModes]);
54
+ const {
55
+ width,
56
+ height
57
+ } = (0, _react.useMemo)(() => resolveSize(size, modes), [size, modes]);
58
+ const WebLottieView = (0, _react.useMemo)(() => (0, _loadWebLottieView.getWebLottieView)(), []);
59
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
60
+ style: {
61
+ width,
62
+ height,
63
+ display: 'flex',
64
+ alignItems: 'center',
65
+ justifyContent: 'center',
66
+ ...style
67
+ },
68
+ "data-testid": testID,
69
+ "aria-label": accessibilityLabel,
70
+ "aria-hidden": accessibilityLabel ? undefined : true,
71
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(WebLottieView, {
72
+ animationData: source,
73
+ autoplay: autoPlay,
74
+ loop: loop,
75
+ style: {
76
+ width: '100%',
77
+ height: '100%'
78
+ }
79
+ })
80
+ });
81
+ }
82
+ var _default = exports.default = /*#__PURE__*/_react.default.memo(LottiePlayer);
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getNativeLottieView = getNativeLottieView;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var _jsxRuntime = require("react/jsx-runtime");
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
+ /** Props we forward to the underlying native Lottie view. */
12
+
13
+ const INSTALL_HINT = 'LottiePlayer requires lottie-react-native in your app.\n' + ' npm install lottie-react-native\n' + ' cd ios && pod install';
14
+
15
+ /**
16
+ * Metro resolves `require('lottie-react-native')` at bundle time even inside
17
+ * try/catch, which breaks apps that import `jfs-components` without having
18
+ * the optional peer installed. Splitting the module id into a runtime string
19
+ * keeps Metro from statically linking it — the native module is loaded only
20
+ * when present in the consumer's node_modules.
21
+ */
22
+ function resolveNativeLottieModuleName() {
23
+ return ['lottie', '-react', '-native'].join('');
24
+ }
25
+ function LottieUnavailableView({
26
+ style
27
+ }) {
28
+ if (__DEV__) {
29
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
30
+ style: [style, {
31
+ alignItems: 'center',
32
+ justifyContent: 'center',
33
+ backgroundColor: 'rgba(255, 196, 0, 0.12)',
34
+ borderWidth: 1,
35
+ borderColor: 'rgba(255, 196, 0, 0.45)',
36
+ borderRadius: 8,
37
+ padding: 8
38
+ }],
39
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
40
+ style: {
41
+ color: '#8a6d00',
42
+ fontSize: 11,
43
+ textAlign: 'center',
44
+ lineHeight: 15
45
+ },
46
+ children: INSTALL_HINT
47
+ })
48
+ });
49
+ }
50
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
51
+ style: style
52
+ });
53
+ }
54
+ function LottieUnavailable(props) {
55
+ _react.default.useEffect(() => {
56
+ if (__DEV__) {
57
+ console.warn(`[jfs-components/LottiePlayer] ${INSTALL_HINT}`);
58
+ }
59
+ }, []);
60
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(LottieUnavailableView, {
61
+ style: props.style
62
+ });
63
+ }
64
+ let cachedView;
65
+ function getNativeLottieView() {
66
+ if (cachedView !== undefined) return cachedView;
67
+ try {
68
+ const mod = require(resolveNativeLottieModuleName());
69
+ cachedView = mod.default ?? LottieUnavailable;
70
+ } catch {
71
+ cachedView = LottieUnavailable;
72
+ }
73
+ return cachedView;
74
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getWebLottieView = getWebLottieView;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _jsxRuntime = require("react/jsx-runtime");
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
+ /** Props we forward to the underlying web Lottie view. */
11
+
12
+ const INSTALL_HINT = 'LottiePlayer requires lottie-react in your app.\n' + ' npm install lottie-react';
13
+ function resolveWebLottieModuleName() {
14
+ return ['lottie', '-react'].join('');
15
+ }
16
+ function LottieUnavailable(props) {
17
+ _react.default.useEffect(() => {
18
+ if (typeof __DEV__ !== 'undefined' && __DEV__) {
19
+ console.warn(`[jfs-components/LottiePlayer] ${INSTALL_HINT}`);
20
+ }
21
+ }, []);
22
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
23
+ style: {
24
+ ...props.style,
25
+ display: 'flex',
26
+ alignItems: 'center',
27
+ justifyContent: 'center',
28
+ backgroundColor: 'rgba(255, 196, 0, 0.12)',
29
+ border: '1px solid rgba(255, 196, 0, 0.45)',
30
+ borderRadius: 8,
31
+ padding: 8,
32
+ color: '#8a6d00',
33
+ fontSize: 11,
34
+ textAlign: 'center',
35
+ lineHeight: '15px'
36
+ },
37
+ children: typeof __DEV__ !== 'undefined' && __DEV__ ? INSTALL_HINT : null
38
+ });
39
+ }
40
+ let cachedView;
41
+ function getWebLottieView() {
42
+ if (cachedView !== undefined) return cachedView;
43
+ try {
44
+ const mod = require(resolveWebLottieModuleName());
45
+ cachedView = mod.default ?? LottieUnavailable;
46
+ } catch {
47
+ cachedView = LottieUnavailable;
48
+ }
49
+ return cachedView;
50
+ }
@@ -0,0 +1,318 @@
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 _JFSThemeProvider = require("../../design-tokens/JFSThemeProvider");
11
+ var _reactUtils = require("../../utils/react-utils");
12
+ var _Form = require("../Form/Form");
13
+ var _jsxRuntime = require("react/jsx-runtime");
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
+ // ---------------------------------------------------------------------------
16
+ // Types
17
+ // ---------------------------------------------------------------------------
18
+
19
+ /**
20
+ * Visual state of the textarea. Mirrors the `FormField States` collection so
21
+ * MessageField slots into the same theming pipeline as FormField. The state
22
+ * is always derived from props (`isInvalid`, `isDisabled`, `isReadOnly` and
23
+ * focus) and is locked in `modes['FormField States']` — passing that key in
24
+ * `modes` is intentionally ignored to keep interactive behaviour and visual
25
+ * state in sync.
26
+ */
27
+
28
+ // ---------------------------------------------------------------------------
29
+ // Token helpers
30
+ // ---------------------------------------------------------------------------
31
+
32
+ function toNumber(value, fallback) {
33
+ if (typeof value === 'number' && Number.isFinite(value)) return value;
34
+ if (typeof value === 'string') {
35
+ const parsed = parseFloat(value);
36
+ if (Number.isFinite(parsed)) return parsed;
37
+ }
38
+ return fallback;
39
+ }
40
+ function toFontWeight(value, fallback) {
41
+ if (typeof value === 'number') return value.toString();
42
+ if (typeof value === 'string' && value.length > 0) return value;
43
+ return fallback;
44
+ }
45
+ function firstError(error) {
46
+ if (!error) return undefined;
47
+ if (Array.isArray(error)) return error[0];
48
+ return error;
49
+ }
50
+ function useMessageFieldTokens(modes) {
51
+ return (0, _react.useMemo)(() => {
52
+ const wrapperGap = toNumber((0, _figmaVariablesResolver.getVariableByName)('messageField/gap', modes), 8);
53
+ const labelColor = (0, _figmaVariablesResolver.getVariableByName)('messageField/label/foreground', modes) || '#000000';
54
+ const labelFontFamily = (0, _figmaVariablesResolver.getVariableByName)('messageField/label/fontFamily', modes) || 'JioType Var';
55
+ const labelFontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('messageField/label/fontSize', modes), 14);
56
+ const labelLineHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('messageField/label/lineHeight', modes), 17);
57
+ const labelFontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('messageField/label/fontWeight', modes), '500');
58
+ const textareaBackground = (0, _figmaVariablesResolver.getVariableByName)('messageField/textarea/background', modes) || '#ffffff';
59
+ const textareaBorderColor = (0, _figmaVariablesResolver.getVariableByName)('messageField/textarea/border/color', modes) || '#b5b6b7';
60
+ const textareaBorderSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('messageField/textarea/border/size', modes), 1.5);
61
+ const textareaRadius = toNumber((0, _figmaVariablesResolver.getVariableByName)('messageField/textarea/radius', modes), 8);
62
+ const textareaPadding = toNumber((0, _figmaVariablesResolver.getVariableByName)('messageField/textarea/padding', modes), 12);
63
+ const textareaHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('messageField/textarea/height', modes), 108);
64
+ const textareaGap = toNumber((0, _figmaVariablesResolver.getVariableByName)('messageField/textarea/gap', modes), 0);
65
+
66
+ // `messageField/text/foreground` is the input text color. It also
67
+ // serves as the placeholder color — in mode-aware token sets it
68
+ // resolves to a muted/idle color when empty and shifts darker via
69
+ // the `FormField States` cascade once typed-state tokens land. We
70
+ // never re-route this through another token (e.g. the counter
71
+ // color) because that conflates two semantically distinct tokens.
72
+ const inputTextColor = (0, _figmaVariablesResolver.getVariableByName)('messageField/text/foreground', modes) || '#707275';
73
+ const inputFontFamily = (0, _figmaVariablesResolver.getVariableByName)('messageField/text/fontFamily', modes) || 'JioType Var';
74
+ const inputFontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('messageField/text/fontSize', modes), 16);
75
+ const inputLineHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('messageField/text/lineHeight', modes), 21);
76
+ const inputFontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('messageField/text/fontWeight', modes), '400');
77
+ const counterColor = (0, _figmaVariablesResolver.getVariableByName)('messageField/maxLength/foreground', modes) || '#24262b';
78
+ const counterFontFamily = (0, _figmaVariablesResolver.getVariableByName)('messageField/maxLength/fontFamily', modes) || 'JioType Var';
79
+ const counterFontSize = toNumber((0, _figmaVariablesResolver.getVariableByName)('messageField/maxLength/fontSize', modes), 14);
80
+ const counterLineHeight = toNumber((0, _figmaVariablesResolver.getVariableByName)('messageField/maxLength/lineHeight', modes), 18);
81
+ const counterFontWeight = toFontWeight((0, _figmaVariablesResolver.getVariableByName)('messageField/maxLength/fontWeight', modes), '400');
82
+ return {
83
+ wrapperGap,
84
+ labelColor,
85
+ labelFontFamily,
86
+ labelFontSize,
87
+ labelLineHeight,
88
+ labelFontWeight,
89
+ textareaBackground,
90
+ textareaBorderColor,
91
+ textareaBorderSize,
92
+ textareaRadius,
93
+ textareaPadding,
94
+ textareaHeight,
95
+ textareaGap,
96
+ inputTextColor,
97
+ inputFontFamily,
98
+ inputFontSize,
99
+ inputLineHeight,
100
+ inputFontWeight,
101
+ counterColor,
102
+ counterFontFamily,
103
+ counterFontSize,
104
+ counterLineHeight,
105
+ counterFontWeight
106
+ };
107
+ }, [modes]);
108
+ }
109
+
110
+ // ---------------------------------------------------------------------------
111
+ // Component
112
+ // ---------------------------------------------------------------------------
113
+
114
+ const REQUIRED_INDICATOR_COLOR = '#d93d3d';
115
+ function MessageField({
116
+ label,
117
+ placeholder,
118
+ value,
119
+ defaultValue,
120
+ onChangeText,
121
+ name,
122
+ maxLength,
123
+ showCounter,
124
+ rows,
125
+ isRequired = false,
126
+ isDisabled = false,
127
+ isInvalid = false,
128
+ isReadOnly = false,
129
+ autoFocus = false,
130
+ modes: propModes = _reactUtils.EMPTY_MODES,
131
+ style,
132
+ textareaStyle,
133
+ inputStyle,
134
+ accessibilityLabel,
135
+ accessibilityHint,
136
+ testID,
137
+ onFocus,
138
+ onBlur
139
+ }) {
140
+ const formCtx = (0, _Form.useFormContext)();
141
+ const formError = name && formCtx ? firstError(formCtx.validationErrors[name]) : undefined;
142
+ const resolvedIsInvalid = isInvalid || Boolean(formError);
143
+ const isControlled = value !== undefined;
144
+ const [uncontrolledValue, setUncontrolledValue] = (0, _react.useState)(defaultValue ?? '');
145
+ const currentValue = isControlled ? value : uncontrolledValue;
146
+ const [isFocused, setIsFocused] = (0, _react.useState)(false);
147
+ const interactive = !isDisabled && !isReadOnly;
148
+
149
+ // Ref to the native textarea so tapping anywhere in the (padded) textarea
150
+ // container focuses it on the FIRST tap, fixing the Android "two taps to
151
+ // open the keyboard" issue.
152
+ const inputRef = (0, _react.useRef)(null);
153
+ const focusInput = (0, _react.useCallback)(() => {
154
+ if (!interactive) return;
155
+ inputRef.current?.focus();
156
+ }, [interactive]);
157
+ const {
158
+ modes: globalModes
159
+ } = (0, _JFSThemeProvider.useTokens)();
160
+ const baseModes = (0, _react.useMemo)(() => ({
161
+ ...globalModes,
162
+ ...propModes
163
+ }), [globalModes, propModes]);
164
+
165
+ // FormField States cascade — error > disabled > read only > active (focus)
166
+ // > idle. Always derived from props and locked into the modes object so
167
+ // consumers cannot pass `modes={{ 'FormField States': ... }}` and get out
168
+ // of sync with the component's actual interactive behaviour.
169
+ const stateMode = (0, _react.useMemo)(() => {
170
+ if (resolvedIsInvalid) return 'Error';
171
+ if (isDisabled) return 'Disabled';
172
+ if (isReadOnly) return 'Read Only';
173
+ if (isFocused) return 'Active';
174
+ return 'Idle';
175
+ }, [resolvedIsInvalid, isDisabled, isReadOnly, isFocused]);
176
+ const modes = (0, _react.useMemo)(() => ({
177
+ ...baseModes,
178
+ 'FormField States': stateMode
179
+ }), [baseModes, stateMode]);
180
+ const tokens = useMessageFieldTokens(modes);
181
+
182
+ // ---------- Event handlers ---------------------------------------------
183
+ const handleFocus = (0, _react.useCallback)(e => {
184
+ setIsFocused(true);
185
+ onFocus?.(e);
186
+ }, [onFocus]);
187
+ const handleBlur = (0, _react.useCallback)(e => {
188
+ setIsFocused(false);
189
+ onBlur?.(e);
190
+ }, [onBlur]);
191
+ const handleChangeText = (0, _react.useCallback)(next => {
192
+ if (!isControlled) {
193
+ setUncontrolledValue(next);
194
+ }
195
+ onChangeText?.(next);
196
+ if (name && formCtx) formCtx.onFieldChange(name);
197
+ }, [isControlled, onChangeText, name, formCtx]);
198
+
199
+ // ---------- Derived layout values --------------------------------------
200
+ const computedHeight = (0, _react.useMemo)(() => {
201
+ if (rows && rows > 0) {
202
+ return Math.round(rows * tokens.inputLineHeight + 2 * tokens.textareaPadding);
203
+ }
204
+ return tokens.textareaHeight;
205
+ }, [rows, tokens.inputLineHeight, tokens.textareaPadding, tokens.textareaHeight]);
206
+ const shouldShowCounter = (0, _react.useMemo)(() => {
207
+ if (showCounter === false) return false;
208
+ if (showCounter === true) return true;
209
+ return typeof maxLength === 'number';
210
+ }, [showCounter, maxLength]);
211
+ const counterText = (0, _react.useMemo)(() => {
212
+ const count = currentValue.length;
213
+ if (typeof maxLength === 'number') return `${count}/${maxLength}`;
214
+ return `${count}`;
215
+ }, [currentValue.length, maxLength]);
216
+
217
+ // ---------- Styles -----------------------------------------------------
218
+ const wrapperStyle = (0, _react.useMemo)(() => ({
219
+ gap: tokens.wrapperGap,
220
+ width: '100%'
221
+ }), [tokens.wrapperGap]);
222
+ const labelRowStyle = (0, _react.useMemo)(() => ({
223
+ flexDirection: 'row',
224
+ alignItems: 'baseline'
225
+ }), []);
226
+ const labelTextStyle = (0, _react.useMemo)(() => ({
227
+ color: tokens.labelColor,
228
+ fontFamily: tokens.labelFontFamily,
229
+ fontSize: tokens.labelFontSize,
230
+ lineHeight: tokens.labelLineHeight,
231
+ fontWeight: tokens.labelFontWeight
232
+ }), [tokens.labelColor, tokens.labelFontFamily, tokens.labelFontSize, tokens.labelLineHeight, tokens.labelFontWeight]);
233
+ const requiredIndicatorStyle = (0, _react.useMemo)(() => ({
234
+ ...labelTextStyle,
235
+ color: REQUIRED_INDICATOR_COLOR
236
+ }), [labelTextStyle]);
237
+ const textareaContainerStyle = (0, _react.useMemo)(() => ({
238
+ backgroundColor: tokens.textareaBackground,
239
+ borderColor: tokens.textareaBorderColor,
240
+ borderWidth: tokens.textareaBorderSize,
241
+ borderStyle: 'solid',
242
+ borderRadius: tokens.textareaRadius,
243
+ padding: tokens.textareaPadding,
244
+ height: computedHeight,
245
+ width: '100%',
246
+ overflow: 'hidden',
247
+ // The gap token is for content within the textarea (icons, etc.);
248
+ // we keep it so downstream layouts that pass children align.
249
+ gap: tokens.textareaGap
250
+ }), [tokens.textareaBackground, tokens.textareaBorderColor, tokens.textareaBorderSize, tokens.textareaRadius, tokens.textareaPadding, computedHeight, tokens.textareaGap]);
251
+ const inputTextStyle = (0, _react.useMemo)(() => ({
252
+ flex: 1,
253
+ color: tokens.inputTextColor,
254
+ fontFamily: tokens.inputFontFamily,
255
+ fontSize: tokens.inputFontSize,
256
+ lineHeight: tokens.inputLineHeight,
257
+ fontWeight: tokens.inputFontWeight,
258
+ padding: 0,
259
+ margin: 0,
260
+ textAlignVertical: 'top',
261
+ // Disable the default web focus ring; the textarea border
262
+ // already encodes focus state.
263
+ outlineStyle: 'none',
264
+ outlineWidth: 0,
265
+ outlineColor: 'transparent'
266
+ }), [tokens.inputTextColor, tokens.inputFontFamily, tokens.inputFontSize, tokens.inputLineHeight, tokens.inputFontWeight]);
267
+ const counterTextStyle = (0, _react.useMemo)(() => ({
268
+ color: tokens.counterColor,
269
+ fontFamily: tokens.counterFontFamily,
270
+ fontSize: tokens.counterFontSize,
271
+ lineHeight: tokens.counterLineHeight,
272
+ fontWeight: tokens.counterFontWeight,
273
+ textAlign: 'right',
274
+ width: '100%'
275
+ }), [tokens.counterColor, tokens.counterFontFamily, tokens.counterFontSize, tokens.counterLineHeight, tokens.counterFontWeight]);
276
+ const resolvedA11yLabel = accessibilityLabel || label || placeholder || 'Message field';
277
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
278
+ style: [wrapperStyle, style],
279
+ pointerEvents: isDisabled ? 'none' : 'auto',
280
+ testID: testID,
281
+ accessible: false,
282
+ children: [label != null && label !== '' && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
283
+ style: labelRowStyle,
284
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
285
+ style: labelTextStyle,
286
+ children: label
287
+ }), isRequired && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
288
+ style: requiredIndicatorStyle,
289
+ children: " *"
290
+ })]
291
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
292
+ style: [textareaContainerStyle, textareaStyle],
293
+ onPress: focusInput,
294
+ accessible: false,
295
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
296
+ ref: inputRef,
297
+ multiline: true,
298
+ value: currentValue,
299
+ onChangeText: handleChangeText,
300
+ onFocus: handleFocus,
301
+ onBlur: handleBlur,
302
+ placeholder: placeholder ?? '',
303
+ placeholderTextColor: tokens.inputTextColor,
304
+ editable: interactive,
305
+ maxLength: maxLength,
306
+ autoFocus: autoFocus,
307
+ accessibilityLabel: resolvedA11yLabel,
308
+ accessibilityHint: accessibilityHint,
309
+ style: [inputTextStyle, inputStyle]
310
+ })
311
+ }), shouldShowCounter && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
312
+ style: counterTextStyle,
313
+ accessibilityElementsHidden: true,
314
+ children: counterText
315
+ })]
316
+ });
317
+ }
318
+ var _default = exports.default = MessageField;
@@ -8,9 +8,20 @@ var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _reactNativeSvg = _interopRequireWildcard(require("react-native-svg"));
10
10
  var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
11
+ var _webPlatformUtils = require("../../utils/web-platform-utils");
11
12
  var _reactUtils = require("../../utils/react-utils");
12
13
  var _jsxRuntime = require("react/jsx-runtime");
13
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
+ /** Minimum touch target per iOS HIG / Material accessibility guidance. */
16
+ const MIN_TOUCH_TARGET = 44;
17
+ const IS_IOS = _reactNative.Platform.OS === 'ios';
18
+ const PRESS_DELAY = IS_IOS ? 130 : 0;
19
+ const touchTargetStyle = {
20
+ minWidth: MIN_TOUCH_TARGET,
21
+ minHeight: MIN_TOUCH_TARGET,
22
+ alignItems: 'center',
23
+ justifyContent: 'center'
24
+ };
14
25
  function resolveNavArrowTokens(modes) {
15
26
  const iconColor = (0, _figmaVariablesResolver.getVariableByName)('navArrow/icon/color', modes) || '#24262b';
16
27
  const widthToken = Number((0, _figmaVariablesResolver.getVariableByName)('navArrow/width', modes)) || 6;
@@ -51,6 +62,8 @@ function NavArrow({
51
62
  modes = _reactUtils.EMPTY_MODES,
52
63
  style,
53
64
  accessibilityLabel,
65
+ onPress,
66
+ disabled = false,
54
67
  ...rest
55
68
  }) {
56
69
  const tokens = (0, _react.useMemo)(() => resolveNavArrowTokens(modes), [modes]);
@@ -64,8 +77,7 @@ function NavArrow({
64
77
  borderRadius: tokens.borderRadius,
65
78
  backgroundColor: tokens.backgroundColor,
66
79
  alignItems: 'center',
67
- justifyContent: 'center',
68
- ...(style || {})
80
+ justifyContent: 'center'
69
81
  };
70
82
  const chevronW = isDown ? tokens.iconHeight : tokens.iconWidth;
71
83
  const chevronH = isDown ? tokens.iconWidth : tokens.iconHeight;
@@ -91,26 +103,55 @@ function NavArrow({
91
103
  svgHeight,
92
104
  points
93
105
  };
94
- }, [tokens, direction, style]);
106
+ }, [tokens, direction]);
95
107
  const defaultAccessibilityLabel = accessibilityLabel || (direction === 'Back' ? 'Go back' : direction === 'Forward' ? 'Go forward' : 'Go down');
108
+ const webProps = (0, _webPlatformUtils.usePressableWebSupport)({
109
+ restProps: rest,
110
+ onPress,
111
+ disabled,
112
+ accessibilityLabel: defaultAccessibilityLabel
113
+ });
114
+ const chevron = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.default, {
115
+ width: computed.svgWidth,
116
+ height: computed.svgHeight,
117
+ viewBox: `0 0 ${computed.svgWidth} ${computed.svgHeight}`,
118
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Polyline, {
119
+ points: computed.points,
120
+ stroke: tokens.iconColor,
121
+ strokeWidth: tokens.strokeWeight,
122
+ strokeLinecap: "round",
123
+ strokeLinejoin: "round",
124
+ fill: "none"
125
+ })
126
+ });
127
+ if (onPress) {
128
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
129
+ onPress: onPress,
130
+ disabled: disabled,
131
+ accessibilityRole: "button",
132
+ accessibilityLabel: defaultAccessibilityLabel,
133
+ accessibilityState: {
134
+ disabled
135
+ },
136
+ unstable_pressDelay: PRESS_DELAY,
137
+ style: ({
138
+ pressed
139
+ }) => [touchTargetStyle, style, pressed && !disabled ? {
140
+ opacity: 0.7
141
+ } : null],
142
+ ...webProps,
143
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
144
+ style: computed.containerStyle,
145
+ children: chevron
146
+ })
147
+ });
148
+ }
96
149
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
97
- style: computed.containerStyle,
150
+ style: [computed.containerStyle, style],
98
151
  accessibilityRole: "image",
99
152
  accessibilityLabel: defaultAccessibilityLabel,
100
153
  ...rest,
101
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.default, {
102
- width: computed.svgWidth,
103
- height: computed.svgHeight,
104
- viewBox: `0 0 ${computed.svgWidth} ${computed.svgHeight}`,
105
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Polyline, {
106
- points: computed.points,
107
- stroke: tokens.iconColor,
108
- strokeWidth: tokens.strokeWeight,
109
- strokeLinecap: "round",
110
- strokeLinejoin: "round",
111
- fill: "none"
112
- })
113
- })
154
+ children: chevron
114
155
  });
115
156
  }
116
157
  var _default = exports.default = /*#__PURE__*/_react.default.memo(NavArrow);