jfs-components 0.0.78 → 0.0.84

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 (119) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/lib/commonjs/components/AppBar/AppBar.js +56 -6
  3. package/lib/commonjs/components/Attached/Attached.js +183 -0
  4. package/lib/commonjs/components/Card/Card.js +25 -2
  5. package/lib/commonjs/components/Checkbox/Checkbox.js +18 -2
  6. package/lib/commonjs/components/Drawer/Drawer.js +6 -1
  7. package/lib/commonjs/components/DropdownInput/DropdownInput.js +30 -6
  8. package/lib/commonjs/components/ExpandableCheckbox/ExpandableCheckbox.js +17 -11
  9. package/lib/commonjs/components/FormField/FormField.js +1 -14
  10. package/lib/commonjs/components/FullscreenModal/FullscreenModal.js +9 -7
  11. package/lib/commonjs/components/ListItem/ListItem.js +26 -24
  12. package/lib/commonjs/components/MessageField/MessageField.js +1 -13
  13. package/lib/commonjs/components/PaymentFeedback/PaymentFeedback.js +12 -9
  14. package/lib/commonjs/components/PlanComparisonCard/PlanComparisonCard.js +237 -0
  15. package/lib/commonjs/components/Slot/Slot.js +73 -0
  16. package/lib/commonjs/components/Spinner/Spinner.js +217 -0
  17. package/lib/commonjs/components/TextInput/TextInput.js +33 -18
  18. package/lib/commonjs/components/index.js +28 -0
  19. package/lib/commonjs/icons/components/IconArrowdown.js +19 -0
  20. package/lib/commonjs/icons/components/IconArrowup.js +19 -0
  21. package/lib/commonjs/icons/components/IconChevrondowncircle.js +19 -0
  22. package/lib/commonjs/icons/components/IconChevronleftcircle.js +19 -0
  23. package/lib/commonjs/icons/components/IconChevronrightcircle.js +19 -0
  24. package/lib/commonjs/icons/components/IconChevronupcircle.js +19 -0
  25. package/lib/commonjs/icons/components/IconOsnavback.js +19 -0
  26. package/lib/commonjs/icons/components/IconOsnavcenter.js +19 -0
  27. package/lib/commonjs/icons/components/IconOsnavhome.js +19 -0
  28. package/lib/commonjs/icons/components/IconOsnavtask.js +19 -0
  29. package/lib/commonjs/icons/components/IconSignin.js +19 -0
  30. package/lib/commonjs/icons/components/IconSignout.js +19 -0
  31. package/lib/commonjs/icons/components/index.js +132 -0
  32. package/lib/commonjs/icons/registry.js +2 -2
  33. package/lib/module/components/AppBar/AppBar.js +56 -6
  34. package/lib/module/components/Attached/Attached.js +178 -0
  35. package/lib/module/components/Card/Card.js +25 -2
  36. package/lib/module/components/Checkbox/Checkbox.js +18 -2
  37. package/lib/module/components/Drawer/Drawer.js +6 -1
  38. package/lib/module/components/DropdownInput/DropdownInput.js +30 -6
  39. package/lib/module/components/ExpandableCheckbox/ExpandableCheckbox.js +17 -11
  40. package/lib/module/components/FormField/FormField.js +3 -16
  41. package/lib/module/components/FullscreenModal/FullscreenModal.js +9 -7
  42. package/lib/module/components/ListItem/ListItem.js +26 -24
  43. package/lib/module/components/MessageField/MessageField.js +3 -15
  44. package/lib/module/components/PaymentFeedback/PaymentFeedback.js +13 -9
  45. package/lib/module/components/PlanComparisonCard/PlanComparisonCard.js +234 -0
  46. package/lib/module/components/Slot/Slot.js +68 -0
  47. package/lib/module/components/Spinner/Spinner.js +212 -0
  48. package/lib/module/components/TextInput/TextInput.js +34 -19
  49. package/lib/module/components/index.js +4 -0
  50. package/lib/module/icons/components/IconArrowdown.js +12 -0
  51. package/lib/module/icons/components/IconArrowup.js +12 -0
  52. package/lib/module/icons/components/IconChevrondowncircle.js +12 -0
  53. package/lib/module/icons/components/IconChevronleftcircle.js +12 -0
  54. package/lib/module/icons/components/IconChevronrightcircle.js +12 -0
  55. package/lib/module/icons/components/IconChevronupcircle.js +12 -0
  56. package/lib/module/icons/components/IconOsnavback.js +12 -0
  57. package/lib/module/icons/components/IconOsnavcenter.js +12 -0
  58. package/lib/module/icons/components/IconOsnavhome.js +12 -0
  59. package/lib/module/icons/components/IconOsnavtask.js +12 -0
  60. package/lib/module/icons/components/IconSignin.js +12 -0
  61. package/lib/module/icons/components/IconSignout.js +12 -0
  62. package/lib/module/icons/components/index.js +12 -0
  63. package/lib/module/icons/registry.js +2 -2
  64. package/lib/typescript/src/components/AppBar/AppBar.d.ts +12 -1
  65. package/lib/typescript/src/components/Attached/Attached.d.ts +64 -0
  66. package/lib/typescript/src/components/Card/Card.d.ts +9 -2
  67. package/lib/typescript/src/components/DropdownInput/DropdownInput.d.ts +3 -2
  68. package/lib/typescript/src/components/ListItem/ListItem.d.ts +16 -6
  69. package/lib/typescript/src/components/PaymentFeedback/PaymentFeedback.d.ts +5 -1
  70. package/lib/typescript/src/components/PlanComparisonCard/PlanComparisonCard.d.ts +66 -0
  71. package/lib/typescript/src/components/Slot/Slot.d.ts +52 -0
  72. package/lib/typescript/src/components/Spinner/Spinner.d.ts +45 -0
  73. package/lib/typescript/src/components/index.d.ts +4 -0
  74. package/lib/typescript/src/icons/components/IconArrowdown.d.ts +3 -0
  75. package/lib/typescript/src/icons/components/IconArrowup.d.ts +3 -0
  76. package/lib/typescript/src/icons/components/IconChevrondowncircle.d.ts +3 -0
  77. package/lib/typescript/src/icons/components/IconChevronleftcircle.d.ts +3 -0
  78. package/lib/typescript/src/icons/components/IconChevronrightcircle.d.ts +3 -0
  79. package/lib/typescript/src/icons/components/IconChevronupcircle.d.ts +3 -0
  80. package/lib/typescript/src/icons/components/IconOsnavback.d.ts +3 -0
  81. package/lib/typescript/src/icons/components/IconOsnavcenter.d.ts +3 -0
  82. package/lib/typescript/src/icons/components/IconOsnavhome.d.ts +3 -0
  83. package/lib/typescript/src/icons/components/IconOsnavtask.d.ts +3 -0
  84. package/lib/typescript/src/icons/components/IconSignin.d.ts +3 -0
  85. package/lib/typescript/src/icons/components/IconSignout.d.ts +3 -0
  86. package/lib/typescript/src/icons/components/index.d.ts +12 -0
  87. package/lib/typescript/src/icons/registry.d.ts +1 -1
  88. package/package.json +3 -2
  89. package/src/components/AppBar/AppBar.tsx +79 -12
  90. package/src/components/Attached/Attached.tsx +237 -0
  91. package/src/components/Card/Card.tsx +28 -1
  92. package/src/components/Checkbox/Checkbox.tsx +14 -2
  93. package/src/components/Drawer/Drawer.tsx +4 -0
  94. package/src/components/DropdownInput/DropdownInput.tsx +54 -20
  95. package/src/components/ExpandableCheckbox/ExpandableCheckbox.tsx +13 -9
  96. package/src/components/FormField/FormField.tsx +3 -19
  97. package/src/components/FullscreenModal/FullscreenModal.tsx +6 -3
  98. package/src/components/ListItem/ListItem.tsx +42 -25
  99. package/src/components/MessageField/MessageField.tsx +3 -18
  100. package/src/components/PaymentFeedback/PaymentFeedback.tsx +15 -8
  101. package/src/components/PlanComparisonCard/PlanComparisonCard.tsx +316 -0
  102. package/src/components/Slot/Slot.tsx +91 -0
  103. package/src/components/Spinner/Spinner.tsx +273 -0
  104. package/src/components/TextInput/TextInput.tsx +37 -19
  105. package/src/components/index.ts +4 -0
  106. package/src/icons/components/IconArrowdown.tsx +11 -0
  107. package/src/icons/components/IconArrowup.tsx +11 -0
  108. package/src/icons/components/IconChevrondowncircle.tsx +11 -0
  109. package/src/icons/components/IconChevronleftcircle.tsx +11 -0
  110. package/src/icons/components/IconChevronrightcircle.tsx +11 -0
  111. package/src/icons/components/IconChevronupcircle.tsx +11 -0
  112. package/src/icons/components/IconOsnavback.tsx +11 -0
  113. package/src/icons/components/IconOsnavcenter.tsx +11 -0
  114. package/src/icons/components/IconOsnavhome.tsx +11 -0
  115. package/src/icons/components/IconOsnavtask.tsx +11 -0
  116. package/src/icons/components/IconSignin.tsx +11 -0
  117. package/src/icons/components/IconSignout.tsx +11 -0
  118. package/src/icons/components/index.ts +12 -0
  119. package/src/icons/registry.ts +49 -1
