jfs-components 0.1.48 → 0.1.49

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.
@@ -36,6 +36,7 @@ type BentoToggleRenderState = {
36
36
  type SectionBentoProps = {
37
37
  navSlot?: React.ReactNode;
38
38
  upiSlot?: React.ReactNode;
39
+ upi?: boolean;
39
40
  modes?: Modes;
40
41
  style?: StyleProp<ViewStyle>;
41
42
  accessibilityLabel?: string;
@@ -82,6 +83,6 @@ type SectionBentoProps = {
82
83
  */
83
84
  renderToggle?: (state: BentoToggleRenderState) => React.ReactNode;
84
85
  } & React.ComponentProps<typeof View>;
85
- declare function SectionBento({ navSlot, upiSlot, modes, style, accessibilityLabel: _accessibilityLabel, accessibilityHint, collapsedCount, defaultExpanded, expanded: controlledExpanded, onExpandedChange, toggleMoreLabel, toggleLessLabel, toggleMoreIcon, toggleLessIcon, renderToggle, ...rest }: SectionBentoProps): import("react/jsx-runtime").JSX.Element;
86
+ declare function SectionBento({ navSlot, upiSlot, upi, modes, style, accessibilityLabel: _accessibilityLabel, accessibilityHint, collapsedCount, defaultExpanded, expanded: controlledExpanded, onExpandedChange, toggleMoreLabel, toggleLessLabel, toggleMoreIcon, toggleLessIcon, renderToggle, ...rest }: SectionBentoProps): import("react/jsx-runtime").JSX.Element;
86
87
  export default Section;
87
88
  //# sourceMappingURL=Section.d.ts.map
@@ -46,7 +46,7 @@ export declare const FIGMA_MODES: {
46
46
  readonly "Calendar Glyph / Output": readonly ["Default"];
47
47
  readonly "Calendar Glyph State": readonly ["Idle", "notSaved", "saved"];
48
48
  readonly "Card / Output": readonly ["Default"];
49
- readonly "Card Apperance": readonly ["Default", "Plain"];
49
+ readonly "Card Container": readonly ["Default", "Plain"];
50
50
  readonly "Card Feedback / Output": readonly ["Default"];
51
51
  readonly "Card Tab / output": readonly ["Default"];
52
52
  readonly "Card Tab State": readonly ["Default", "Active"];
@@ -231,6 +231,7 @@ export declare const FIGMA_MODES: {
231
231
  readonly "Slot gap": readonly ["S", "M", "L", "XL", "XS"];
232
232
  readonly "special button": readonly ["Default"];
233
233
  readonly "Spinner / Output": readonly ["Default"];
234
+ readonly "Stack Context": readonly ["Root", "Nested"];
234
235
  readonly "statGroup / Output": readonly ["Default"];
235
236
  readonly "StatItem / Output": readonly ["Default"];
236
237
  readonly "StatItem Label Position ": readonly ["Top", "Bottom"];
@@ -4,7 +4,7 @@
4
4
  * Auto-generated from SVG files in src/icons/
5
5
  * DO NOT EDIT MANUALLY - Run "npm run icons:generate" to regenerate
6
6
  *
7
- * Generated: 2026-07-22T21:03:43.084Z
7
+ * Generated: 2026-07-25T08:19:21.865Z
8
8
  */
9
9
  export declare const iconRegistry: Record<string, {
10
10
  path: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jfs-components",
3
- "version": "0.1.48",
3
+ "version": "0.1.49",
4
4
  "description": "React Native Jio Finance Components Library",
5
5
  "author": "sunshuaiqi@gmail.com",
6
6
  "license": "MIT",
@@ -1,5 +1,13 @@
1
1
  import React, { useState, useMemo, useRef, useCallback } from 'react'
2
- import { View, Text, Pressable, Platform, type StyleProp, type ViewStyle, type PressableStateCallbackType } from 'react-native'
2
+ import {
3
+ View,
4
+ Text,
5
+ Pressable,
6
+ Platform,
7
+ type StyleProp,
8
+ type ViewStyle,
9
+ type PressableStateCallbackType,
10
+ } from 'react-native'
3
11
  import Animated, {
4
12
  Easing,
5
13
  FadeInUp,
@@ -94,16 +102,16 @@ const SLOT_GRID_HEIGHT_DURATION_MS = 280
94
102
  const SLOT_GRID_EASING = Easing.out(Easing.cubic)
95
103
 
96
104
  type SlotGridProps = {
97
- items: React.ReactNode[];
98
- gap: number;
99
- maxColumns?: number;
105
+ items: React.ReactNode[]
106
+ gap: number
107
+ maxColumns?: number
100
108
  /**
101
109
  * If set, cells whose index is `>= animateExtrasFromIndex` are wrapped in
102
110
  * `Animated.View` with staggered FadeInUp/FadeOutUp builders so that they
103
111
  * fade in (and reverse-fade out) when they mount or unmount. Cells below
104
112
  * this threshold render as plain `<View>` and are unaffected.
105
113
  */
106
- animateExtrasFromIndex?: number;
114
+ animateExtrasFromIndex?: number
107
115
  /**
108
116
  * If true, the rows container animates its height via an explicit
109
117
  * `useSharedValue` + `withTiming` (ease-out cubic, no overshoot) driven by
@@ -111,7 +119,7 @@ type SlotGridProps = {
111
119
  * to clip mid-animation. Cells inside always render at their natural size
112
120
  * — they are *never* resized during the transition. Default false.
113
121
  */
114
- animateContainerLayout?: boolean;
122
+ animateContainerLayout?: boolean
115
123
  }
116
124
 
117
125
  const slotGridRowFlowStyle: ViewStyle = {
@@ -150,12 +158,10 @@ const SlotGrid = React.memo(function SlotGrid({
150
158
  for (const w of widths.values()) {
151
159
  if (w > newMax) newMax = w
152
160
  }
153
- setFirstRowMaxWidth((prev) =>
154
- prev !== null && Math.abs(prev - newMax) < 0.5 ? prev : newMax
155
- )
161
+ setFirstRowMaxWidth((prev) => (prev !== null && Math.abs(prev - newMax) < 0.5 ? prev : newMax))
156
162
  }
157
163
  },
158
- [firstRowSize]
164
+ [firstRowSize],
159
165
  )
160
166
 
161
167
  const cellWidth = firstRowMaxWidth
@@ -175,7 +181,7 @@ const SlotGrid = React.memo(function SlotGrid({
175
181
  // animated-height clip springs to the new total).
176
182
  const cellStyle = useMemo<ViewStyle | undefined>(
177
183
  () => (cellWidth !== null ? { width: cellWidth } : undefined),
178
- [cellWidth]
184
+ [cellWidth],
179
185
  )
180
186
 
181
187
  // `space-between` distributes any leftover row space as inter-cell gap, so
@@ -188,15 +194,11 @@ const SlotGrid = React.memo(function SlotGrid({
188
194
  // Resolve the threshold once. When undefined we treat it as
189
195
  // Number.POSITIVE_INFINITY so the per-cell branch always picks the plain
190
196
  // `<View>` path.
191
- const extrasThreshold = animationsEnabled
192
- ? (animateExtrasFromIndex as number)
193
- : Number.POSITIVE_INFINITY
197
+ const extrasThreshold = animationsEnabled ? (animateExtrasFromIndex as number) : Number.POSITIVE_INFINITY
194
198
  // Total count of "extra" cells currently rendered. Used to compute the
195
199
  // reverse-stagger delay for the exiting animation so that the last cell
196
200
  // leaves first.
197
- const extrasCount = animationsEnabled
198
- ? Math.max(0, totalItems - extrasThreshold)
199
- : 0
201
+ const extrasCount = animationsEnabled ? Math.max(0, totalItems - extrasThreshold) : 0
200
202
 
201
203
  const useAnimatedContainer = animateContainerLayout === true
202
204
 
@@ -236,12 +238,10 @@ const SlotGrid = React.memo(function SlotGrid({
236
238
  reduceMotion: ReduceMotion.System,
237
239
  })
238
240
  },
239
- [animatedHeight]
241
+ [animatedHeight],
240
242
  )
241
243
  const animatedHeightStyle = useAnimatedStyle(() =>
242
- animatedHeight.value < 0
243
- ? {}
244
- : { height: animatedHeight.value, overflow: 'hidden' as const }
244
+ animatedHeight.value < 0 ? {} : { height: animatedHeight.value, overflow: 'hidden' as const },
245
245
  )
246
246
 
247
247
  const rowsChildren = (
@@ -258,26 +258,14 @@ const SlotGrid = React.memo(function SlotGrid({
258
258
  const onLayoutHandler =
259
259
  firstRowMaxWidth === null && itemIndex < firstRowSize
260
260
  ? (e: { nativeEvent: { layout: { width: number } } }) =>
261
- handleFirstRowItemLayout(
262
- itemIndex,
263
- e.nativeEvent.layout.width
264
- )
261
+ handleFirstRowItemLayout(itemIndex, e.nativeEvent.layout.width)
265
262
  : undefined
266
263
 
267
264
  if (itemIndex >= extrasThreshold) {
268
265
  const extraOrdinal = itemIndex - extrasThreshold
269
- const enterStaggerSteps = Math.min(
270
- extraOrdinal,
271
- SLOT_GRID_STAGGER_CAP
272
- )
273
- const reverseOrdinal = Math.max(
274
- 0,
275
- extrasCount - 1 - extraOrdinal
276
- )
277
- const exitStaggerSteps = Math.min(
278
- reverseOrdinal,
279
- SLOT_GRID_STAGGER_CAP
280
- )
266
+ const enterStaggerSteps = Math.min(extraOrdinal, SLOT_GRID_STAGGER_CAP)
267
+ const reverseOrdinal = Math.max(0, extrasCount - 1 - extraOrdinal)
268
+ const exitStaggerSteps = Math.min(reverseOrdinal, SLOT_GRID_STAGGER_CAP)
281
269
  const entering = FadeInUp.duration(SLOT_GRID_ENTER_DURATION_MS)
282
270
  .easing(SLOT_GRID_EASING)
283
271
  .delay(enterStaggerSteps * SLOT_GRID_ENTER_STAGGER_MS)
@@ -300,20 +288,14 @@ const SlotGrid = React.memo(function SlotGrid({
300
288
  }
301
289
 
302
290
  return (
303
- <View
304
- key={itemIndex}
305
- {...(onLayoutHandler ? { onLayout: onLayoutHandler } : null)}
306
- style={cellStyle}
307
- >
291
+ <View key={itemIndex} {...(onLayoutHandler ? { onLayout: onLayoutHandler } : null)} style={cellStyle}>
308
292
  {child}
309
293
  </View>
310
294
  )
311
295
  })}
312
296
  {cellWidth !== null &&
313
297
  spacersNeeded > 0 &&
314
- Array.from({ length: spacersNeeded }, (_, i) => (
315
- <View key={`spacer-${i}`} style={cellStyle} />
316
- ))}
298
+ Array.from({ length: spacersNeeded }, (_, i) => <View key={`spacer-${i}`} style={cellStyle} />)}
317
299
  </View>
318
300
  )
319
301
  })}
@@ -351,28 +333,28 @@ function slotGridPropsAreEqual(prev: SlotGridProps, next: SlotGridProps) {
351
333
  }
352
334
 
353
335
  type SectionProps = {
354
- title?: string;
355
- supportText?: string;
356
- showSupportText?: boolean;
357
- slot?: React.ReactNode;
336
+ title?: string
337
+ supportText?: string
338
+ showSupportText?: boolean
339
+ slot?: React.ReactNode
358
340
  /** Layout direction of the slot's children. Defaults to 'row' (horizontal). */
359
- slotDirection?: 'row' | 'column';
360
- modes?: Modes;
361
- onPress?: () => void;
362
- style?: StyleProp<ViewStyle>;
363
- accessibilityLabel?: string;
364
- accessibilityHint?: string;
341
+ slotDirection?: 'row' | 'column'
342
+ modes?: Modes
343
+ onPress?: () => void
344
+ style?: StyleProp<ViewStyle>
345
+ accessibilityLabel?: string
346
+ accessibilityHint?: string
365
347
  /**
366
348
  * Web-specific accessibility props (only used on web platform)
367
349
  */
368
- webAccessibilityProps?: WebAccessibilityProps;
350
+ webAccessibilityProps?: WebAccessibilityProps
369
351
  /**
370
352
  * When `true`, disables text truncation: the trailing ellipsis (`…`) is never
371
353
  * shown and any `numberOfLines` clamp is ignored, so the text wraps to as many
372
354
  * lines as it needs even when horizontal space is tight.
373
355
  */
374
- disableTruncation?: boolean;
375
- } & React.ComponentProps<typeof View>;
356
+ disableTruncation?: boolean
357
+ } & React.ComponentProps<typeof View>
376
358
 
377
359
  /**
378
360
  * Section component that mirrors the Figma "Section" component.
@@ -399,18 +381,18 @@ type SectionProps = {
399
381
  * @param {string} [props.accessibilityHint] - Additional accessibility hint for screen readers
400
382
  */
401
383
  interface SectionTokens {
402
- containerStyle: ViewStyle;
403
- headerStyle: ViewStyle;
404
- titleStyle: ViewStyle;
405
- supportTextStyle: ViewStyle;
406
- sectionGap: number;
407
- slotGap: number;
384
+ containerStyle: ViewStyle
385
+ headerStyle: ViewStyle
386
+ titleStyle: ViewStyle
387
+ supportTextStyle: ViewStyle
388
+ sectionGap: number
389
+ slotGap: number
408
390
  }
409
391
 
410
392
  function resolveSectionTokens(modes: Modes): SectionTokens {
411
393
  const backgroundColor = getVariableByName('section/background/color', modes)
412
- const sectionGap = (getVariableByName('section/gap', modes)) as number
413
- const slotGap = (getVariableByName('slot/gap', modes)) as number
394
+ const sectionGap = getVariableByName('section/gap', modes) as number
395
+ const slotGap = getVariableByName('slot/gap', modes) as number
414
396
  const paddingHorizontal = getVariableByName('section/padding/horizontal', modes)
415
397
  const paddingVertical = getVariableByName('section/padding/vertical', modes)
416
398
  const radius = getVariableByName('section/radius', modes)
@@ -424,10 +406,7 @@ function resolveSectionTokens(modes: Modes): SectionTokens {
424
406
  const titleLineHeight = getVariableByName('section/title/lineHeight', modes)
425
407
  const titleFontFamily = getVariableByName('section/title/fontFamily', modes)
426
408
  const titleFontWeightRaw = getVariableByName('section/title/fontWeight', modes)
427
- const titleFontWeight =
428
- typeof titleFontWeightRaw === 'number'
429
- ? titleFontWeightRaw.toString()
430
- : titleFontWeightRaw
409
+ const titleFontWeight = typeof titleFontWeightRaw === 'number' ? titleFontWeightRaw.toString() : titleFontWeightRaw
431
410
 
432
411
  const supportTextColor = getVariableByName('section/supportText/color', modes)
433
412
  const supportTextFontSize = getVariableByName('section/supportText/fontSize', modes)
@@ -435,9 +414,7 @@ function resolveSectionTokens(modes: Modes): SectionTokens {
435
414
  const supportTextFontFamily = getVariableByName('section/supportText/fontFamily', modes)
436
415
  const supportTextFontWeightRaw = getVariableByName('section/supportText/fontWeight', modes)
437
416
  const supportTextFontWeight =
438
- typeof supportTextFontWeightRaw === 'number'
439
- ? supportTextFontWeightRaw.toString()
440
- : supportTextFontWeightRaw
417
+ typeof supportTextFontWeightRaw === 'number' ? supportTextFontWeightRaw.toString() : supportTextFontWeightRaw
441
418
 
442
419
  return {
443
420
  containerStyle: {
@@ -540,9 +517,7 @@ function Section({
540
517
  >
541
518
  {title}
542
519
  </Text>
543
- {onPress && (
544
- <NavArrow direction="Forward" modes={modes} />
545
- )}
520
+ {onPress && <NavArrow direction="Forward" modes={modes} />}
546
521
  </View>
547
522
  {showSupportText && (
548
523
  <Text
@@ -592,13 +567,10 @@ function Section({
592
567
  isHeaderHovered ? headerHoverStyle : null,
593
568
  isHeaderFocused ? headerFocusStyle : null,
594
569
  ],
595
- [tokens.headerStyle, isHeaderHovered, isHeaderFocused]
570
+ [tokens.headerStyle, isHeaderHovered, isHeaderFocused],
596
571
  )
597
572
 
598
- const containerStyleArray = useMemo(
599
- () => [tokens.containerStyle, style],
600
- [tokens.containerStyle, style]
601
- )
573
+ const containerStyleArray = useMemo(() => [tokens.containerStyle, style], [tokens.containerStyle, style])
602
574
 
603
575
  return (
604
576
  <View
@@ -627,21 +599,27 @@ function Section({
627
599
  {headerContent}
628
600
  </Pressable>
629
601
  ) : (
630
- <View style={tokens.headerStyle}>
631
- {headerContent}
632
- </View>
602
+ <View style={tokens.headerStyle}>{headerContent}</View>
603
+ )}
604
+ {slot && (
605
+ <SectionSlot
606
+ slot={slot}
607
+ modes={modes}
608
+ direction={slotDirection}
609
+ rowGap={tokens.sectionGap}
610
+ columnGap={tokens.slotGap}
611
+ />
633
612
  )}
634
- {slot && <SectionSlot slot={slot} modes={modes} direction={slotDirection} rowGap={tokens.sectionGap} columnGap={tokens.slotGap} />}
635
613
  </View>
636
614
  )
637
615
  }
638
616
 
639
617
  type SectionSlotProps = {
640
- slot: React.ReactNode;
641
- modes: Modes;
642
- direction: 'row' | 'column';
643
- rowGap: number;
644
- columnGap: number;
618
+ slot: React.ReactNode
619
+ modes: Modes
620
+ direction: 'row' | 'column'
621
+ rowGap: number
622
+ columnGap: number
645
623
  }
646
624
 
647
625
  /**
@@ -651,15 +629,9 @@ type SectionSlotProps = {
651
629
  * without re-walking the slot tree via `cloneChildrenWithModes`.
652
630
  */
653
631
  function SectionSlot({ slot, modes, direction, rowGap, columnGap }: SectionSlotProps) {
654
- const processed = useMemo(
655
- () => cloneChildrenWithModes(flattenChildren(slot), modes),
656
- [slot, modes]
657
- )
632
+ const processed = useMemo(() => cloneChildrenWithModes(flattenChildren(slot), modes), [slot, modes])
658
633
 
659
- const columnContainerStyle = useMemo<ViewStyle>(
660
- () => ({ flexDirection: 'column', gap: columnGap }),
661
- [columnGap]
662
- )
634
+ const columnContainerStyle = useMemo<ViewStyle>(() => ({ flexDirection: 'column', gap: columnGap }), [columnGap])
663
635
 
664
636
  if (direction === 'row') {
665
637
  return <SlotGrid items={processed} gap={rowGap} />
@@ -668,21 +640,22 @@ function SectionSlot({ slot, modes, direction, rowGap, columnGap }: SectionSlotP
668
640
  }
669
641
 
670
642
  type BentoToggleRenderState = {
671
- expanded: boolean;
672
- toggle: () => void;
643
+ expanded: boolean
644
+ toggle: () => void
673
645
  }
674
646
 
675
647
  type SectionBentoProps = {
676
- navSlot?: React.ReactNode;
677
- upiSlot?: React.ReactNode;
678
- modes?: Modes;
679
- style?: StyleProp<ViewStyle>;
680
- accessibilityLabel?: string;
681
- accessibilityHint?: string;
648
+ navSlot?: React.ReactNode
649
+ upiSlot?: React.ReactNode
650
+ upi?: boolean
651
+ modes?: Modes
652
+ style?: StyleProp<ViewStyle>
653
+ accessibilityLabel?: string
654
+ accessibilityHint?: string
682
655
  /**
683
656
  * Web-specific accessibility props (only used on web platform)
684
657
  */
685
- webAccessibilityProps?: WebAccessibilityProps;
658
+ webAccessibilityProps?: WebAccessibilityProps
686
659
  /**
687
660
  * Total cell count visible when collapsed (real items + the toggle cell).
688
661
  * Defaults to {@link SLOT_GRID_MAX_COLUMNS} (4) so the collapsed state fills
@@ -690,37 +663,37 @@ type SectionBentoProps = {
690
663
  * disabled (no toggle injected, no animation wrappers — identical to the
691
664
  * legacy behavior for back-compat).
692
665
  */
693
- collapsedCount?: number;
666
+ collapsedCount?: number
694
667
  /**
695
668
  * Uncontrolled initial expanded state. Ignored when `expanded` is provided.
696
669
  * Defaults to `false`.
697
670
  */
698
- defaultExpanded?: boolean;
671
+ defaultExpanded?: boolean
699
672
  /**
700
673
  * Controlled expanded state. When provided, `onExpandedChange` should also
701
674
  * be provided so the component can request changes.
702
675
  */
703
- expanded?: boolean;
676
+ expanded?: boolean
704
677
  /**
705
678
  * Called when the user taps the toggle. Required in controlled mode; ignored
706
679
  * in uncontrolled mode unless you want to observe the change.
707
680
  */
708
- onExpandedChange?: (next: boolean) => void;
681
+ onExpandedChange?: (next: boolean) => void
709
682
  /** Label shown on the toggle cell when collapsed. Default `'More'`. */
710
- toggleMoreLabel?: string;
683
+ toggleMoreLabel?: string
711
684
  /** Label shown on the toggle cell when expanded. Default `'Less'`. */
712
- toggleLessLabel?: string;
685
+ toggleLessLabel?: string
713
686
  /** Icon name shown on the toggle when collapsed. Default `'ic_chevron_down'`. */
714
- toggleMoreIcon?: string;
687
+ toggleMoreIcon?: string
715
688
  /** Icon name shown on the toggle when expanded. Default `'ic_chevron_up'`. */
716
- toggleLessIcon?: string;
689
+ toggleLessIcon?: string
717
690
  /**
718
691
  * Escape hatch: render a custom toggle cell instead of the default ListItem.
719
692
  * The provided node is rendered in the toggle's grid slot. Wire `toggle()` to
720
693
  * any tap interaction inside it. Height + per-cell animations still apply.
721
694
  */
722
- renderToggle?: (state: BentoToggleRenderState) => React.ReactNode;
723
- } & React.ComponentProps<typeof View>;
695
+ renderToggle?: (state: BentoToggleRenderState) => React.ReactNode
696
+ } & React.ComponentProps<typeof View>
724
697
 
725
698
  /**
726
699
  * Section.Bento component that mirrors the Figma "Section.Bento" component.
@@ -739,6 +712,7 @@ type SectionBentoProps = {
739
712
  * @param {Object} props
740
713
  * @param {React.ReactNode} [props.navSlot] - Optional custom slot for navigation items (Figma Slot "Nav wrap")
741
714
  * @param {React.ReactNode} [props.upiSlot] - Optional custom slot for UPI handles (Figma Slot "UPI wrap")
715
+ * @param {boolean} [props.upi=true] - Toggles the UPI wrap (Figma boolean property "upi")
742
716
  * @param {Object} [props.modes={}] - Modes object passed to `getVariableByName` for all design tokens
743
717
  * @param {Object} [props.style] - Optional container style overrides
744
718
  * @param {string} [props.accessibilityLabel] - Accessibility label for the section
@@ -749,6 +723,7 @@ const sectionBentoUpiRowStyle: ViewStyle = { flexDirection: 'row', gap: 8 }
749
723
  function SectionBento({
750
724
  navSlot,
751
725
  upiSlot,
726
+ upi = true,
752
727
  modes = EMPTY_MODES,
753
728
  style,
754
729
  // Same rationale as Section: accepted on the type but unused internally.
@@ -779,17 +754,17 @@ function SectionBento({
779
754
  borderRadius: radius,
780
755
  gap,
781
756
  }),
782
- [backgroundColor, paddingHorizontal, paddingVertical, radius, gap]
757
+ [backgroundColor, paddingHorizontal, paddingVertical, radius, gap],
783
758
  )
784
759
 
785
760
  const processedNavSlot = useMemo(
786
761
  () => (navSlot ? cloneChildrenWithModes(flattenChildren(navSlot), modes) : null),
787
- [navSlot, modes]
762
+ [navSlot, modes],
788
763
  )
789
764
 
790
765
  const processedUpiSlot = useMemo(
791
766
  () => (upiSlot ? cloneChildrenWithModes(flattenChildren(upiSlot), modes) : null),
792
- [upiSlot, modes]
767
+ [upiSlot, modes],
793
768
  )
794
769
 
795
770
  // `canExpand` is true iff there are strictly more real items than fit into
@@ -823,24 +798,22 @@ function SectionBento({
823
798
  return allRealItems
824
799
  }
825
800
  // Leave the last collapsed slot for the toggle cell.
826
- const visibleRealItems = expanded
827
- ? allRealItems
828
- : allRealItems.slice(0, collapsedCount - 1)
829
-
830
- const toggleNode = renderToggle
831
- ? renderToggle({ expanded, toggle })
832
- : (
833
- <DefaultBentoToggle
834
- expanded={expanded}
835
- onPress={toggle}
836
- modes={modes}
837
- moreLabel={toggleMoreLabel}
838
- lessLabel={toggleLessLabel}
839
- moreIcon={toggleMoreIcon}
840
- lessIcon={toggleLessIcon}
841
- extraCount={allRealItems.length - (collapsedCount - 1)}
842
- />
843
- )
801
+ const visibleRealItems = expanded ? allRealItems : allRealItems.slice(0, collapsedCount - 1)
802
+
803
+ const toggleNode = renderToggle ? (
804
+ renderToggle({ expanded, toggle })
805
+ ) : (
806
+ <DefaultBentoToggle
807
+ expanded={expanded}
808
+ onPress={toggle}
809
+ modes={modes}
810
+ moreLabel={toggleMoreLabel}
811
+ lessLabel={toggleLessLabel}
812
+ moreIcon={toggleMoreIcon}
813
+ lessIcon={toggleLessIcon}
814
+ extraCount={allRealItems.length - (collapsedCount - 1)}
815
+ />
816
+ )
844
817
 
845
818
  return [...visibleRealItems, toggleNode]
846
819
  }, [
@@ -877,11 +850,7 @@ function SectionBento({
877
850
  : null)}
878
851
  />
879
852
  )}
880
- {processedUpiSlot && (
881
- <View style={sectionBentoUpiRowStyle}>
882
- {processedUpiSlot}
883
- </View>
884
- )}
853
+ {upi && processedUpiSlot && <View style={sectionBentoUpiRowStyle}>{processedUpiSlot}</View>}
885
854
  </View>
886
855
  )
887
856
  }
@@ -897,15 +866,15 @@ function SectionBento({
897
866
  // shared-value-driven rotation would lose its anchor across toggles.
898
867
  // ---------------------------------------------------------------------------
899
868
  type DefaultBentoToggleProps = {
900
- expanded: boolean;
901
- onPress: () => void;
902
- modes: Modes;
903
- moreLabel: string;
904
- lessLabel: string;
905
- moreIcon: string;
906
- lessIcon: string;
869
+ expanded: boolean
870
+ onPress: () => void
871
+ modes: Modes
872
+ moreLabel: string
873
+ lessLabel: string
874
+ moreIcon: string
875
+ lessIcon: string
907
876
  /** How many additional actions become visible when expanding. Used in the a11y hint. */
908
- extraCount: number;
877
+ extraCount: number
909
878
  }
910
879
 
911
880
  function DefaultBentoToggle({
@@ -921,10 +890,7 @@ function DefaultBentoToggle({
921
890
  const label = expanded ? lessLabel : moreLabel
922
891
  const iconName = expanded ? lessIcon : moreIcon
923
892
  const accessibilityState = useMemo(() => ({ expanded }), [expanded])
924
- const webAccessibilityProps = useMemo(
925
- () => ({ ariaExpanded: expanded }),
926
- [expanded]
927
- )
893
+ const webAccessibilityProps = useMemo(() => ({ ariaExpanded: expanded }), [expanded])
928
894
  const accessibilityHint = expanded
929
895
  ? `Hides ${extraCount} additional ${extraCount === 1 ? 'action' : 'actions'}`
930
896
  : `Shows ${extraCount} additional ${extraCount === 1 ? 'action' : 'actions'}`
@@ -948,4 +914,3 @@ function DefaultBentoToggle({
948
914
  Section.Bento = SectionBento
949
915
 
950
916
  export default Section
951
-
@@ -63,7 +63,7 @@ export const FIGMA_MODES = {
63
63
  "Calendar Glyph / Output": ["Default"],
64
64
  "Calendar Glyph State": ["Idle", "notSaved", "saved"],
65
65
  "Card / Output": ["Default"],
66
- "Card Apperance": ["Default", "Plain"],
66
+ "Card Container": ["Default", "Plain"],
67
67
  "Card Feedback / Output": ["Default"],
68
68
  "Card Tab / output": ["Default"],
69
69
  "Card Tab State": ["Default", "Active"],
@@ -248,6 +248,7 @@ export const FIGMA_MODES = {
248
248
  "Slot gap": ["S", "M", "L", "XL", "XS"],
249
249
  "special button": ["Default"],
250
250
  "Spinner / Output": ["Default"],
251
+ "Stack Context": ["Root", "Nested"],
251
252
  "statGroup / Output": ["Default"],
252
253
  "StatItem / Output": ["Default"],
253
254
  "StatItem Label Position ": ["Top", "Bottom"],
@@ -304,7 +305,7 @@ export const FIGMA_COMPONENT_MODES: Record<string, readonly string[]> = {
304
305
  "Accordion": ["Accordion States"],
305
306
  "AccordionCheckbox": ["Color Mode", "context 10", "Profile Card Appearance"],
306
307
  "AccountCard": ["AppearanceBrand", "Button / Size", "Button / State", "Color Mode", "Emphasis", "Page type"],
307
- "ActionFooter": ["Color Mode", "context5"],
308
+ "ActionFooter": ["Color Mode", "Context", "context5", "Slot gap"],
308
309
  "ActionTile": ["AppearanceBrand", "AppearanceSystem", "Color Mode", "Context", "Emphasis", "Icon Capsule Size", "Page type", "Semantic Intent"],
309
310
  "Additem": ["AppearanceBrand", "AppearanceSystem", "Color Mode", "Context", "Emphasis", "Icon Capsule Size", "Page type", "Semantic Intent"],
310
311
  "AllocationComparisonChart": ["Appearance / DataViz", "Color Mode", "Emphasis / DataViz"],
@@ -322,7 +323,7 @@ export const FIGMA_COMPONENT_MODES: Record<string, readonly string[]> = {
322
323
  "BrandChip": ["Avatar Size", "Badge Size", "Color Mode", "context 10", "Context4", "Profile Card Appearance"],
323
324
  "BubbleChart": ["Appearance / DataViz", "Color Mode", "Context", "context 10", "Emphasis / DataViz", "Profile Card Appearance", "Text Appearance"],
324
325
  "Button": ["AppearanceBrand", "AppearanceSystem", "Button / Size", "Button / State", "Color Mode", "Context", "context 10", "Emphasis", "Page type", "Profile Card Appearance", "Semantic Intent"],
325
- "Card": ["AppearanceBrand", "AppearanceSystem", "Border Boolean", "Card Apperance", "Color Mode", "Gap", "Page type", "Semantic Intent"],
326
+ "Card": ["AppearanceBrand", "AppearanceSystem", "Card Container", "Color Mode", "Gap", "Page type", "Semantic Intent"],
326
327
  "CardAdvisory": ["AppearanceBrand", "AppearanceSystem", "Button / Size", "Button / State", "circularProgressBar Size", "Color Mode", "Context", "context 10", "Emphasis", "Nudge padding", "Page type", "Profile Card Appearance", "Semantic Intent", "Slot gap"],
327
328
  "CardBankAccount": ["AppearanceBrand", "AppearanceSystem", "Avatar Size", "Badge Size", "Button / Size", "Button / State", "Color Mode", "Context", "context 10", "Context4", "context5", "Emphasis", "List Item Style", "Page type", "Profile Card Appearance", "Semantic Intent", "Text Appearance", "Text Sizes", "Weight"],
328
329
  "CardCTA": ["AppearanceBrand", "AppearanceSystem", "Avatar Size", "Badge Size", "Button / Size", "Button / State", "Color Mode", "Context", "context 10", "context 8", "Context4", "Emphasis", "Icon Capsule Size", "MediaBlock", "Page type", "Profile Card Appearance", "Semantic Intent"],
@@ -341,7 +342,7 @@ export const FIGMA_COMPONENT_MODES: Record<string, readonly string[]> = {
341
342
  "CircularProgressBar": ["AppearanceBrand", "AppearanceSystem", "circularProgressBar Size", "Color Mode", "Emphasis", "Semantic Intent"],
342
343
  "CircularRating": ["AppearanceBrand", "AppearanceSystem", "Button / Size", "Button / State", "Color Mode", "Context", "context 10", "Emphasis", "Nudge padding", "Page type", "Profile Card Appearance", "Semantic Intent", "Slot gap"],
343
344
  "ClusterBubble": ["Appearance / DataViz", "Color Mode", "Context", "context 10", "Emphasis / DataViz", "Profile Card Appearance", "Text Appearance"],
344
- "CompareTable": ["Accordion States", "AppearanceBrand", "Button / Size", "Button / State", "Color Mode", "Emphasis", "Page type", "Radius", "Selection Card Radius"],
345
+ "CompareTable": ["Accordion States", "AppearanceBrand", "Button / Size", "Button / State", "Color Mode", "Emphasis", "Page type", "Radius"],
345
346
  "ComparisonBar": ["AppearanceBrand", "AppearanceSystem", "Button / Size", "Button / State", "Color Mode", "Context", "context 10", "Emphasis", "Icon Capsule Size", "Page type", "Profile Card Appearance", "Radius", "Semantic Intent"],
346
347
  "ContentSheet": ["Color Mode", "Page type"],
347
348
  "CoverageBarComparison": ["Appearance / DataViz", "Color Mode", "Emphasis / DataViz"],
@@ -366,7 +367,7 @@ export const FIGMA_COMPONENT_MODES: Record<string, readonly string[]> = {
366
367
  "HelloJioInput": ["AppearanceBrand", "Button / Size", "Button / State", "Color Mode", "Emphasis", "Hello Jio Input Size", "Hello Jio Input State", "Page type"],
367
368
  "HeroSection": ["AppearanceBrand", "Button / Size", "Button / State", "Color Mode", "context 9", "context7", "Emphasis", "FormField States", "InputState", "Page type", "Status"],
368
369
  "HoldingsCard": ["AppearanceBrand", "Color Mode"],
369
- "HStack": ["Context", "Padding", "Page type", "Slot gap"],
370
+ "HStack": ["Context", "Padding", "Page type", "Slot gap", "Stack Context"],
370
371
  "Icon": ["AppearanceBrand", "AppearanceSystem", "Badge Size", "Color Mode", "context 10", "Context4", "Emphasis", "Page type", "Profile Card Appearance", "Semantic Intent"],
371
372
  "IconButton": ["AppearanceBrand", "Button / Size", "Button / State", "Color Mode", "Emphasis", "Page type"],
372
373
  "IconCapsule": ["AppearanceBrand", "AppearanceSystem", "Color Mode", "Context", "Emphasis", "Icon Capsule Size", "Page type", "Semantic Intent"],
@@ -393,7 +394,7 @@ export const FIGMA_COMPONENT_MODES: Record<string, readonly string[]> = {
393
394
  "PaymentFeedback": ["AppearanceBrand", "AppearanceSystem", "Color Mode", "Context", "Emphasis", "Icon Capsule Size", "Page type", "Semantic Intent"],
394
395
  "PdpCcCard": ["AppearanceBrand", "AppearanceSystem", "Button / Size", "Button / State", "Color Mode", "Context", "context 10", "context7", "Emphasis", "Page type", "Profile Card Appearance", "Radius", "Semantic Intent"],
395
396
  "PlanComparisonCard": ["Color Mode"],
396
- "Popup": ["Color Mode", "Context", "Padding", "Page type", "Slot gap"],
397
+ "Popup": ["Color Mode", "Context", "Padding", "Page type", "Slot gap", "Stack Context"],
397
398
  "PortfolioHero": ["Avatar Size", "Badge Size", "Color Mode", "context 10", "Context3", "Context4", "Profile Card Appearance"],
398
399
  "ProductLabel": ["Avatar Size", "Badge Size", "Color Mode", "context 10", "Context4", "Profile Card Appearance"],
399
400
  "ProductMerchandisingCard": ["AppearanceBrand", "AppearanceSystem", "Avatar Size", "Badge Size", "Button / Size", "Button / State", "Color Mode", "Context", "context 10", "Context4", "Emphasis", "Page type", "Profile Card Appearance", "Semantic Intent"],
@@ -434,7 +435,7 @@ export const FIGMA_COMPONENT_MODES: Record<string, readonly string[]> = {
434
435
  "TransactionStatus": ["Transaction Status"],
435
436
  "UpiHandle": ["Color Mode", "context 10", "Profile Card Appearance", "UPI Handle Image"],
436
437
  "ValueBackMetric": ["AppearanceBrand", "AppearanceSystem", "Badge Size", "Color Mode", "Context", "context 10", "Context4", "Emphasis", "Page type", "Profile Card Appearance", "Semantic Intent", "Text Appearance", "Text Sizes", "Weight"],
437
- "VStack": ["Context", "Padding", "Page type", "Slot gap"],
438
+ "VStack": ["Context", "Padding", "Page type", "Slot gap", "Stack Context"],
438
439
  };
439
440
 
440
441
  /**