jfs-components 0.1.25 → 0.1.30

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 (97) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/lib/commonjs/components/AutoplayControl/AutoplayControl.js +66 -0
  3. package/lib/commonjs/components/Carousel/Carousel.js +112 -19
  4. package/lib/commonjs/components/CompareTable/CompareTable.js +191 -25
  5. package/lib/commonjs/components/ContentSheet/ContentSheet.js +104 -10
  6. package/lib/commonjs/components/FormUpload/Additem.js +168 -0
  7. package/lib/commonjs/components/FormUpload/FormUpload.js +198 -0
  8. package/lib/commonjs/components/Grid/Grid.js +206 -0
  9. package/lib/commonjs/components/MoneyValue/MoneyValue.js +179 -54
  10. package/lib/commonjs/components/NumberPagination/NumberPagination.js +144 -0
  11. package/lib/commonjs/components/PdpCcCard/PdpCcCard.js +7 -1
  12. package/lib/commonjs/components/ProfileCard/ProfileCard.js +208 -0
  13. package/lib/commonjs/components/Table/Table.js +27 -7
  14. package/lib/commonjs/components/UpiHandle/UpiHandle.js +23 -11
  15. package/lib/commonjs/components/index.js +42 -0
  16. package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
  17. package/lib/commonjs/design-tokens/figma-modes.generated.js +21 -10
  18. package/lib/commonjs/icons/components/IconBrokenimage.js +19 -0
  19. package/lib/commonjs/icons/components/IconImage.js +19 -0
  20. package/lib/commonjs/icons/components/IconMic.js +19 -0
  21. package/lib/commonjs/icons/components/IconMicoff.js +19 -0
  22. package/lib/commonjs/icons/components/IconPause.js +19 -0
  23. package/lib/commonjs/icons/components/IconPlay.js +19 -0
  24. package/lib/commonjs/icons/components/index.js +66 -0
  25. package/lib/commonjs/icons/registry.js +2 -2
  26. package/lib/module/components/AutoplayControl/AutoplayControl.js +60 -0
  27. package/lib/module/components/Carousel/Carousel.js +111 -19
  28. package/lib/module/components/CompareTable/CompareTable.js +191 -26
  29. package/lib/module/components/ContentSheet/ContentSheet.js +108 -14
  30. package/lib/module/components/FormUpload/Additem.js +162 -0
  31. package/lib/module/components/FormUpload/FormUpload.js +192 -0
  32. package/lib/module/components/Grid/Grid.js +201 -0
  33. package/lib/module/components/MoneyValue/MoneyValue.js +182 -57
  34. package/lib/module/components/NumberPagination/NumberPagination.js +138 -0
  35. package/lib/module/components/PdpCcCard/PdpCcCard.js +7 -1
  36. package/lib/module/components/ProfileCard/ProfileCard.js +202 -0
  37. package/lib/module/components/Table/Table.js +27 -7
  38. package/lib/module/components/UpiHandle/UpiHandle.js +23 -11
  39. package/lib/module/components/index.js +7 -1
  40. package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
  41. package/lib/module/design-tokens/figma-modes.generated.js +21 -10
  42. package/lib/module/icons/components/IconBrokenimage.js +12 -0
  43. package/lib/module/icons/components/IconImage.js +12 -0
  44. package/lib/module/icons/components/IconMic.js +12 -0
  45. package/lib/module/icons/components/IconMicoff.js +12 -0
  46. package/lib/module/icons/components/IconPause.js +12 -0
  47. package/lib/module/icons/components/IconPlay.js +12 -0
  48. package/lib/module/icons/components/index.js +6 -0
  49. package/lib/module/icons/registry.js +2 -2
  50. package/lib/typescript/src/components/AutoplayControl/AutoplayControl.d.ts +15 -0
  51. package/lib/typescript/src/components/Carousel/Carousel.d.ts +8 -1
  52. package/lib/typescript/src/components/CompareTable/CompareTable.d.ts +21 -1
  53. package/lib/typescript/src/components/ContentSheet/ContentSheet.d.ts +20 -1
  54. package/lib/typescript/src/components/FormUpload/Additem.d.ts +96 -0
  55. package/lib/typescript/src/components/FormUpload/FormUpload.d.ts +85 -0
  56. package/lib/typescript/src/components/Grid/Grid.d.ts +87 -0
  57. package/lib/typescript/src/components/MoneyValue/MoneyValue.d.ts +10 -1
  58. package/lib/typescript/src/components/NumberPagination/NumberPagination.d.ts +21 -0
  59. package/lib/typescript/src/components/PdpCcCard/PdpCcCard.d.ts +25 -1
  60. package/lib/typescript/src/components/ProfileCard/ProfileCard.d.ts +89 -0
  61. package/lib/typescript/src/components/Table/Table.d.ts +9 -1
  62. package/lib/typescript/src/components/UpiHandle/UpiHandle.d.ts +7 -1
  63. package/lib/typescript/src/components/index.d.ts +34 -28
  64. package/lib/typescript/src/design-tokens/figma-modes.generated.d.ts +10 -4
  65. package/lib/typescript/src/icons/components/IconBrokenimage.d.ts +3 -0
  66. package/lib/typescript/src/icons/components/IconImage.d.ts +3 -0
  67. package/lib/typescript/src/icons/components/IconMic.d.ts +3 -0
  68. package/lib/typescript/src/icons/components/IconMicoff.d.ts +3 -0
  69. package/lib/typescript/src/icons/components/IconPause.d.ts +3 -0
  70. package/lib/typescript/src/icons/components/IconPlay.d.ts +3 -0
  71. package/lib/typescript/src/icons/components/index.d.ts +6 -0
  72. package/lib/typescript/src/icons/registry.d.ts +1 -1
  73. package/package.json +1 -1
  74. package/src/components/AutoplayControl/AutoplayControl.tsx +77 -0
  75. package/src/components/Carousel/Carousel.tsx +133 -23
  76. package/src/components/CompareTable/CompareTable.tsx +224 -30
  77. package/src/components/ContentSheet/ContentSheet.tsx +138 -8
  78. package/src/components/FormUpload/Additem.tsx +262 -0
  79. package/src/components/FormUpload/FormUpload.tsx +313 -0
  80. package/src/components/Grid/Grid.tsx +368 -0
  81. package/src/components/MoneyValue/MoneyValue.tsx +216 -65
  82. package/src/components/NumberPagination/NumberPagination.tsx +170 -0
  83. package/src/components/PdpCcCard/PdpCcCard.tsx +36 -1
  84. package/src/components/ProfileCard/ProfileCard.tsx +268 -0
  85. package/src/components/Table/Table.tsx +29 -4
  86. package/src/components/UpiHandle/UpiHandle.tsx +35 -24
  87. package/src/components/index.ts +329 -182
  88. package/src/design-tokens/Coin Variables-variables-full.json +1 -1
  89. package/src/design-tokens/figma-modes.generated.ts +21 -10
  90. package/src/icons/components/IconBrokenimage.tsx +11 -0
  91. package/src/icons/components/IconImage.tsx +11 -0
  92. package/src/icons/components/IconMic.tsx +11 -0
  93. package/src/icons/components/IconMicoff.tsx +11 -0
  94. package/src/icons/components/IconPause.tsx +11 -0
  95. package/src/icons/components/IconPlay.tsx +11 -0
  96. package/src/icons/components/index.ts +6 -0
  97. package/src/icons/registry.ts +25 -1