@@ -7,7 +7,6 @@ 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 _IconCapsule = _interopRequireDefault(require("../IconCapsule/IconCapsule"));
11
10
  var _NavArrow = _interopRequireDefault(require("../NavArrow/NavArrow"));
12
11
  var _webPlatformUtils = require("../../utils/web-platform-utils");
13
12
  var _reactUtils = require("../../utils/react-utils");
@@ -21,9 +20,10 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
21
20
  const IS_IOS = _reactNative.Platform.OS === 'ios';
22
21
  const PRESS_DELAY = IS_IOS ? 130 : 0;
23
22
 
24
- // Forced modes for the endSlot — `Context: 'ListItem'` can never be
25
- // overridden by external modes. Frozen so identity is stable across renders.
26
- const END_SLOT_FORCED_MODES = Object.freeze({
23
+ // Forced modes for the leading/trailing slots — `Context: 'ListItem'` can
24
+ // never be overridden by external modes. Frozen so identity is stable across
25
+ // renders. Applied to both slots so they cascade modes identically.
26
+ const SLOT_FORCED_MODES = Object.freeze({
27
27
  Context: 'ListItem'
28
28
  });
29
29
 
@@ -38,7 +38,7 @@ const pressedOverlayStyle = {
38
38
  // ---------------------------------------------------------------------------
39
39
 
40
40
  function resolveListItemTokens(modes) {
41
- // Modes used to cascade into slot children (leading / supportSlot / endSlot).
41
+ // Modes used to cascade into slot children (leading / supportSlot / trailing).
42
42
  // We do NOT inject an `AppearanceBrand` default here: slot content such as
43
43
  // Buttons or Badges carry their own intended appearance, so forcing one onto
44
44
  // them would be surprising.
@@ -137,9 +137,11 @@ const verticalSupportTextOverride = {
137
137
  * - **design-token driven styling** via `getVariableByName` and `modes`
138
138
  *
139
139
  * Wherever the Figma layer name contains "Slot", this component exposes a
140
- * dedicated React "slot" prop:
140
+ * dedicated React "slot" prop. The leading and trailing edges share a
141
+ * symmetric `leading` / `trailing` slot API:
142
+ * - Slot "leading" → `leading`
141
143
  * - Slot "support text" → `supportSlot`
142
- * - Slot "end" → `endSlot`
144
+ * - Slot "trailing" → `trailing`
143
145
  *
144
146
  * @component
145
147
  * @param {Object} props
@@ -147,9 +149,9 @@ const verticalSupportTextOverride = {
147
149
  * @param {string} [props.title='Title'] - Primary title used in the horizontal layout.
148
150
  * @param {string} [props.supportText='Support Text'] - Support text used in both layouts when `supportSlot` is not provided.
149
151
  * @param {boolean} [props.showSupportText=true] - Toggles rendering of the support text in Horizontal layout.
150
- * @param {React.ReactNode} [props.leading] - Optional leading element. Defaults to `IconCapsule`.
152
+ * @param {React.ReactNode|null} [props.leading] - Optional leading slot. Omitted or `null` renders nothing.
151
153
  * @param {React.ReactNode} [props.supportSlot] - Optional custom slot used instead of the default support text block.
152
- * @param {React.ReactNode} [props.endSlot] - Optional custom trailing slot (Figma Slot "end").
154
+ * @param {React.ReactNode} [props.trailing] - Optional trailing slot (Figma Slot "trailing"). Horizontal layout only.
153
155
  * @param {boolean} [props.navArrow=true] - Whether to show NavArrow on the far right (Horizontal layout only).
154
156
  * @param {Object} [props.modes={}] - Modes object passed to `getVariableByName` for all design tokens.
155
157
  * @param {Function} [props.onPress] - When provided, the entire item becomes pressable (navigation variant).
@@ -178,6 +180,7 @@ function ListItemImpl({
178
180
  showSupportText = true,
179
181
  leading,
180
182
  supportSlot,
183
+ trailing,
181
184
  endSlot,
182
185
  navArrow = true,
183
186
  modes = _reactUtils.EMPTY_MODES,
@@ -215,13 +218,9 @@ function ListItemImpl({
215
218
  // Process leading slot to pass modes to children. Memoized on
216
219
  // (leading, resolvedModes) so a parent re-render doesn't re-walk the tree.
217
220
  const leadingElement = (0, _react.useMemo)(() => {
218
- const processed = leading ? (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(leading), tokens.resolvedModes) : [];
219
- if (processed.length === 0) {
220
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_IconCapsule.default, {
221
- modes: tokens.resolvedModes,
222
- accessibilityLabel: undefined
223
- });
224
- }
221
+ if (leading == null) return null;
222
+ const processed = (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(leading), tokens.resolvedModes, SLOT_FORCED_MODES);
223
+ if (processed.length === 0) return null;
225
224
  return processed.length === 1 ? processed[0] : processed;
226
225
  }, [leading, tokens.resolvedModes]);
227
226
  const processedSupportSlot = (0, _react.useMemo)(() => {
@@ -229,11 +228,14 @@ function ListItemImpl({
229
228
  const processed = (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(supportSlot), tokens.resolvedModes);
230
229
  return processed.length === 1 ? processed[0] : processed;
231
230
  }, [supportSlot, tokens.resolvedModes]);
232
- const processedEndSlot = (0, _react.useMemo)(() => {
233
- if (!endSlot) return null;
234
- const processed = (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(endSlot), tokens.resolvedModes, END_SLOT_FORCED_MODES);
231
+
232
+ // `trailing` wins; `endSlot` is the deprecated alias kept for back-compat.
233
+ const trailingContent = trailing ?? endSlot;
234
+ const processedTrailing = (0, _react.useMemo)(() => {
235
+ if (!trailingContent) return null;
236
+ const processed = (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(trailingContent), tokens.resolvedModes, SLOT_FORCED_MODES);
235
237
  return processed.length === 1 ? processed[0] : processed;
236
- }, [endSlot, tokens.resolvedModes]);
238
+ }, [trailingContent, tokens.resolvedModes]);
237
239
  const renderSupportContent = () => {
238
240
  if (processedSupportSlot) return processedSupportSlot;
239
241
 
@@ -268,7 +270,7 @@ function ListItemImpl({
268
270
  if (layout === 'Horizontal') {
269
271
  const innerContent = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
270
272
  style: innerContentStyleArray,
271
- children: [leadingElement, /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
273
+ children: [leadingElement ?? null, /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
272
274
  style: {
273
275
  flex: 1,
274
276
  minWidth: 1,
@@ -279,9 +281,9 @@ function ListItemImpl({
279
281
  numberOfLines: 1,
280
282
  children: title
281
283
  }), showSupportText && renderSupportContent()]
282
- }), processedEndSlot ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
284
+ }), processedTrailing ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
283
285
  style: tokens.trailingWrapperStyle,
284
- children: processedEndSlot
286
+ children: processedTrailing
285
287
  }) : null, navArrow && /*#__PURE__*/(0, _jsxRuntime.jsx)(_NavArrow.default, {
286
288
  direction: "Forward",
287
289
  modes: tokens.resolvedModes
@@ -315,7 +317,7 @@ function ListItemImpl({
315
317
  // Vertical layout — icon on top, support text/slot below
316
318
  const verticalContent = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
317
319
  style: verticalContentStyleArray,
318
- children: [leadingElement, renderSupportContent()]
320
+ children: [leadingElement ?? null, renderSupportContent()]
319
321
  });
320
322
  if (onPress) {
321
323
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
@@ -145,15 +145,6 @@ function MessageField({
145
145
  const currentValue = isControlled ? value : uncontrolledValue;
146
146
  const [isFocused, setIsFocused] = (0, _react.useState)(false);
147
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
148
  const {
158
149
  modes: globalModes
159
150
  } = (0, _JFSThemeProvider.useTokens)();
@@ -288,12 +279,9 @@ function MessageField({
288
279
  style: requiredIndicatorStyle,
289
280
  children: " *"
290
281
  })]
291
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
282
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
292
283
  style: [textareaContainerStyle, textareaStyle],
293
- onPress: focusInput,
294
- accessible: false,
295
284
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
296
- ref: inputRef,
297
285
  multiline: true,
298
286
  value: currentValue,
299
287
  onChangeText: handleChangeText,
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = PaymentFeedback;
7
- var _react = _interopRequireWildcard(require("react"));
7
+ var _react = _interopRequireDefault(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
10
10
  var _JFSThemeProvider = require("../../design-tokens/JFSThemeProvider");
@@ -12,11 +12,10 @@ var _IconCapsule = _interopRequireDefault(require("../IconCapsule/IconCapsule"))
12
12
  var _reactUtils = require("../../utils/react-utils");
13
13
  var _jsxRuntime = require("react/jsx-runtime");
14
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
- function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
16
15
  function PaymentFeedback({
17
16
  title = '₹50,000',
18
17
  subtitle = 'Payment successful',
19
- body = 'Your payment has been\nsuccessfully processed.',
18
+ body,
20
19
  details = '18 March 2025, 4:15 pm\nTransaction ID: TXN121466784',
21
20
  showDetails = true,
22
21
  iconName = 'ic_confirm',
@@ -103,17 +102,21 @@ function PaymentFeedback({
103
102
  fontWeight: String(detailsFontWeight),
104
103
  textAlign: 'center'
105
104
  };
106
- const mediaContent = /*#__PURE__*/(0, _react.isValidElement)(renderMedia) ? /*#__PURE__*/(0, _react.cloneElement)(renderMedia, {
107
- modes
108
- }) : renderMedia;
105
+
106
+ // Cascade modes into a custom media slot (per the modes-cascade convention);
107
+ // any modes the consumer set on the slot child still take precedence.
108
+ const mediaContent = renderMedia != null ? (0, _reactUtils.cloneChildrenWithModes)(renderMedia, modes) : null;
109
109
  const defaultMedia = /*#__PURE__*/(0, _jsxRuntime.jsx)(_IconCapsule.default, {
110
- iconName: iconName,
110
+ iconName: iconName
111
+ // `positive` is the default; consumers override the capsule color by
112
+ // passing `AppearanceSystem` (or any other mode) via the `modes` prop.
113
+ ,
111
114
  modes: {
115
+ AppearanceSystem: 'positive',
112
116
  ...modes,
113
117
  'Icon Capsule Size': 'L',
114
118
  Emphasis: 'High',
115
- 'Semantic Intent': 'System',
116
- AppearanceSystem: 'positive'
119
+ 'Semantic Intent': 'System'
117
120
  }
118
121
  });
119
122
  const detailLines = details?.split('\n') ?? [];
@@ -0,0 +1,237 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
10
+ var _reactUtils = require("../../utils/react-utils");
11
+ var _Icon = _interopRequireDefault(require("../../icons/Icon"));
12
+ var _jsxRuntime = require("react/jsx-runtime");
13
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
+ /** Figma grid: label column 1.8fr, each plan column 1fr. */const LABEL_COLUMN_FR = 1.8;
15
+ const PLAN_COLUMN_FR = 1;
16
+
17
+ /**
18
+ * A single plan column header (the label column has no header of its own).
19
+ */
20
+
21
+ /**
22
+ * Value rendered inside a plan cell.
23
+ * - `string` / `number` → rendered as value text.
24
+ * - `false` → renders the muted "not available" cross icon.
25
+ * - any React node → rendered as-is (e.g. a `Badge`, `MoneyValue`, icon…).
26
+ * - `null` / `undefined` / `true` → empty cell.
27
+ */
28
+
29
+ const DEFAULT_COLUMNS = [{
30
+ label: 'Your plan'
31
+ }, {
32
+ label: 'JioFinance+',
33
+ brand: true
34
+ }];
35
+ const DEFAULT_ROWS = [{
36
+ label: 'JioPoints multiplier',
37
+ values: ['1x', '1.25x']
38
+ }, {
39
+ label: 'Cashback',
40
+ showInfo: true,
41
+ values: [false, 'Upto ₹5000']
42
+ }, {
43
+ label: 'Bonus JioGold',
44
+ showInfo: true,
45
+ values: [false, '1%']
46
+ }];
47
+
48
+ /** Keeps every text layer on a single line. */
49
+ const NO_WRAP_TEXT = {
50
+ flexShrink: 0,
51
+ ...(_reactNative.Platform.OS === 'web' ? {
52
+ whiteSpace: 'nowrap'
53
+ } : {})
54
+ };
55
+ const labelColumnStyle = {
56
+ flex: LABEL_COLUMN_FR,
57
+ minWidth: 0
58
+ };
59
+ const planColumnStyle = {
60
+ flex: PLAN_COLUMN_FR,
61
+ minWidth: 0,
62
+ alignItems: 'center'
63
+ };
64
+
65
+ /**
66
+ * PlanComparisonCard renders a compact comparison table that pits the user's
67
+ * current plan against one or more alternative plans across a set of feature
68
+ * rows. Implementation of Figma node `4498:2968` (`PlanComparisonCard`).
69
+ *
70
+ * Columns use a 1.8fr / 1fr flex ratio (label vs plan), matching the Figma grid.
71
+ *
72
+ * @component
73
+ */
74
+ function PlanComparisonCard({
75
+ columns = DEFAULT_COLUMNS,
76
+ rows = DEFAULT_ROWS,
77
+ modes = _reactUtils.EMPTY_MODES,
78
+ style
79
+ }) {
80
+ const gap = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/gap', modes) ?? 16;
81
+ const headerFg = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/header/fg', modes) ?? '#ffffff';
82
+ const headerBrandFg = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/header/brand/fg', modes) ?? '#cea15a';
83
+ const headerFontSize = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/header/fontSize', modes) ?? 14;
84
+ const headerFontFamily = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/header/fontFamily', modes) ?? 'JioType Var';
85
+ const headerLineHeight = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/header/lineHeight', modes) ?? 18;
86
+ const headerFontWeight = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/header/fontWeight', modes) ?? '500';
87
+ const tableBackground = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableRow/background', modes) ?? '#141414';
88
+ const tableRadius = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableRow/radius', modes) ?? 16;
89
+ const tableBorderSize = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableRow/border/size', modes) ?? 1;
90
+ const tableBorderColor = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableRow/border/color', modes) ?? '#1e1a14';
91
+ const cellPadding = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableCell/padding', modes) ?? 12;
92
+ const cellGap = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableCell/gap', modes) ?? 2;
93
+ const cellMinHeight = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableCell/height', modes) ?? 46;
94
+ const cellBorderSize = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableCell/border/size', modes) ?? 1;
95
+ const cellBorderColor = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableCell/border/color', modes) ?? '#1e1a14';
96
+ const labelColor = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableCell/label/color', modes) ?? '#ffffff';
97
+ const labelDisabledColor = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableCell/label/disabled/color', modes) ?? '#91949c';
98
+ const labelFontSize = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableCell/label/fontSize', modes) ?? 12;
99
+ const labelFontFamily = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableCell/label/fontFamily', modes) ?? 'JioType Var';
100
+ const labelLineHeight = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableCell/label/lineHeight', modes) ?? 16;
101
+ const labelFontWeight = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableCell/label/fontWeight', modes) ?? '400';
102
+ const valueColor = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableCell/value/color', modes) ?? '#ffffff';
103
+ const valueFontSize = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableCell/value/fontSize', modes) ?? 12;
104
+ const valueFontFamily = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableCell/value/fontFamily', modes) ?? 'JioType Var';
105
+ const valueLineHeight = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableCell/value/lineHeight', modes) ?? 16;
106
+ const valueFontWeight = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/tableCell/value/fontWeight', modes) ?? '500';
107
+ const iconColor = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/icon/color', modes) ?? '#ffffff';
108
+ const iconSize = (0, _figmaVariablesResolver.getVariableByName)('planComparisonCard/icon/size', modes) ?? 16;
109
+ const toWeight = w => typeof w === 'number' ? `${w}` : w;
110
+ const headerTextStyle = {
111
+ ...NO_WRAP_TEXT,
112
+ fontFamily: headerFontFamily,
113
+ fontSize: headerFontSize,
114
+ lineHeight: headerLineHeight,
115
+ fontWeight: toWeight(headerFontWeight),
116
+ textAlign: 'center'
117
+ };
118
+ const labelTextStyle = {
119
+ ...NO_WRAP_TEXT,
120
+ color: labelColor,
121
+ fontFamily: labelFontFamily,
122
+ fontSize: labelFontSize,
123
+ lineHeight: labelLineHeight,
124
+ fontWeight: toWeight(labelFontWeight)
125
+ };
126
+ const valueTextStyle = {
127
+ ...NO_WRAP_TEXT,
128
+ color: valueColor,
129
+ fontFamily: valueFontFamily,
130
+ fontSize: valueFontSize,
131
+ lineHeight: valueLineHeight,
132
+ fontWeight: toWeight(valueFontWeight),
133
+ textAlign: 'center'
134
+ };
135
+ const rowStyle = {
136
+ flexDirection: 'row',
137
+ width: '100%'
138
+ };
139
+ const labelCellStyle = {
140
+ flexDirection: 'row',
141
+ alignItems: 'center',
142
+ gap: cellGap,
143
+ padding: cellPadding,
144
+ minHeight: cellMinHeight
145
+ };
146
+ const valueCellStyle = {
147
+ flexDirection: 'row',
148
+ alignItems: 'center',
149
+ justifyContent: 'center',
150
+ padding: cellPadding,
151
+ minHeight: cellMinHeight,
152
+ width: '100%'
153
+ };
154
+ const renderValue = (value, cellKey) => {
155
+ if (value === false) {
156
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.default, {
157
+ name: "ic_close",
158
+ size: iconSize,
159
+ color: labelDisabledColor
160
+ }, cellKey);
161
+ }
162
+ if (value === null || value === undefined || value === true) {
163
+ return null;
164
+ }
165
+ if (typeof value === 'string' || typeof value === 'number') {
166
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
167
+ style: valueTextStyle,
168
+ children: value
169
+ }, cellKey);
170
+ }
171
+ return (0, _reactUtils.cloneChildrenWithModes)(value, modes);
172
+ };
173
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
174
+ style: [{
175
+ gap,
176
+ width: '100%'
177
+ }, style],
178
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
179
+ style: rowStyle,
180
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
181
+ style: labelColumnStyle
182
+ }), columns.map((column, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
183
+ style: planColumnStyle,
184
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
185
+ style: [headerTextStyle, {
186
+ color: column.brand ? headerBrandFg : headerFg
187
+ }],
188
+ children: column.label
189
+ })
190
+ }, column.label ?? index))]
191
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
192
+ style: {
193
+ width: '100%',
194
+ backgroundColor: tableBackground,
195
+ borderWidth: tableBorderSize,
196
+ borderColor: tableBorderColor,
197
+ borderRadius: tableRadius,
198
+ overflow: 'hidden'
199
+ },
200
+ children: rows.map((row, rowIndex) => {
201
+ const isLast = rowIndex === rows.length - 1;
202
+ const showInfo = row.showInfo || row.onInfoPress != null;
203
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
204
+ style: [rowStyle, {
205
+ borderBottomWidth: isLast ? 0 : cellBorderSize,
206
+ borderBottomColor: cellBorderColor
207
+ }],
208
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
209
+ style: [labelColumnStyle, labelCellStyle],
210
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
211
+ style: labelTextStyle,
212
+ children: row.label
213
+ }), showInfo && (row.onInfoPress ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
214
+ onPress: row.onInfoPress,
215
+ accessibilityRole: "button",
216
+ accessibilityLabel: `More information about ${row.label}`,
217
+ hitSlop: 8,
218
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.default, {
219
+ name: "ic_info",
220
+ size: iconSize,
221
+ color: iconColor
222
+ })
223
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.default, {
224
+ name: "ic_info",
225
+ size: iconSize,
226
+ color: iconColor
227
+ }))]
228
+ }), columns.map((column, colIndex) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
229
+ style: [planColumnStyle, valueCellStyle],
230
+ children: renderValue(row.values?.[colIndex], `${rowIndex}-${colIndex}`)
231
+ }, column.label ?? colIndex))]
232
+ }, row.key ?? `${row.label}-${rowIndex}`);
233
+ })
234
+ })]
235
+ });
236
+ }
237
+ var _default = exports.default = PlanComparisonCard;
@@ -0,0 +1,73 @@
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 _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
+ /**
15
+ * Slot — a token-driven layout container for grouped slot content.
16
+ *
17
+ * Use `Slot` instead of a raw `View` when you need a vertical or horizontal
18
+ * stack with design-token gap spacing and automatic `modes` propagation to
19
+ * children. Typical usage is nesting a column of actions inside a
20
+ * direction-locked parent such as `ActionFooter`:
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * <ActionFooter modes={modes}>
25
+ * <Slot layoutDirection="vertical" modes={modes}>
26
+ * <Button label="Continue" modes={primaryModes} />
27
+ * <Disclaimer disclaimer="Terms apply." modes={modes} />
28
+ * </Slot>
29
+ * </ActionFooter>
30
+ * ```
31
+ */
32
+ function Slot({
33
+ children,
34
+ layoutDirection = 'vertical',
35
+ alignCrossAxis,
36
+ justifyMainAxis,
37
+ modes: propModes = _reactUtils.EMPTY_MODES,
38
+ style,
39
+ ...rest
40
+ }) {
41
+ const {
42
+ modes: globalModes
43
+ } = (0, _JFSThemeProvider.useTokens)();
44
+ const modes = (0, _react.useMemo)(() => ({
45
+ ...globalModes,
46
+ ...propModes
47
+ }), [globalModes, propModes]);
48
+ const {
49
+ containerStyle,
50
+ processedChildren
51
+ } = (0, _react.useMemo)(() => {
52
+ const gap = (0, _figmaVariablesResolver.getVariableByName)('slot/gap', modes) ?? 8;
53
+ const isHorizontal = layoutDirection === 'horizontal';
54
+ const container = {
55
+ flexDirection: isHorizontal ? 'row' : 'column',
56
+ alignItems: alignCrossAxis ?? (isHorizontal ? 'flex-start' : 'stretch'),
57
+ justifyContent: justifyMainAxis ?? (isHorizontal ? 'center' : undefined),
58
+ alignSelf: 'stretch',
59
+ gap
60
+ };
61
+ const processed = children ? (0, _reactUtils.cloneChildrenWithModes)(children, modes) : null;
62
+ return {
63
+ containerStyle: container,
64
+ processedChildren: processed
65
+ };
66
+ }, [children, modes, layoutDirection, alignCrossAxis, justifyMainAxis]);
67
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
68
+ style: [containerStyle, style],
69
+ ...rest,
70
+ children: processedChildren
71
+ });
72
+ }
73
+ var _default = exports.default = /*#__PURE__*/_react.default.memo(Slot);