jfs-components 0.1.55 → 0.1.57

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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,16 @@ All notable changes to this project are documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
+ ## [0.1.57] - 2026-07-27
8
+
9
+ - `Carousel` — fix infinite-tall slides: equal-height no longer uses unbounded `alignItems:'stretch'` / `height:'100%'` in a horizontal ScrollView; it measures intrinsic slide heights then locks slots to the tallest.
10
+ - `CardCTA` (rating) — pin the footer when given an explicit height without `flexGrow` (which also caused infinite height in horizontal carousels).
11
+
12
+ ## [0.1.56] - 2026-07-27
13
+
14
+ - `Carousel` — `equalHeight` defaults to `true` (hug tallest slide; no token `maxHeight` clip). New `itemInset`, `bleedHorizontal`, and `maxHeight` (`number | false`) props for edge-aligned cards without consumer math. Opt out with `equalHeight={false}` to keep the legacy clipped strip. Storybook docs refreshed for the new API.
15
+ - `CardCTA` (rating) — media/badge slot centers by default (`ratingMediaAlign`); `showButton={false}` for actions-only start-aligned footers; rating footer IconButtons keep Neutral / S / Low even when the card is Secondary; rating cards stretch and pin the footer in equal-height carousels.
16
+
7
17
  ## [0.1.55] - 2026-07-27
8
18
 
9
19
  - D2C playbooks (`.cursor/commands/D2C.md`, `.cursor/D2C-FLOW.md`, `.cursor/D2C-SCREEN.md`) — on unresolved mode pairs, notify the user then continue with resolved modes (no longer stop execution).
@@ -15,14 +15,14 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
15
15
  * ButtonGroup component that aggregates multiple buttons (e.g., IconButton)
16
16
  * and handles their layout and styling/theming via design tokens.
17
17
  *
18
- * It passes the provided `modes` to all its immediate React Element children.
19
- * Non-IconButton children (e.g., Button) are automatically stretched to fill
20
- * available space. IconButton children keep their natural width.
18
+ * Group `modes` cascade to every child (and nested slot children). A child's
19
+ * own `modes` still win on conflict. Non-IconButton children (e.g. Button) are
20
+ * stretched to fill available space; IconButton children keep intrinsic width.
21
21
  *
22
22
  * @component
23
23
  * @example