@@ -0,0 +1,201 @@
1
+ "use strict";
2
+
3
+ import React, { useMemo } from 'react';
4
+ import { View } from 'react-native';
5
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
6
+ import { useTokens } from '../../design-tokens/JFSThemeProvider';
7
+ import { EMPTY_MODES, cloneChildrenWithModes, flattenChildren } from '../../utils/react-utils';
8
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
+ function toNumber(value, fallback) {
10
+ if (typeof value === 'number' && Number.isFinite(value)) return value;
11
+ if (typeof value === 'string') {
12
+ const parsed = parseFloat(value);
13
+ if (Number.isFinite(parsed)) return parsed;
14
+ }
15
+ return fallback;
16
+ }
17
+ function resolveGridTokens(modes) {
18
+ const gapFallback = toNumber(getVariableByName('Grid/gap', modes), 8);
19
+ const columnGap = toNumber(getVariableByName('Grid/column/gap', modes), gapFallback);
20
+ const rowGap = toNumber(getVariableByName('Grid/row/gap', modes), gapFallback);
21
+ const paddingHorizontal = toNumber(getVariableByName('Grid/padding/horizontal', modes), 8);
22
+ const paddingVertical = toNumber(getVariableByName('Grid/padding/vertical', modes), 8);
23
+ const paddingTop = toNumber(getVariableByName('Grid/padding/top', modes), paddingVertical);
24
+ const paddingBottom = toNumber(getVariableByName('Grid/padding/bottom', modes), paddingVertical);
25
+ const paddingLeft = toNumber(getVariableByName('Grid/padding/left', modes), paddingHorizontal);
26
+ const paddingRight = toNumber(getVariableByName('Grid/padding/right', modes), paddingHorizontal);
27
+ const backgroundColor = getVariableByName('Grid/background/color', modes) ?? 'transparent';
28
+ return {
29
+ backgroundColor,
30
+ columnGap,
31
+ rowGap,
32
+ paddingTop,
33
+ paddingBottom,
34
+ paddingLeft,
35
+ paddingRight
36
+ };
37
+ }
38
+ function normalizeFrs(frs, count) {
39
+ if (!frs || frs.length === 0) {
40
+ return Array.from({
41
+ length: count
42
+ }, () => 1);
43
+ }
44
+ return Array.from({
45
+ length: count
46
+ }, (_, index) => {
47
+ const value = frs[index] ?? frs[frs.length - 1] ?? 1;
48
+ return value > 0 ? value : 1;
49
+ });
50
+ }
51
+ function resolveAlignSelf(alignItems) {
52
+ if (alignItems === 'center') return 'center';
53
+ if (alignItems === 'start') return 'flex-start';
54
+ return 'stretch';
55
+ }
56
+ function resolveRowJustifyContent(justifyContent) {
57
+ if (justifyContent === 'space-between') return 'space-between';
58
+ if (justifyContent === 'start') return 'flex-start';
59
+ return 'flex-start';
60
+ }
61
+ function buildCellStyle(columnFr, justifyContent, alignItems) {
62
+ const alignSelf = resolveAlignSelf(alignItems);
63
+ if (justifyContent === 'space-between' || justifyContent === 'start') {
64
+ return {
65
+ flexGrow: 0,
66
+ flexShrink: 1,
67
+ flexBasis: 'auto',
68
+ minWidth: 0,
69
+ alignSelf
70
+ };
71
+ }
72
+ return {
73
+ flex: columnFr,
74
+ minWidth: 0,
75
+ alignSelf
76
+ };
77
+ }
78
+
79
+ /**
80
+ * `Grid` — a token-driven layout grid for React Native.
81
+ *
82
+ * Mirrors the Figma "Grid" component: a padded container with configurable
83
+ * columns, rows, fractional column tracks (`columnFrs`), and gap tokens.
84
+ * Each slot child maps to one cell — no separate `GridItem` wrapper is needed.
85
+ *
86
+ * @component
87
+ */
88
+ function Grid({
89
+ columns = 1,
90
+ rows,
91
+ columnFrs,
92
+ rowFrs,
93
+ columnGap: columnGapProp,
94
+ rowGap: rowGapProp,
95
+ gap: gapProp,
96
+ padding: paddingProp,
97
+ paddingHorizontal: paddingHorizontalProp,
98
+ paddingVertical: paddingVerticalProp,
99
+ paddingTop: paddingTopProp,
100
+ paddingBottom: paddingBottomProp,
101
+ paddingLeft: paddingLeftProp,
102
+ paddingRight: paddingRightProp,
103
+ justifyContent = 'stretch',
104
+ alignItems = 'stretch',
105
+ children,
106
+ modes: propModes = EMPTY_MODES,
107
+ style,
108
+ contentStyle,
109
+ cellStyle,
110
+ accessibilityLabel,
111
+ testID
112
+ }) {
113
+ const {
114
+ modes: globalModes
115
+ } = useTokens();
116
+ const modes = useMemo(() => globalModes === EMPTY_MODES && propModes === EMPTY_MODES ? EMPTY_MODES : {
117
+ ...globalModes,
118
+ ...propModes
119
+ }, [globalModes, propModes]);
120
+ const tokens = useMemo(() => resolveGridTokens(modes), [modes]);
121
+ const resolvedColumnGap = columnGapProp ?? gapProp ?? tokens.columnGap;
122
+ const resolvedRowGap = rowGapProp ?? gapProp ?? tokens.rowGap;
123
+ const resolvedPadding = useMemo(() => ({
124
+ paddingTop: paddingTopProp ?? paddingVerticalProp ?? paddingProp ?? tokens.paddingTop,
125
+ paddingBottom: paddingBottomProp ?? paddingVerticalProp ?? paddingProp ?? tokens.paddingBottom,
126
+ paddingLeft: paddingLeftProp ?? paddingHorizontalProp ?? paddingProp ?? tokens.paddingLeft,
127
+ paddingRight: paddingRightProp ?? paddingHorizontalProp ?? paddingProp ?? tokens.paddingRight
128
+ }), [paddingTopProp, paddingBottomProp, paddingLeftProp, paddingRightProp, paddingHorizontalProp, paddingVerticalProp, paddingProp, tokens]);
129
+ const safeColumns = Math.max(1, Math.floor(columns));
130
+ const processedChildren = useMemo(() => cloneChildrenWithModes(flattenChildren(children), modes), [children, modes]);
131
+ const cellNodes = useMemo(() => {
132
+ const nodes = [...processedChildren];
133
+ if (rows != null) {
134
+ const targetCount = safeColumns * Math.max(1, Math.floor(rows));
135
+ while (nodes.length < targetCount) {
136
+ nodes.push(null);
137
+ }
138
+ if (nodes.length > targetCount) {
139
+ nodes.length = targetCount;
140
+ }
141
+ }
142
+ return nodes;
143
+ }, [processedChildren, rows, safeColumns]);
144
+ const gridRows = useMemo(() => {
145
+ const result = [];
146
+ for (let index = 0; index < cellNodes.length; index += safeColumns) {
147
+ result.push(cellNodes.slice(index, index + safeColumns));
148
+ }
149
+ return result;
150
+ }, [cellNodes, safeColumns]);
151
+ const normalizedColumnFrs = useMemo(() => normalizeFrs(columnFrs, safeColumns), [columnFrs, safeColumns]);
152
+ const normalizedRowFrs = useMemo(() => rowFrs ? normalizeFrs(rowFrs, gridRows.length) : null, [rowFrs, gridRows.length]);
153
+ const containerStyle = useMemo(() => ({
154
+ backgroundColor: tokens.backgroundColor,
155
+ ...resolvedPadding,
156
+ width: '100%'
157
+ }), [tokens.backgroundColor, resolvedPadding]);
158
+ const rowsContainerStyle = useMemo(() => ({
159
+ gap: resolvedRowGap,
160
+ width: '100%'
161
+ }), [resolvedRowGap]);
162
+ const rowStyle = useMemo(() => ({
163
+ flexDirection: 'row',
164
+ columnGap: resolvedColumnGap,
165
+ justifyContent: resolveRowJustifyContent(justifyContent),
166
+ alignItems: alignItems === 'stretch' ? 'stretch' : alignItems === 'center' ? 'center' : 'flex-start',
167
+ width: '100%'
168
+ }), [resolvedColumnGap, justifyContent, alignItems]);
169
+ const defaultAccessibilityLabel = accessibilityLabel ?? `Grid, ${safeColumns} column${safeColumns === 1 ? '' : 's'}, ${gridRows.length} row${gridRows.length === 1 ? '' : 's'}`;
170
+ return /*#__PURE__*/_jsx(View, {
171
+ style: [containerStyle, style],
172
+ accessibilityRole: "none",
173
+ accessibilityLabel: defaultAccessibilityLabel,
174
+ testID: testID,
175
+ children: /*#__PURE__*/_jsx(View, {
176
+ style: [rowsContainerStyle, contentStyle],
177
+ children: gridRows.map((row, rowIndex) => {
178
+ const rowFr = normalizedRowFrs?.[rowIndex];
179
+ const spacersNeeded = justifyContent === 'space-between' && row.length < safeColumns ? safeColumns - row.length : 0;
180
+ return /*#__PURE__*/_jsxs(View, {
181
+ style: rowFr != null ? [rowStyle, {
182
+ flexGrow: rowFr
183
+ }] : rowStyle,
184
+ children: [row.map((cell, columnIndex) => {
185
+ const absoluteIndex = rowIndex * safeColumns + columnIndex;
186
+ const cellFlexStyle = buildCellStyle(normalizedColumnFrs[columnIndex] ?? 1, justifyContent, alignItems);
187
+ return /*#__PURE__*/_jsx(View, {
188
+ style: [cellFlexStyle, cellStyle],
189
+ children: cell
190
+ }, `grid-cell-${absoluteIndex}`);
191
+ }), spacersNeeded > 0 && Array.from({
192
+ length: spacersNeeded
193
+ }, (_, spacerIndex) => /*#__PURE__*/_jsx(View, {
194
+ style: buildCellStyle(normalizedColumnFrs[row.length + spacerIndex] ?? 1, justifyContent, alignItems)
195
+ }, `grid-spacer-${rowIndex}-${spacerIndex}`))]
196
+ }, `grid-row-${rowIndex}`);
197
+ })
198
+ })
199
+ });
200
+ }
201
+ export default /*#__PURE__*/React.memo(Grid);
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
 