24
24
  * ```jsx
25
- * <ButtonGroup modes={{"Color Mode": "Light"}}>
25
+ * <ButtonGroup modes={{"Color Mode": "Light", AppearanceBrand: "Neutral"}}>
26
26
  * <IconButton iconName="ic_qr_code" />
27
27
  * <Button label="Pay" />
28
28
  * </ButtonGroup>
@@ -33,12 +33,9 @@ function ButtonGroup({
33
33
  modes = _reactUtils.EMPTY_MODES,
34
34
  style
35
35
  }) {
36
- // Resolve design tokens
37
36
  const gap = (0, _figmaVariablesResolver.getVariableByName)('buttonGroup/gap', modes) ?? 12;
38
37
  const paddingHorizontal = (0, _figmaVariablesResolver.getVariableByName)('buttonGroup/padding/horizontal', modes) ?? 0;
39
38
  const paddingVertical = (0, _figmaVariablesResolver.getVariableByName)('buttonGroup/padding/vertical', modes) ?? 0;
40
-
41
- // Container style
42
39
  const containerStyle = {
43
40
  flexDirection: 'row',
44
41
  alignItems: 'center',
@@ -46,27 +43,20 @@ function ButtonGroup({
46
43
  paddingHorizontal: paddingHorizontal,
47
44
  paddingVertical: paddingVertical
48
45
  };
49
-
50
- // Flatten children to handle Fragments properly
51
46
  const flatChildren = (0, _reactUtils.flattenChildren)(children);
52
- const childrenWithModes = _react.default.Children.map(flatChildren, child => {
53
- if (/*#__PURE__*/_react.default.isValidElement(child)) {
54
- const element = child;
55
- const childModes = element.props.modes || {};
56
- const mergedModes = {
57
- ...modes,
58
- ...childModes
59
- };
60
- const isIconButton = element.type === _IconButton.default;
61
- const stretchStyle = isIconButton ? undefined : {
62
- flex: 1
63
- };
64
- return /*#__PURE__*/_react.default.cloneElement(element, {
65
- modes: mergedModes,
66
- style: [stretchStyle, element.props.style]
67
- });
47
+ const cascadedChildren = (0, _reactUtils.cloneChildrenWithModes)(flatChildren, modes);
48
+ const childrenWithModes = _react.default.Children.map(cascadedChildren, child => {
49
+ if (! /*#__PURE__*/_react.default.isValidElement(child)) {
50
+ return child;
68
51
  }
69
- return child;
52
+ const element = child;
53
+ const isIconButton = element.type === _IconButton.default;
54
+ const stretchStyle = isIconButton ? undefined : {
55
+ flex: 1
56
+ };
57
+ return /*#__PURE__*/_react.default.cloneElement(element, {
58
+ style: [stretchStyle, element.props.style]
59
+ });
70
60
  });
71
61
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
72
62
  style: [containerStyle, style],
@@ -46,6 +46,8 @@ function CardCTA({
46
46
  onPressButton,
47
47
  ratingLabel = '+28 Rating',
48
48
  showRatingActions = true,
49
+ showButton = true,
50
+ ratingMediaAlign = 'center',
49
51
  onPressLike,
50
52
  onPressDislike,
51
53
  headline = 'Headline',
@@ -132,11 +134,14 @@ function CardCTA({
132
134
  AppearanceBrand: 'Secondary',
133
135
  'Button / Size': 'S'
134
136
  };
137
+ // Rating footer IconButtons are Neutral / S / Low per Figma. Apply those
138
+ // AFTER cascaded modes so card-level AppearanceBrand (often Secondary)
139
+ // cannot override the footer chrome.
135
140
  const iconButtonModes = {
141
+ ...modes,
136
142
  'Button / Size': 'S',
137
- 'Emphasis': 'Low',
138
- 'AppearanceBrand': 'Neutral',
139
- ...modes
143
+ Emphasis: 'Low',
144
+ AppearanceBrand: 'Neutral'
140
145
  };
141
146
  const effectiveButtonLabel = buttonLabel ?? (isRating ? 'Save' : 'Button');
142
147
  const nonWrappingButtonLabel = effectiveButtonLabel.replace(/\s/g, '\u00A0');
@@ -209,7 +214,13 @@ function CardCTA({
209
214
  borderWidth: borderSize,
210
215
  borderColor,
211
216
  flexDirection: isRating || isSip ? 'column' : 'row',
212
- overflow: 'visible'
217
+ overflow: 'visible',
218
+ // Pin footer to the bottom when a parent (e.g. equal-height Carousel)
219
+ // assigns an explicit height. Do not flexGrow — that unbounded-grows
220
+ // inside horizontal ScrollViews and blows cards to infinite height.
221
+ ...(isRating ? {
222
+ justifyContent: 'space-between'
223
+ } : {})
213
224
  };
214
225
 
215
226
  // NOTE: `minWidth: 0` + explicit `flexShrink: 1` are required on native.
@@ -358,16 +369,23 @@ function CardCTA({
358
369
  paddingHorizontal: ratingContentPaddingH,
359
370
  paddingVertical: ratingContentPaddingV,
360
371
  gap: ratingContentGap,
361
- alignItems: 'flex-start'
372
+ alignItems: 'flex-start',
373
+ alignSelf: 'stretch'
374
+ };
375
+ const ratingMediaStyle = {
376
+ alignSelf: 'stretch',
377
+ width: '100%',
378
+ alignItems: ratingMediaAlign === 'center' ? 'center' : 'flex-start'
362
379
  };
363
380
  const ratingFooterStyle = {
364
381
  flexDirection: 'row',
365
382
  alignItems: 'flex-start',
366
- justifyContent: 'space-between',
383
+ justifyContent: showButton ? 'space-between' : 'flex-start',
367
384
  paddingHorizontal: ratingFooterPaddingH,
368
385
  paddingTop: ratingFooterPaddingTop,
369
386
  paddingBottom: ratingFooterPaddingBottom,
370
- overflow: 'visible'
387
+ overflow: 'visible',
388
+ alignSelf: 'stretch'
371
389
  };
372
390
  const buttonLabelStyle = {
373
391
  flexGrow: 0,
@@ -451,9 +469,12 @@ function CardCTA({
451
469
  style: [containerStyle, style],
452
470
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
453
471
  style: ratingContentStyle,
454
- children: [ratingBadgeSlot ? (0, _reactUtils.cloneChildrenWithModes)(ratingBadgeSlot, modes) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_Badge.default, {
455
- label: ratingLabel,
456
- modes: modes
472
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
473
+ style: ratingMediaStyle,
474
+ children: ratingBadgeSlot ? (0, _reactUtils.cloneChildrenWithModes)(ratingBadgeSlot, modes) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_Badge.default, {
475
+ label: ratingLabel,
476
+ modes: modes
477
+ })
457
478
  }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
458
479
  style: textWrapStyle,
459
480
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
@@ -466,7 +487,7 @@ function CardCTA({
466
487
  })]
467
488
  }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
468
489
  style: ratingFooterStyle,
469
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
490
+ children: [showButton ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
470
491
  style: ratingButtonWrapStyle,
471
492
  children: buttonSlot ? (0, _reactUtils.cloneChildrenWithModes)(buttonSlot, buttonModes) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, {
472
493
  label: effectiveButtonLabel,
@@ -475,17 +496,19 @@ function CardCTA({
475
496
  style: ratingButtonStyle,
476
497
  renderContent: renderButtonContent(ratingButtonLabelStyle)
477
498
  })
478
- }), showRatingActions ? ratingActionsSlot ? (0, _reactUtils.cloneChildrenWithModes)(ratingActionsSlot, iconButtonModes) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_ButtonGroup.default, {
499
+ }) : null, showRatingActions ? ratingActionsSlot ? (0, _reactUtils.cloneChildrenWithModes)(ratingActionsSlot, iconButtonModes) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_ButtonGroup.default, {
479
500
  modes: iconButtonModes,
480
501
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_IconButton.default, {
481
502
  iconName: "ic_like",
482
503
  accessibilityLabel: "Like",
504
+ modes: iconButtonModes,
483
505
  ...(onPressLike ? {
484
506
  onPress: onPressLike
485
507
  } : {})
486
508
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_IconButton.default, {
487
509
  iconName: "ic_dislike",
488
510
  accessibilityLabel: "Dislike",
511
+ modes: iconButtonModes,
489
512
  ...(onPressDislike ? {
490
513
  onPress: onPressDislike
491
514
  } : {})
@@ -46,8 +46,12 @@ function Carousel({
46
46
  loop = true,
47
47
  gap: gapProp,
48
48
  itemWidth: itemWidthProp,
49
+ itemInset,
50
+ bleedHorizontal,
49
51
  paddingHorizontal: paddingHorizontalProp,
50
52
  paddingVertical: paddingVerticalProp,
53
+ equalHeight = true,
54
+ maxHeight: maxHeightProp,
51
55
  type = 'Default',
52
56
  onIndexChange,
53
57
  style
@@ -59,7 +63,7 @@ function Carousel({
59
63
  const containerPaddingH = parseFloat((0, _figmaVariablesResolver.getVariableByName)('carousel/padding/horizontal', modes));
60
64
  const containerPaddingV = parseFloat((0, _figmaVariablesResolver.getVariableByName)('carousel/padding/vertical', modes));
61
65
  // Outer container max height per Figma (`carousel/maxHeight`).
62
- const maxHeight = parseFloat((0, _figmaVariablesResolver.getVariableByName)('carousel/maxHeight', modes));
66
+ const tokenMaxHeight = parseFloat((0, _figmaVariablesResolver.getVariableByName)('carousel/maxHeight', modes));
63
67
  // Gap between AutoplayControl and NumberPagination in the Numbered overlay.
64
68
  const controlGap = parseFloat((0, _figmaVariablesResolver.getVariableByName)('carouselControl/gap', modes));
65
69
 
@@ -88,15 +92,47 @@ function Carousel({
88
92
  const items = (0, _react.useMemo)(() => _react.default.Children.toArray(children).filter(_react.default.isValidElement), [children]);
89
93
  const totalItems = items.length;
90
94
 
91
- // Effective item width: provided prop, or full container width minus peek offsets.
95
+ // Effective item width: explicit prop, itemInset derivation, or token peek.
92
96
  // For the Numbered variant the items are full-bleed (no peek padding).
93
97
  const effectiveItemWidth = (0, _react.useMemo)(() => {
94
98
  if (itemWidthProp != null) return itemWidthProp;
95
99
  if (containerWidth === 0) return 0;
96
100
  if (isNumbered) return containerWidth;
101
+ if (itemInset != null) {
102
+ return Math.max(0, containerWidth - itemInset * 2);
103
+ }
97
104
  // Full-width minus peekOffset on each side
98
105
  return containerWidth - containerPaddingH * 4;
99
- }, [itemWidthProp, containerWidth, containerPaddingH, isNumbered]);
106
+ }, [itemWidthProp, itemInset, containerWidth, containerPaddingH, isNumbered]);
107
+
108
+ // Equal-height: measure each slide's intrinsic height, then lock every slot
109
+ // to the tallest. Do NOT use contentContainerStyle.alignItems:'stretch' or
110
+ // height:'100%' without a bounded cross-axis — in a horizontal ScrollView
111
+ // that resolves to an unbounded/infinite height.
112
+ const slideHeightsRef = (0, _react.useRef)({});
113
+ const [equalizedHeight, setEqualizedHeight] = (0, _react.useState)();
114
+ const equalizedHeightRef = (0, _react.useRef)(undefined);
115
+ equalizedHeightRef.current = equalizedHeight;
116
+ (0, _react.useEffect)(() => {
117
+ slideHeightsRef.current = {};
118
+ equalizedHeightRef.current = undefined;
119
+ setEqualizedHeight(undefined);
120
+ }, [totalItems, effectiveItemWidth, equalHeight]);
121
+ const handleSlideLayout = (0, _react.useCallback)(index => event => {
122
+ if (!equalHeight) return;
123
+ // Only measure while unconstrained. After lock, the slot height is forced
124
+ // and onLayout would just echo equalizedHeight.
125
+ if (equalizedHeightRef.current != null) return;
126
+ const height = Math.ceil(event.nativeEvent.layout.height);
127
+ if (height <= 0) return;
128
+ const previous = slideHeightsRef.current[index] ?? 0;
129
+ if (height <= previous) return;
130
+ slideHeightsRef.current[index] = height;
131
+ const measured = items.map((_, i) => slideHeightsRef.current[i]);
132
+ if (measured.some(value => value == null)) return;
133
+ const next = Math.max(...measured);
134
+ setEqualizedHeight(next);
135
+ }, [equalHeight, items]);
100
136
 
101
137
  // Snap interval = item width + gap
102
138
  const snapInterval = effectiveItemWidth + gap;
@@ -230,14 +266,20 @@ function Carousel({
230
266
  }, [isPlaying, startAutoPlay, clearAutoPlay]);
231
267
 
232
268
  // ---- Render ----
233
- // Explicit padding props win verbatim; otherwise fall back to the
234
- // token-derived values (horizontal keeps its legacy ×2 "peek" multiplier).
235
- // Numbered variant is full-bleed: zero padding.
236
- const effectivePaddingH = isNumbered ? 0 : paddingHorizontalProp ?? containerPaddingH;
269
+ // Padding priority: Numbered 0; itemInset inset; explicit padding →
270
+ // verbatim; else token (legacy ×2 peek is applied via item width, not here).
271
+ const effectivePaddingH = isNumbered ? 0 : itemInset ?? paddingHorizontalProp ?? containerPaddingH;
237
272
  const effectivePaddingV = isNumbered ? 0 : paddingVerticalProp ?? containerPaddingV;
273
+
274
+ // Equal-height rows hug content — don't clip with the token maxHeight unless
275
+ // the caller opts into a numeric max (or disables equalHeight for legacy strips).
276
+ const resolvedMaxHeight = isNumbered ? undefined : maxHeightProp === false ? undefined : typeof maxHeightProp === 'number' ? maxHeightProp : equalHeight ? undefined : tokenMaxHeight;
238
277
  const outerStyle = {
239
278
  paddingVertical: effectivePaddingV,
240
- maxHeight: isNumbered ? undefined : maxHeight,
279
+ maxHeight: resolvedMaxHeight,
280
+ ...(bleedHorizontal != null ? {
281
+ marginHorizontal: -Math.abs(bleedHorizontal)
282
+ } : {}),
241
283
  // Numbered needs relative positioning for the floating controls overlay.
242
284
  ...(isNumbered ? {
243
285
  overflow: 'hidden'
@@ -246,7 +288,8 @@ function Carousel({
246
288
  const contentContainerStyle = {
247
289
  paddingHorizontal: effectivePaddingH,
248
290
  gap,
249
- // Align items to the start so snap works correctly
291
+ // Always flex-start on the cross axis. Stretch + unbounded ScrollView
292
+ // height is what caused infinite-tall slides.
250
293
  alignItems: 'flex-start'
251
294
  };
252
295
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(CarouselContext.Provider, {
@@ -269,6 +312,8 @@ function Carousel({
269
312
  onScrollEndDrag: handleScrollEndDrag,
270
313
  onMomentumScrollEnd: finishProgrammaticScroll,
271
314
  children: items.map((child, index) => {
315
+ const hasEqualizedHeight = equalHeight && equalizedHeight != null && equalizedHeight > 0;
316
+
272
317
  // Strict slot box: width must be honored; never grow or shrink with
273
318
  // content, and clip anything that misbehaves (e.g. a child whose
274
319
  // inner flex layout would otherwise leak into the next slot on
@@ -278,7 +323,10 @@ function Carousel({
278
323
  flexGrow: 0,
279
324
  flexShrink: 0,
280
325
  flexBasis: effectiveItemWidth > 0 ? effectiveItemWidth : 'auto',
281
- overflow: 'hidden'
326
+ overflow: 'hidden',
327
+ ...(hasEqualizedHeight ? {
328
+ height: equalizedHeight
329
+ } : {})
282
330
  };
283
331
 
284
332
  // The cloned style forces the child's outer node to also honor the
@@ -288,7 +336,11 @@ function Carousel({
288
336
  width: effectiveItemWidth > 0 ? effectiveItemWidth : undefined,
289
337
  maxWidth: effectiveItemWidth > 0 ? effectiveItemWidth : undefined,
290
338
  flexGrow: 0,
291
- flexShrink: 0
339
+ flexShrink: 0,
340
+ ...(hasEqualizedHeight ? {
341
+ height: '100%',
342
+ alignSelf: 'stretch'
343
+ } : {})
292
344
  };
293
345
 
294
346
  // Pass modes down to children
@@ -301,7 +353,11 @@ function Carousel({
301
353
  }) : child;
302
354
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
303
355
  style: slotStyle,
304
- children: childWithModes
356
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
357
+ style: hasEqualizedHeight ? styles.equalizedFill : undefined,
358
+ onLayout: handleSlideLayout(index),
359
+ children: childWithModes
360
+ })
305
361
  }, index);
306
362
  })
307
363
  }), !isNumbered && showPagination && totalItems > 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(Pagination, {
@@ -450,6 +506,11 @@ function AnimatedDot({
450
506
  }
451
507
  });
452
508
  }
509
+ const styles = _reactNative.StyleSheet.create({
510
+ equalizedFill: {
511
+ flex: 1
512
+ }
513
+ });
453
514
 
454
515
  // ---------------------------------------------------------------------------
455
516
  // Attach sub-components
@@ -202,6 +202,7 @@ const FIGMA_MODES = exports.FIGMA_MODES = {
202
202
  "NavArrow Direction": ["Left&Right", "Top&Bottom"],
203
203
  "NoteInput / Output": ["Default"],
204
204
  "Nudge / Output": ["Default"],
205
+ "Nudge Border Radius ": ["Default", "Pill"],
205
206
  "Nudge padding": ["Default", "None"],
206
207
  "number pagination": ["Default"],
207
208
  "Numpad / Output": ["Default"],
@@ -326,19 +327,19 @@ const FIGMA_COMPONENT_MODES = exports.FIGMA_COMPONENT_MODES = {
326
327
  "AvatarGroup": ["Avatar Size", "Badge Size", "Context4"],
327
328
  "Badge": ["AppearanceBrand", "AppearanceSystem", "Badge Size", "Color Mode", "Emphasis", "Semantic Intent"],
328
329
  "Balance": ["Color Mode", "Context3"],
329
- "BenefitCard": ["AppearanceBrand", "AppearanceSystem", "Avatar Size", "Badge Size", "Button / Size", "Button / State", "Button Glass State", "Button type", "Color Mode", "Context", "context 10", "Context4", "Emphasis", "Nudge padding", "Page type", "Profile Card Appearance", "Semantic Intent", "Slot gap", "Text Appearance", "Text Sizes", "Weight"],
330
+ "BenefitCard": ["AppearanceBrand", "AppearanceSystem", "Avatar Size", "Badge Size", "Button / Size", "Button / State", "Button Glass State", "Button type", "Color Mode", "Context", "context 10", "Context4", "Emphasis", "Nudge Border Radius ", "Nudge padding", "Page type", "Profile Card Appearance", "Semantic Intent", "Slot gap", "Text Appearance", "Text Sizes", "Weight"],
330
331
  "BottomNav": ["Color Mode"],
331
332
  "BottomNavItem": ["BottomNavItem / State", "Color Mode"],
332
333
  "BrandChip": ["Avatar Size", "Badge Size", "Color Mode", "context 10", "Context4", "Profile Card Appearance"],
333
334
  "BubbleChart": ["Appearance / DataViz", "Color Mode", "Context", "context 10", "Emphasis / DataViz", "Profile Card Appearance", "Text Appearance"],
334
335
  "Button": ["AppearanceBrand", "AppearanceSystem", "Button / Size", "Button / State", "Button Glass State", "Button type", "Color Mode", "Context", "context 10", "Emphasis", "Page type", "Profile Card Appearance", "Semantic Intent"],
335
336
  "Card": ["AppearanceBrand", "AppearanceSystem", "Card Container", "Color Mode", "context 8", "Gap", "Page type", "Semantic Intent"],
336
- "CardAdvisory": ["AppearanceBrand", "AppearanceSystem", "Button / Size", "Button / State", "Button Glass State", "Button type", "circularProgressBar Size", "Color Mode", "Context", "context 10", "Emphasis", "Nudge padding", "Page type", "Profile Card Appearance", "Semantic Intent", "Slot gap"],
337
+ "CardAdvisory": ["AppearanceBrand", "AppearanceSystem", "Button / Size", "Button / State", "Button Glass State", "Button type", "circularProgressBar Size", "Color Mode", "Context", "context 10", "Emphasis", "Nudge Border Radius ", "Nudge padding", "Page type", "Profile Card Appearance", "Semantic Intent", "Slot gap"],
337
338
  "CardBankAccount": ["AppearanceBrand", "AppearanceSystem", "Avatar Size", "Badge Size", "Button / Size", "Button / State", "Button Glass State", "Button type", "Color Mode", "Context", "context 10", "Context4", "context5", "Emphasis", "List Item Style", "Page type", "Profile Card Appearance", "Semantic Intent", "Text Appearance", "Text Sizes", "Weight"],
338
339
  "CardCTA": ["AppearanceBrand", "AppearanceSystem", "Avatar Size", "Badge Size", "Button / Size", "Button / State", "Button Glass State", "Button type", "Color Mode", "Context", "context 10", "context 8", "context 9", "Context4", "Emphasis", "Icon Capsule Size", "MediaBlock", "Page type", "Profile Card Appearance", "Semantic Intent"],
339
340
  "CardFeedback": ["AppearanceBrand", "AppearanceSystem", "Color Mode"],
340
- "CardFinancialCondition": ["AppearanceBrand", "AppearanceSystem", "Button / Size", "Button / State", "Button Glass State", "Button type", "circularProgressBar Size", "Color Mode", "Context", "context 10", "Emphasis", "Nudge padding", "Page type", "Profile Card Appearance", "Semantic Intent", "Slot gap"],
341
- "CardInsight": ["Appearance / DataViz", "AppearanceBrand", "AppearanceSystem", "Badge Size", "Button / Size", "Button / State", "Button Glass State", "Button type", "Color Mode", "Context", "context 10", "context 8", "Emphasis", "Emphasis / DataViz", "LinearProgress Size", "Nudge padding", "Page type", "Profile Card Appearance", "Semantic Intent", "Slot gap", "Text Appearance"],
341
+ "CardFinancialCondition": ["AppearanceBrand", "AppearanceSystem", "Button / Size", "Button / State", "Button Glass State", "Button type", "circularProgressBar Size", "Color Mode", "Context", "context 10", "Emphasis", "Nudge Border Radius ", "Nudge padding", "Page type", "Profile Card Appearance", "Semantic Intent", "Slot gap"],
342
+ "CardInsight": ["Appearance / DataViz", "AppearanceBrand", "AppearanceSystem", "Badge Size", "Button / Size", "Button / State", "Button Glass State", "Button type", "Color Mode", "Context", "context 10", "context 8", "Emphasis", "Emphasis / DataViz", "LinearProgress Size", "Nudge Border Radius ", "Nudge padding", "Page type", "Profile Card Appearance", "Semantic Intent", "Slot gap", "Text Appearance"],
342
343
  "CardProviderInfo": ["AppearanceBrand", "Avatar Size", "Badge Size", "Color Mode", "context 10", "Context4", "Profile Card Appearance"],
343
344
  "Carousel": ["peekOffset"],
344
345
  "CarouselCardAccounts": ["peekOffset"],
@@ -349,7 +350,7 @@ const FIGMA_COMPONENT_MODES = exports.FIGMA_COMPONENT_MODES = {
349
350
  "CheckboxItem": ["Color Mode", "Context", "Slot gap"],
350
351
  "ChipSelect": ["ChipSelect State", "Color Mode"],
351
352
  "CircularProgressBar": ["AppearanceBrand", "AppearanceSystem", "circularProgressBar Size", "Color Mode", "Emphasis", "Semantic Intent"],
352
- "CircularRating": ["AppearanceBrand", "AppearanceSystem", "Button / Size", "Button / State", "Button Glass State", "Button type", "Color Mode", "Context", "context 10", "Emphasis", "Nudge padding", "Page type", "Profile Card Appearance", "Semantic Intent", "Slot gap"],
353
+ "CircularRating": ["AppearanceBrand", "AppearanceSystem", "Button / Size", "Button / State", "Button Glass State", "Button type", "Color Mode", "Context", "context 10", "Emphasis", "Nudge Border Radius ", "Nudge padding", "Page type", "Profile Card Appearance", "Semantic Intent", "Slot gap"],
353
354
  "ClusterBubble": ["Appearance / DataViz", "Color Mode", "Context", "context 10", "Emphasis / DataViz", "Profile Card Appearance", "Text Appearance"],
354
355
  "CompareTable": ["Accordion States", "AppearanceBrand", "Button / Size", "Button / State", "Color Mode", "Emphasis", "Page type", "Radius"],
355
356
  "ComparisonBar": ["AppearanceBrand", "AppearanceSystem", "Button / Size", "Button / State", "Button Glass State", "Button type", "Color Mode", "Context", "context 10", "Emphasis", "Icon Capsule Size", "Page type", "Profile Card Appearance", "Radius", "Semantic Intent"],
@@ -377,7 +378,7 @@ const FIGMA_COMPONENT_MODES = exports.FIGMA_COMPONENT_MODES = {
377
378
  "HeroSection": ["AppearanceBrand", "Button / Size", "Button / State", "Color Mode", "context 9", "context7", "Emphasis", "FormField States", "InputState", "Page type", "Status"],
378
379
  "HoldingsCard": ["AppearanceBrand", "Color Mode"],
379
380
  "HStack": ["Context", "Padding", "Page type", "Slot gap", "Stack Context"],
380
- "Icon": ["AppearanceBrand", "AppearanceSystem", "Badge Size", "Color Mode", "context 10", "Context4", "Emphasis", "Page type", "Profile Card Appearance", "Semantic Intent"],
381
+ "Icon": ["AppearanceBrand", "Badge Size", "Color Mode", "context 10", "Context4", "Emphasis", "Page type", "Profile Card Appearance", "Semantic Intent"],
381
382
  "IconButton": ["AppearanceBrand", "Button / Size", "Button / State", "Color Mode", "Emphasis", "Page type"],
382
383
  "IconCapsule": ["AppearanceBrand", "AppearanceSystem", "Color Mode", "Context", "Emphasis", "Icon Capsule Size", "Page type", "Semantic Intent"],
383
384
  "InputSearch": ["Color Mode", "FormField States", "InputState", "Status"],
@@ -392,12 +393,12 @@ const FIGMA_COMPONENT_MODES = exports.FIGMA_COMPONENT_MODES = {
392
393
  "MediaCard": ["Contrast Context"],
393
394
  "MerchantProfile": ["Avatar Size", "Badge Size", "Color Mode", "context 10", "Context4", "Profile Card Appearance"],
394
395
  "MessageField": ["Color Mode", "FormField States"],
395
- "MetricData": ["AppearanceBrand", "AppearanceSystem", "Badge Size", "Color Mode", "context 10", "Context4", "Emphasis", "Page type", "Profile Card Appearance", "Semantic Intent"],
396
+ "MetricData": ["AppearanceBrand", "Badge Size", "Color Mode", "context 10", "Context4", "Emphasis", "Page type", "Profile Card Appearance", "Semantic Intent"],
396
397
  "MetricLegendItem": ["Appearance / DataViz", "Color Mode", "Emphasis / DataViz"],
397
398
  "MoneyValue": ["Color Mode", "Context3"],
398
399
  "MonthlyStatusGrid": ["Appearance / DataViz", "Calendar Glyph State", "Color Mode", "Emphasis / DataViz"],
399
400
  "NavArrow": ["Color Mode", "context 10", "Context2", "context5", "List Item Style", "NavArrow Direction", "Page type", "Profile Card Appearance"],
400
- "Nudge": ["AppearanceBrand", "AppearanceSystem", "Button / Size", "Button / State", "Button Glass State", "Button type", "Color Mode", "Context", "context 10", "Emphasis", "Nudge padding", "Page type", "Profile Card Appearance", "Semantic Intent", "Slot gap"],
401
+ "Nudge": ["AppearanceBrand", "AppearanceSystem", "Button / Size", "Button / State", "Button Glass State", "Button type", "Color Mode", "Context", "context 10", "Emphasis", "Nudge Border Radius ", "Nudge padding", "Page type", "Profile Card Appearance", "Semantic Intent", "Slot gap"],
401
402
  "OTP": ["AppearanceBrand", "AppearanceSystem", "Button / Size", "Button / State", "Button Glass State", "Button type", "Color Mode", "Context", "context 10", "Emphasis", "FormField States", "Input/PINSlot States", "Page type", "Profile Card Appearance", "Semantic Intent", "Status"],
402
403
  "PageHero": ["AppearanceBrand", "AppearanceSystem", "Button / Size", "Button / State", "Button Glass State", "Button type", "Color Mode", "Context", "context 10", "Emphasis", "Page type", "PageHero Size", "Profile Card Appearance", "Semantic Intent", "Video / Output"],
403
404
  "PaymentFeedback": ["AppearanceBrand", "AppearanceSystem", "Color Mode", "Context", "Emphasis", "Icon Capsule Size", "Page type", "Semantic Intent"],
@@ -443,7 +444,7 @@ const FIGMA_COMPONENT_MODES = exports.FIGMA_COMPONENT_MODES = {
443
444
  "TransactionBubble": ["Color Mode", "context 10", "Context2", "Context3", "context5", "List Item Style", "NavArrow Direction", "Page type", "Profile Card Appearance", "Transaction Status"],
444
445
  "TransactionStatus": ["Transaction Status"],
445
446
  "UpiHandle": ["Color Mode", "context 10", "Profile Card Appearance", "UPI Handle Image"],
446
- "ValueBackMetric": ["AppearanceBrand", "AppearanceSystem", "Badge Size", "Color Mode", "Context", "context 10", "Context4", "Emphasis", "Page type", "Profile Card Appearance", "Semantic Intent", "Text Appearance", "Text Sizes", "Weight"],
447
+ "ValueBackMetric": ["AppearanceBrand", "Badge Size", "Color Mode", "Context", "context 10", "Context4", "Emphasis", "Page type", "Profile Card Appearance", "Semantic Intent", "Text Appearance", "Text Sizes", "Weight"],
447
448
  "VStack": ["Context", "Padding", "Page type", "Slot gap", "Stack Context"]
448
449
  };
449
450