3
- import React, { useMemo, useEffect, useRef } from 'react';
4
- import { View, Text, Pressable, Animated } from 'react-native';
3
+ import React, { useMemo, useEffect, useRef, useState, useCallback } from 'react';
4
+ import { View, Text, TextInput, Pressable, Animated, Platform, Keyboard } from 'react-native';
5
5
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
6
6
  import { EMPTY_MODES } from '../../utils/react-utils';
7
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  // Map of common ISO 4217 currency codes to display symbols
9
9
  const CURRENCY_SYMBOLS = {
10
10
  INR: '₹',
@@ -56,6 +56,8 @@ function MoneyValue({
56
56
  negative,
57
57
  focused = false,
58
58
  hidden = false,
59
+ editable = false,
60
+ onValueChange,
59
61
  modes = EMPTY_MODES,
60
62
  style,
61
63
  valueStyle,
@@ -67,24 +69,51 @@ function MoneyValue({
67
69
  ...rest
68
70
  }) {
69
71
  // Auto-detect negative from value and compute display value
70
- const {
71
- isNegative,
72
- displayValue
73
- } = useMemo(() => {
74
- const stringValue = String(value);
75
- const trimmed = stringValue.trim();
76
- const valueIsNegative = trimmed.startsWith('-') || typeof value === 'number' && value < 0;
72
+ const stringValue = String(value);
73
+ const trimmed = stringValue.trim();
74
+ const valueIsNegative = trimmed.startsWith('-') || typeof value === 'number' && value < 0;
77
75
 
78
- // Strip leading minus sign for display (we show it separately)
79
- const absoluteValue = trimmed.startsWith('-') ? trimmed.slice(1) : trimmed;
76
+ // Strip leading minus sign for display (we show it separately)
77
+ const absoluteValue = trimmed.startsWith('-') ? trimmed.slice(1) : trimmed;
80
78
 
81
- // Use explicit negative prop if provided, otherwise use auto-detected
82
- const showNegative = negative !== undefined ? negative : valueIsNegative;
83
- return {
84
- isNegative: hidden ? false : showNegative,
85
- displayValue: hidden ? '•••' : absoluteValue
86
- };
87
- }, [value, negative, hidden]);
79
+ // Use explicit negative prop if provided, otherwise use auto-detected
80
+ const showNegative = negative !== undefined ? negative : valueIsNegative;
81
+ const isNegative = hidden ? false : showNegative;
82
+ const displayValue = hidden ? '•••' : absoluteValue;
83
+
84
+ // Inline editing state
85
+ const [isEditing, setIsEditing] = useState(false);
86
+ const [editBuffer, setEditBuffer] = useState('');
87
+ const inputRef = useRef(null);
88
+ // Always-current snapshot of the display value for callbacks to reference.
89
+ const displayValueRef = useRef(displayValue);
90
+ displayValueRef.current = displayValue;
91
+ const enterEditMode = useCallback(() => {
92
+ setIsEditing(true);
93
+ setEditBuffer(displayValueRef.current);
94
+ // Focus the input on next frame so the keyboard opens
95
+ setTimeout(() => inputRef.current?.focus(), 0);
96
+ }, []);
97
+ const commitEdit = useCallback(() => {
98
+ setIsEditing(false);
99
+ const resolved = editBuffer || '0';
100
+ if (resolved !== displayValueRef.current) {
101
+ onValueChange?.(resolved);
102
+ }
103
+ }, [editBuffer, onValueChange]);
104
+ const handleChangeText = useCallback(text => {
105
+ // Allow only digits and at most one decimal point
106
+ const filtered = text.replace(/[^0-9.]/g, '');
107
+ const parts = filtered.split('.');
108
+ const clean = parts.length > 2 ? parts[0] + '.' + parts.slice(1).join('') : filtered;
109
+ setEditBuffer(clean);
110
+ }, []);
111
+ const handlePress = useCallback(event => {
112
+ if (editable) {
113
+ enterEditMode();
114
+ }
115
+ onPress?.(event);
116
+ }, [editable, enterEditMode, onPress]);
88
117
 
89
118
  // Resolve typography and layout tokens from Figma
90
119
  const textColor = getVariableByName('moneyValue/text/color', modes);
@@ -145,44 +174,140 @@ function MoneyValue({
145
174
  cursorOpacity.setValue(0);
146
175
  }
147
176
  }, [focused, cursorOpacity]);
148
- return /*#__PURE__*/_jsxs(Pressable, {
149
- style: [containerStyle, style],
150
- accessibilityRole: "text",
151
- accessibilityLabel: undefined,
152
- accessibilityHint: accessibilityHint,
153
- onPress: onPress,
154
- disabled: !onPress,
155
- ...rest,
156
- children: [isNegative && /*#__PURE__*/_jsx(Text, {
157
- style: [currencyTextStyle, negativeSignStyle],
158
- accessibilityElementsHidden: true,
159
- importantForAccessibility: "no",
160
- children: "-"
161
- }), /*#__PURE__*/_jsx(Text, {
162
- style: [currencyTextStyle, currencyStyle],
163
- accessibilityElementsHidden: true,
164
- importantForAccessibility: "no",
165
- children: resolvedCurrency
166
- }), /*#__PURE__*/_jsxs(View, {
167
- style: {
168
- flexDirection: 'row',
169
- alignItems: 'center'
170
- },
171
- children: [/*#__PURE__*/_jsx(Text, {
172
- style: [valueTextStyle, valueStyle],
173
- accessibilityElementsHidden: true,
174
- importantForAccessibility: "no",
175
- children: displayValue
176
- }), focused && /*#__PURE__*/_jsx(Animated.View, {
177
- style: {
178
- opacity: cursorOpacity,
179
- width: 2,
180
- height: valueFontSize * 1.1,
181
- backgroundColor: textColor,
182
- marginLeft: 2
183
- }
184
- })]
185
- })]
177
+
178
+ // Keyboard avoidance — lift the component when the keyboard would cover it.
179
+ // Follows the same pattern as ActionFooter (uses Keyboard.addListener).
180
+ // Resets when editing ends or the keyboard hides.
181
+ const rootRef = useRef(null);
182
+ const keyboardLift = useRef(new Animated.Value(0)).current;
183
+ const rootWindowYRef = useRef(0);
184
+ const rootMeasuredHeightRef = useRef(0);
185
+ const measureRoot = useCallback(() => {
186
+ rootRef.current?.measureInWindow((_x, y, _w, h) => {
187
+ rootWindowYRef.current = y;
188
+ rootMeasuredHeightRef.current = h;
189
+ });
190
+ }, []);
191
+ const handleRootLayout = useCallback(_e => {
192
+ // measureInWindow gives the component's position relative to the window,
193
+ // which is what we need for keyboard overlap calculation. onLayout fires
194
+ // after the component mounts and whenever its size changes.
195
+ measureRoot();
196
+ }, [measureRoot]);
197
+ useEffect(() => {
198
+ if (!editable) return;
199
+ const showSub = Keyboard.addListener('keyboardDidShow', e => {
200
+ measureRoot();
201
+ if (!isEditing) return;
202
+ const kbHeight = e.endCoordinates.height;
203
+ const {
204
+ height: screenH
205
+ } = require('react-native').Dimensions.get('window');
206
+ const componentBottom = rootWindowYRef.current + rootMeasuredHeightRef.current;
207
+ const visibleBottom = screenH - kbHeight;
208
+ const overlap = componentBottom - visibleBottom + 12;
209
+ if (overlap > 0) {
210
+ Animated.timing(keyboardLift, {
211
+ toValue: -overlap,
212
+ duration: e.duration ?? 250,
213
+ useNativeDriver: true
214
+ }).start();
215
+ }
216
+ });
217
+ const hideSub = Keyboard.addListener('keyboardDidHide', () => {
218
+ Animated.timing(keyboardLift, {
219
+ toValue: 0,
220
+ duration: 150,
221
+ useNativeDriver: true
222
+ }).start();
223
+ });
224
+ return () => {
225
+ showSub.remove();
226
+ hideSub.remove();
227
+ };
228
+ }, [editable, isEditing, keyboardLift, measureRoot]);
229
+
230
+ // Reset lift when editing ends
231
+ useEffect(() => {
232
+ if (!isEditing) {
233
+ keyboardLift.setValue(0);
234
+ }
235
+ }, [isEditing, keyboardLift]);
236
+ const handleBlur = useCallback(() => {
237
+ commitEdit();
238
+ }, [commitEdit]);
239
+ const handleSubmitEditing = useCallback(() => {
240
+ commitEdit();
241
+ }, [commitEdit]);
242
+ return /*#__PURE__*/_jsx(Animated.View, {
243
+ style: {
244
+ transform: [{
245
+ translateY: keyboardLift
246
+ }]
247
+ },
248
+ children: /*#__PURE__*/_jsx(View, {
249
+ ref: rootRef,
250
+ onLayout: handleRootLayout,
251
+ children: /*#__PURE__*/_jsxs(Pressable, {
252
+ style: [containerStyle, style],
253
+ accessibilityRole: "text",
254
+ accessibilityLabel: undefined,
255
+ accessibilityHint: accessibilityHint,
256
+ onPress: handlePress,
257
+ disabled: !onPress && !editable,
258
+ ...rest,
259
+ children: [isNegative && /*#__PURE__*/_jsx(Text, {
260
+ style: [currencyTextStyle, negativeSignStyle],
261
+ accessibilityElementsHidden: true,
262
+ importantForAccessibility: "no",
263
+ children: "-"
264
+ }), /*#__PURE__*/_jsx(Text, {
265
+ style: [currencyTextStyle, currencyStyle],
266
+ accessibilityElementsHidden: true,
267
+ importantForAccessibility: "no",
268
+ children: resolvedCurrency
269
+ }), /*#__PURE__*/_jsx(View, {
270
+ style: {
271
+ flexDirection: 'row',
272
+ alignItems: 'center'
273
+ },
274
+ children: isEditing ? /*#__PURE__*/_jsx(TextInput, {
275
+ ref: inputRef,
276
+ value: editBuffer,
277
+ onChangeText: handleChangeText,
278
+ onBlur: handleBlur,
279
+ onSubmitEditing: handleSubmitEditing,
280
+ keyboardType: "decimal-pad",
281
+ returnKeyType: "done",
282
+ selectTextOnFocus: true,
283
+ style: [valueTextStyle, valueStyle, {
284
+ padding: 0,
285
+ margin: 0,
286
+ // On web a thin border helps the cursor appear precisely
287
+ ...(Platform.OS === 'web' ? {
288
+ outlineStyle: 'none'
289
+ } : {})
290
+ }],
291
+ accessibilityLabel: accessibilityLabel || 'Edit value'
292
+ }) : /*#__PURE__*/_jsxs(_Fragment, {
293
+ children: [/*#__PURE__*/_jsx(Text, {
294
+ style: [valueTextStyle, valueStyle],
295
+ accessibilityElementsHidden: true,
296
+ importantForAccessibility: "no",
297
+ children: displayValue
298
+ }), focused && /*#__PURE__*/_jsx(Animated.View, {
299
+ style: {
300
+ opacity: cursorOpacity,
301
+ width: 2,
302
+ height: valueFontSize * 1.1,
303
+ backgroundColor: textColor,
304
+ marginLeft: 2
305
+ }
306
+ })]
307
+ })
308
+ })]
309
+ })
310
+ })
186
311
  });
187
312
  }
188
313
  export default MoneyValue;
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+
3
+ import React, { useMemo } from 'react';
4
+ import { Pressable, Text, View } from 'react-native';
5
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
6
+ import GlassFill from '../../utils/GlassFill/GlassFill';
7
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
+ function resolveNumberPaginationTokens(modes) {
9
+ const horizontalPadding = getVariableByName('numberPagination/padding/horizontal', modes) ?? 4;
10
+ const verticalPadding = getVariableByName('numberPagination/padding/vertical', modes) ?? 4;
11
+ const radiusRaw = getVariableByName('numberPagination/radius', modes) ?? 9999;
12
+ const backgroundColor = getVariableByName('numberPagination/background/color', modes) ?? 'rgba(141, 141, 141, 0.4)';
13
+ const borderColor = getVariableByName('numberPagination/border/color', modes) ?? 'rgba(255, 255, 255, 0.15)';
14
+
15
+ // control number variables
16
+ const itemWidth = getVariableByName('controlNumber/width', modes) ?? 32;
17
+ const itemHeight = getVariableByName('controlNumber/height', modes) ?? 32;
18
+ const itemRadiusRaw = getVariableByName('controlNumber/radius', modes) ?? 9999;
19
+ const activeBgColor = getVariableByName('control/active/background/color', modes) ?? '#ffffff';
20
+ const activeTextColor = getVariableByName('control/active/text/color', modes) ?? '#000000';
21
+ const inactiveTextColor = getVariableByName('control/text/default', modes) ?? '#ffffff';
22
+
23
+ // typography variables
24
+ const fontFamily = getVariableByName('numberPagination/fontFamily', modes) ?? 'JioType';
25
+ const fontSize = getVariableByName('numberPagination/fontSize', modes) ?? 16;
26
+ const fontWeight = String(getVariableByName('numberPagination/fontWeight', modes) ?? '500');
27
+ const lineHeight = getVariableByName('numberPagination/lineHeight', modes) ?? 18;
28
+ const blurMinimal = getVariableByName('blur/minimal', modes) ?? 29;
29
+ const blurIntensity = Math.max(0, Math.min(100, Math.round(Number(blurMinimal))));
30
+ const borderRadius = radiusRaw === 9999 ? 39 / 2 : radiusRaw;
31
+ const itemRadius = itemRadiusRaw === 9999 ? itemWidth / 2 : itemRadiusRaw;
32
+ return {
33
+ containerStyle: {
34
+ height: 39,
35
+ borderRadius,
36
+ borderWidth: 1,
37
+ borderColor,
38
+ backgroundColor: 'transparent',
39
+ overflow: 'hidden',
40
+ flexDirection: 'row',
41
+ alignItems: 'center',
42
+ paddingHorizontal: horizontalPadding,
43
+ paddingVertical: verticalPadding
44
+ },
45
+ activeItemStyle: {
46
+ width: itemWidth,
47
+ height: itemHeight,
48
+ borderRadius: itemRadius,
49
+ backgroundColor: activeBgColor,
50
+ alignItems: 'center',
51
+ justifyContent: 'center'
52
+ },
53
+ inactiveItemStyle: {
54
+ width: itemWidth,
55
+ height: itemHeight,
56
+ borderRadius: itemRadius,
57
+ backgroundColor: 'transparent',
58
+ alignItems: 'center',
59
+ justifyContent: 'center'
60
+ },
61
+ activeTextStyle: {
62
+ fontFamily,
63
+ fontSize,
64
+ fontWeight,
65
+ lineHeight,
66
+ color: activeTextColor,
67
+ textAlign: 'center'
68
+ },
69
+ inactiveTextStyle: {
70
+ fontFamily,
71
+ fontSize,
72
+ fontWeight,
73
+ lineHeight,
74
+ color: inactiveTextColor,
75
+ textAlign: 'center'
76
+ },
77
+ blurIntensity,
78
+ backgroundColor
79
+ };
80
+ }
81
+
82
+ /**
83
+ * NumberPagination component displays a horizontal list of page numbers on a frosted glass surface.
84
+ * All styling is driven by Figma design tokens with support for custom children slot.
85
+ */
86
+ export default function NumberPagination({
87
+ activePage = 1,
88
+ totalPages = 1,
89
+ onPageChange,
90
+ children,
91
+ modes,
92
+ style
93
+ }) {
94
+ const tokens = useMemo(() => resolveNumberPaginationTokens(modes ?? {}), [modes]);
95
+ const renderPages = () => {
96
+ if (children) {
97
+ return children;
98
+ }
99
+ const pages = [];
100
+ for (let i = 1; i <= totalPages; i++) {
101
+ const active = i === activePage;
102
+ pages.push(/*#__PURE__*/_jsx(Pressable, {
103
+ onPress: () => onPageChange?.(i),
104
+ style: ({
105
+ pressed
106
+ }) => [active ? tokens.activeItemStyle : tokens.inactiveItemStyle, pressed && {
107
+ opacity: 0.7
108
+ }],
109
+ accessibilityRole: "button",
110
+ accessibilityState: {
111
+ selected: active
112
+ },
113
+ accessibilityLabel: `Page ${i}`,
114
+ children: /*#__PURE__*/_jsx(Text, {
115
+ style: active ? tokens.activeTextStyle : tokens.inactiveTextStyle,
116
+ children: i
117
+ })
118
+ }, i));
119
+ }
120
+ return pages;
121
+ };
122
+ return /*#__PURE__*/_jsxs(View, {
123
+ style: [tokens.containerStyle, style],
124
+ children: [/*#__PURE__*/_jsx(GlassFill, {
125
+ tint: "light",
126
+ intensity: tokens.blurIntensity,
127
+ overlayColor: tokens.backgroundColor,
128
+ androidTintWash: false
129
+ }), /*#__PURE__*/_jsx(View, {
130
+ style: {
131
+ flexDirection: 'row',
132
+ alignItems: 'center',
133
+ height: '100%'
134
+ },
135
+ children: renderPages()
136
+ })]
137
+ });
138
+ }
@@ -39,6 +39,9 @@ function PdpCcCard({
39
39
  media,
40
40
  title = 'Title',
41
41
  subtitle = 'Subtitle',
42
+ numberOfLines,
43
+ disableTruncation,
44
+ singleLine,
42
45
  metrics = DEFAULT_METRICS,
43
46
  buttonLabel = 'button',
44
47
  buttonIcon = 'ic_add_circle',
@@ -90,7 +93,10 @@ function PdpCcCard({
90
93
  title: title,
91
94
  subtitle: subtitle,
92
95
  textAlign: "Center",
93
- modes: modes
96
+ modes: modes,
97
+ numberOfLines: numberOfLines,
98
+ disableTruncation: disableTruncation,
99
+ singleLine: singleLine
94
100
  }), metrics.length > 0 ? /*#__PURE__*/_jsx(View, {
95
101
  style: styles.metricsRow,
96
102
  children: metrics.map((metric, index) => /*#__PURE__*/_jsxs(React.Fragment, {