jfs-components 0.0.55 → 0.0.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.
Files changed (48) hide show
  1. package/lib/commonjs/components/Accordion/Accordion.js +2 -34
  2. package/lib/commonjs/components/AppBar/AppBar.js +4 -36
  3. package/lib/commonjs/components/FilterBar/FilterBar.js +2 -34
  4. package/lib/commonjs/components/LazyList/LazyList.js +2 -34
  5. package/lib/commonjs/components/MoneyValue/MoneyValue.js +1 -1
  6. package/lib/commonjs/components/NavArrow/NavArrow.js +45 -44
  7. package/lib/commonjs/components/Numpad/Numpad.js +6 -5
  8. package/lib/commonjs/components/Section/Section.js +7 -8
  9. package/lib/commonjs/components/TextInput/TextInput.js +4 -38
  10. package/lib/commonjs/components/TransactionBubble/TransactionBubble.js +149 -0
  11. package/lib/commonjs/components/index.js +7 -0
  12. package/lib/commonjs/design-tokens/JFSThemeProvider.js +38 -3
  13. package/lib/commonjs/icons/registry.js +1 -1
  14. package/lib/commonjs/utils/react-utils.js +18 -13
  15. package/lib/module/components/Accordion/Accordion.js +1 -33
  16. package/lib/module/components/AppBar/AppBar.js +1 -34
  17. package/lib/module/components/FilterBar/FilterBar.js +1 -35
  18. package/lib/module/components/LazyList/LazyList.js +1 -35
  19. package/lib/module/components/MoneyValue/MoneyValue.js +1 -1
  20. package/lib/module/components/NavArrow/NavArrow.js +44 -44
  21. package/lib/module/components/Numpad/Numpad.js +5 -5
  22. package/lib/module/components/Section/Section.js +8 -9
  23. package/lib/module/components/TextInput/TextInput.js +2 -36
  24. package/lib/module/components/TransactionBubble/TransactionBubble.js +144 -0
  25. package/lib/module/components/index.js +1 -0
  26. package/lib/module/design-tokens/JFSThemeProvider.js +35 -3
  27. package/lib/module/icons/registry.js +1 -1
  28. package/lib/module/utils/react-utils.js +18 -13
  29. package/lib/typescript/src/components/NavArrow/NavArrow.d.ts +6 -11
  30. package/lib/typescript/src/components/TransactionBubble/TransactionBubble.d.ts +39 -0
  31. package/lib/typescript/src/components/index.d.ts +1 -0
  32. package/lib/typescript/src/design-tokens/JFSThemeProvider.d.ts +15 -0
  33. package/lib/typescript/src/icons/registry.d.ts +1 -1
  34. package/package.json +1 -1
  35. package/src/components/Accordion/Accordion.tsx +1 -44
  36. package/src/components/AppBar/AppBar.tsx +1 -44
  37. package/src/components/FilterBar/FilterBar.tsx +1 -44
  38. package/src/components/LazyList/LazyList.tsx +1 -41
  39. package/src/components/MoneyValue/MoneyValue.tsx +1 -1
  40. package/src/components/NavArrow/NavArrow.tsx +46 -43
  41. package/src/components/Numpad/Numpad.tsx +5 -5
  42. package/src/components/Section/Section.tsx +8 -8
  43. package/src/components/TextInput/TextInput.tsx +1 -44
  44. package/src/components/TransactionBubble/TransactionBubble.tsx +155 -0
  45. package/src/components/index.ts +1 -0
  46. package/src/design-tokens/JFSThemeProvider.tsx +37 -2
  47. package/src/icons/registry.ts +1 -1
  48. package/src/utils/react-utils.ts +29 -21
@@ -7,17 +7,25 @@ import React from 'react';
7
7
  * This ensures that all child components in slots receive the modes prop from the parent.
8
8
  */
9
9
  export function cloneChildrenWithModes(children, modes, forcedModes) {
10
- return React.Children.map(children, child => {
10
+ const result = [];
11
+ React.Children.forEach(children, child => {
11
12
  if (! /*#__PURE__*/React.isValidElement(child)) {
12
- return child;
13
+ if (child !== null && child !== undefined) {
14
+ result.push(child);
15
+ }
16
+ return;
13
17
  }
14
18
 
15
- // Get existing children
19
+ // Unwrap Fragments: Fragments can't accept arbitrary props like `modes`,
20
+ // so recurse into their children and process each one individually.
21
+ if (child.type === React.Fragment) {
22
+ const fragment = child;
23
+ result.push(...cloneChildrenWithModes(fragment.props.children, modes, forcedModes));
24
+ return;
25
+ }
16
26
  const childChildren = child.props?.children;
17
27
  const hasChildren = childChildren !== undefined && childChildren !== null;
18
28
 
19
- // Clone the child with modes prop if it doesn't already have one
20
- // or merge with existing modes if it does
21
29
  // Merge order: parent modes first, then child's explicit modes override them,
22
30
  // then forcedModes (if provided) are applied last and can never be overridden
23
31
  const existingModes = child.props?.modes;
@@ -29,16 +37,13 @@ export function cloneChildrenWithModes(children, modes, forcedModes) {
29
37
  ...modes,
30
38
  ...existingModes
31
39
  } : modes;
32
-
33
- // Recursively process children if they exist
34
- const processedChildren = hasChildren ? cloneChildrenWithModes(React.Children.toArray(childChildren), modes, forcedModes) : undefined;
35
-
36
- // Clone element with modes and processed children
37
- return /*#__PURE__*/React.cloneElement(child, {
40
+ const processedChildren = hasChildren ? cloneChildrenWithModes(childChildren, modes, forcedModes) : undefined;
41
+ result.push(/*#__PURE__*/React.cloneElement(child, {
38
42
  ...child.props,
39
43
  modes: mergedModes
40
- }, processedChildren);
41
- })?.filter(child => child !== null && child !== undefined) ?? [];
44
+ }, processedChildren));
45
+ });
46
+ return result;
42
47
  }
43
48
 
44
49
  /**
@@ -12,23 +12,18 @@ type NavArrowProps = {
12
12
  accessibilityLabel?: string;
13
13
  } & Omit<React.ComponentProps<typeof View>, 'style' | 'accessibilityLabel'>;
14
14
  /**
15
- * NavArrow component that displays a small chevron arrow for navigation.
15
+ * NavArrow component that displays a chevron arrow for navigation.
16
16
  *
17
- * This component uses design tokens for all visual properties:
17
+ * Renders a stroked SVG chevron whose dimensions and thickness are
18
+ * fully driven by design tokens:
18
19
  * - navArrow/icon/color - chevron stroke color
19
- * - navArrow/icon/width - icon width
20
- * - navArrow/icon/height - icon height
21
- * - navArrow/icon/strokeWeight - stroke width
20
+ * - navArrow/icon/width - chevron arm width (horizontal spread)
21
+ * - navArrow/icon/height - chevron arm height (vertical spread)
22
+ * - navArrow/icon/strokeWeight - stroke thickness
22
23
  * - navArrow/width - container width
23
24
  * - navArrow/height - container height
24
25
  * - navArrow/radius - border radius
25
26
  * - navArrow/background - background color
26
- *
27
- * @component
28
- * @param {Object} props
29
- * @param {'Back'|'Forward'|'Down'} [props.direction='Back'] - Arrow direction
30
- * @param {Object} [props.modes={}] - Modes for design token resolution
31
- * @param {Object} [props.style] - Additional container styles
32
27
  */
33
28
  export default function NavArrow({ direction, modes, style, accessibilityLabel, ...rest }: NavArrowProps): import("react/jsx-runtime").JSX.Element;
34
29
  export {};
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+ import { type ViewStyle, type PressableProps } from 'react-native';
3
+ import { type WebAccessibilityProps } from '../../utils/web-platform-utils';
4
+ export type TransactionBubbleProps = {
5
+ description?: string;
6
+ value?: string | number;
7
+ currency?: string;
8
+ status?: string;
9
+ date?: string;
10
+ /** Slot for the status area. When provided, replaces the default TransactionStatus + NavArrow. */
11
+ statusSlot?: React.ReactNode;
12
+ children?: React.ReactNode;
13
+ modes?: Record<string, any>;
14
+ onPress?: () => void;
15
+ style?: ViewStyle;
16
+ accessibilityLabel?: string;
17
+ accessibilityHint?: string;
18
+ webAccessibilityProps?: WebAccessibilityProps;
19
+ } & Omit<PressableProps, 'style' | 'children' | 'onPress'>;
20
+ /**
21
+ * TransactionBubble — Figma node 1517:1155.
22
+ *
23
+ * Layout (vertical stack inside a rounded bordered pill):
24
+ *
25
+ * ┌──────────────────────────────────────────────┐
26
+ * │ Description │
27
+ * │ ₹56 │
28
+ * │ [slot / children content] │
29
+ * │ ⚠ Expired · 20 Mar 2025 › │
30
+ * └──────────────────────────────────────────────┘
31
+ *
32
+ * moneyValueWrap: description + MoneyValue, vertical with `transactionBubble/wrap/gap`.
33
+ * slotWrap: children (optional), rendered between moneyValueWrap and statusWrap.
34
+ * statusWrap: TransactionStatus + NavArrow, horizontal row with `transactionBubble/statusWrap/gap`.
35
+ * Container gap between sections: `transactionBubble/gap`.
36
+ */
37
+ declare function TransactionBubble({ description, value, currency, status, date, statusSlot, children, modes, onPress, style, accessibilityLabel, accessibilityHint, webAccessibilityProps, ...rest }: TransactionBubbleProps): import("react/jsx-runtime").JSX.Element;
38
+ export default TransactionBubble;
39
+ //# sourceMappingURL=TransactionBubble.d.ts.map
@@ -47,6 +47,7 @@ export { default as ThreadHero, type ThreadHeroProps } from './ThreadHero/Thread
47
47
  export { Tooltip } from './Tooltip/Tooltip';
48
48
  export { default as TransactionDetails } from './TransactionDetails/TransactionDetails';
49
49
  export { default as TransactionStatus } from './TransactionStatus/TransactionStatus';
50
+ export { default as TransactionBubble, type TransactionBubbleProps } from './TransactionBubble/TransactionBubble';
50
51
  export { default as UpiHandle } from './UpiHandle/UpiHandle';
51
52
  export { default as VStack, type VStackProps } from './VStack/VStack';
52
53
  export { default as ChipGroup, type ChipGroupProps } from './ChipGroup/ChipGroup';
@@ -40,5 +40,20 @@ export declare const JFSThemeProvider: React.FC<JFSThemeProviderProps>;
40
40
  * }
41
41
  */
42
42
  export declare const useTokens: () => TokenContextType;
43
+ /**
44
+ * Returns the JFS font map. The TTF is encapsulated within the package at
45
+ * src/assets/fonts/JioType Var.ttf (included via package.json "files").
46
+ * Call this inside load functions to avoid top-level require errors if font missing.
47
+ */
48
+ export declare const getJFSFonts: () => {
49
+ readonly 'JioType Var': any;
50
+ };
51
+ /**
52
+ * Hook for loading JFS fonts using expo-font. This improves Android font support by explicitly registering
53
+ * the custom 'JioType Var' font (encapsulated in the package) via Font.loadAsync before components render.
54
+ * Without it, Android defaults to Roboto. Call at app root (e.g. before JFSThemeProvider). Returns loaded state.
55
+ * See getJFSFonts() for direct use with Font.loadAsync. Handles missing font gracefully for web/Storybook.
56
+ */
57
+ export declare function useJFSFonts(): boolean;
43
58
  export {};
44
59
  //# sourceMappingURL=JFSThemeProvider.d.ts.map
@@ -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-04-13T20:48:16.865Z
7
+ * Generated: 2026-04-14T14:14:19.990Z
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.0.55",
3
+ "version": "0.0.57",
4
4
  "description": "React Native Jio Finance Components Library",
5
5
  "author": "sunshuaiqi@gmail.com",
6
6
  "license": "MIT",
@@ -14,56 +14,13 @@ import {
14
14
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
15
15
  import Icon from '../../icons/Icon'
16
16
  import { usePressableWebSupport, type WebAccessibilityProps } from '../../utils/web-platform-utils'
17
+ import { cloneChildrenWithModes } from '../../utils/react-utils'
17
18
 
18
19
  // Enable LayoutAnimation on Android
19
20
  if (Platform.OS === 'android' && UIManager.setLayoutAnimationEnabledExperimental) {
20
21
  UIManager.setLayoutAnimationEnabledExperimental(true)
21
22
  }
22
23
 
23
- /**
24
- * Helper function to recursively clone children and pass modes prop to components that accept it.
25
- * This ensures that all child components in slots receive the modes prop from the parent.
26
- */
27
- function cloneChildrenWithModes(
28
- children: React.ReactNode,
29
- modes: Record<string, any>
30
- ): React.ReactNode[] {
31
- const result = React.Children.map(children, (child) => {
32
- if (!React.isValidElement(child)) {
33
- return child
34
- }
35
-
36
- // Get existing children
37
- const childChildren = (child.props as any)?.children
38
- const hasChildren = childChildren !== undefined && childChildren !== null
39
-
40
- // Merge modes: parent modes first, then child's explicit modes override them
41
- const existingModes = (child.props as any)?.modes
42
- const mergedModes = existingModes
43
- ? { ...modes, ...existingModes }
44
- : modes
45
-
46
- // Recursively process children if they exist
47
- const processedChildren: React.ReactNode | undefined = hasChildren
48
- ? cloneChildrenWithModes(
49
- React.Children.toArray(childChildren),
50
- modes
51
- )
52
- : undefined
53
-
54
- // Clone element with modes and processed children
55
- return React.cloneElement(
56
- child,
57
- {
58
- ...(child.props as any),
59
- modes: mergedModes,
60
- },
61
- processedChildren
62
- )
63
- })
64
- return result || []
65
- }
66
-
67
24
  export type AccordionProps = {
68
25
  /** The accordion header title */
69
26
  title?: string;
@@ -3,51 +3,8 @@ import { View, type StyleProp, type ViewStyle, Pressable } from 'react-native'
3
3
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
4
4
  import { useTokens } from '../../design-tokens/JFSThemeProvider'
5
5
 
6
- import Avatar from '../Avatar/Avatar'
7
6
  import NavArrow from '../NavArrow/NavArrow'
8
- // We might need to import Image or Svg if we had the assets locally, but for now we'll use placeholders or standard icons for defaults.
9
- // The user prompt mentioned "Use getVariableByName... strict camelCase".
10
-
11
- /**
12
- * Helper function to recursively clone children and pass modes prop to components that accept it.
13
- */
14
- function cloneChildrenWithModes(
15
- children: React.ReactNode,
16
- modes: Record<string, any>
17
- ): React.ReactNode[] {
18
- return React.Children.map(children, (child) => {
19
- if (!React.isValidElement(child)) {
20
- return child
21
- }
22
-
23
- // Get existing children
24
- const childChildren = (child.props as any)?.children
25
- const hasChildren = childChildren !== undefined && childChildren !== null
26
-
27
- // Clone the child with modes prop if it doesn't already have one
28
- // or merge with existing modes if it does
29
- const existingModes = (child.props as any)?.modes
30
- const mergedModes = existingModes ? { ...modes, ...existingModes } : modes
31
-
32
- // Recursively process children if they exist
33
- const processedChildren: React.ReactNode | undefined = hasChildren
34
- ? cloneChildrenWithModes(
35
- React.Children.toArray(childChildren),
36
- modes
37
- )
38
- : undefined
39
-
40
- // Clone element with modes and processed children
41
- return React.cloneElement(
42
- child,
43
- {
44
- ...(child.props as any),
45
- modes: mergedModes,
46
- },
47
- processedChildren
48
- )
49
- })?.filter((child) => child !== null && child !== undefined) as React.ReactNode[] ?? []
50
- }
7
+ import { cloneChildrenWithModes } from '../../utils/react-utils'
51
8
 
52
9
  type AppBarType = 'MainPage' | 'SubPage'
53
10
 
@@ -2,50 +2,7 @@ import React, { useState } from 'react'
2
2
  import { View, type StyleProp, type ViewStyle } from 'react-native'
3
3
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
4
4
  import TextInput from '../TextInput/TextInput'
5
-
6
- /**
7
- * Helper function to recursively clone children and pass modes prop to components that accept it.
8
- * This ensures that all child components in slots receive the modes prop from the parent.
9
- */
10
- function cloneChildrenWithModes(
11
- children: React.ReactNode,
12
- modes: Record<string, any>
13
- ): React.ReactNode[] {
14
- const result = React.Children.map(children, (child) => {
15
- if (!React.isValidElement(child)) {
16
- return child
17
- }
18
-
19
- // Get existing children
20
- const childChildren = (child.props as any)?.children
21
- const hasChildren = childChildren !== undefined && childChildren !== null
22
-
23
- // Clone the child with modes prop if it doesn't already have one
24
- // or merge with existing modes if it does
25
- // Merge order: parent modes first, then child's explicit modes override them
26
- const existingModes = (child.props as any)?.modes
27
- const mergedModes = existingModes ? { ...modes, ...existingModes } : modes
28
-
29
- // Recursively process children if they exist
30
- const processedChildren: React.ReactNode | undefined = hasChildren
31
- ? cloneChildrenWithModes(
32
- React.Children.toArray(childChildren),
33
- modes
34
- )
35
- : undefined
36
-
37
- // Clone element with modes and processed children
38
- return React.cloneElement(
39
- child,
40
- {
41
- ...(child.props as any),
42
- modes: mergedModes,
43
- },
44
- processedChildren
45
- )
46
- })
47
- return result || []
48
- }
5
+ import { cloneChildrenWithModes } from '../../utils/react-utils'
49
6
 
50
7
  type RenderInputArgs = {
51
8
  placeholder: string;
@@ -1,47 +1,7 @@
1
1
  import React from 'react'
2
2
  import { View, type StyleProp, type ViewStyle } from 'react-native'
3
3
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
4
-
5
- /**
6
- * Helper function to recursively clone children and pass modes prop to components that accept it.
7
- * This ensures that all child components in slots receive the modes prop from the parent.
8
- */
9
- function cloneChildrenWithModes(children: React.ReactNode, modes: Record<string, any>): React.ReactNode {
10
- return React.Children.map(children, (child) => {
11
- if (!React.isValidElement(child)) {
12
- return child
13
- }
14
-
15
- // Get existing children
16
- const childProps = child.props as { children?: React.ReactNode; modes?: Record<string, any>; [key: string]: any }
17
- const childChildren = childProps?.children
18
- const hasChildren = childChildren !== undefined && childChildren !== null
19
-
20
- // Clone the child with modes prop if it doesn't already have one
21
- // or merge with existing modes if it does
22
- // Merge order: parent modes first, then child's explicit modes override them
23
- const existingModes = childProps?.modes
24
- const mergedModes = existingModes ? { ...modes, ...existingModes } : modes
25
-
26
- // Recursively process children if they exist
27
- const processedChildren = hasChildren
28
- ? cloneChildrenWithModes(
29
- React.Children.toArray(childChildren),
30
- modes
31
- )
32
- : undefined
33
-
34
- // Clone element with modes and processed children
35
- return React.cloneElement(
36
- child,
37
- {
38
- ...childProps,
39
- modes: mergedModes,
40
- } as any,
41
- processedChildren
42
- )
43
- })
44
- }
4
+ import { cloneChildrenWithModes } from '../../utils/react-utils'
45
5
 
46
6
  type LazyListProps = {
47
7
  listGroupsSlot?: React.ReactNode;
@@ -127,7 +127,7 @@ function MoneyValue({
127
127
  ? fontWeightValue.toString()
128
128
  : fontWeightValue
129
129
  const fontFamily = getVariableByName('moneyValue/fontFamily', modes) || 'System'
130
- const gap = getVariableByName('moneyValue/gap', modes) || 4
130
+ const gap = getVariableByName('moneyValue/gap', modes) ?? 4
131
131
 
132
132
  // Resolve currency to a symbol, supporting both symbols and ISO codes
133
133
  const resolvedCurrency = useMemo(() => {
@@ -1,7 +1,7 @@
1
1
  import React from 'react'
2
2
  import { View, type ViewStyle } from 'react-native'
3
+ import Svg, { Polyline } from 'react-native-svg'
3
4
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
4
- import Icon from '../../icons/Icon'
5
5
 
6
6
  type NavArrowDirection = 'Back' | 'Forward' | 'Down'
7
7
 
@@ -17,23 +17,18 @@ type NavArrowProps = {
17
17
  } & Omit<React.ComponentProps<typeof View>, 'style' | 'accessibilityLabel'>
18
18
 
19
19
  /**
20
- * NavArrow component that displays a small chevron arrow for navigation.
20
+ * NavArrow component that displays a chevron arrow for navigation.
21
21
  *
22
- * This component uses design tokens for all visual properties:
22
+ * Renders a stroked SVG chevron whose dimensions and thickness are
23
+ * fully driven by design tokens:
23
24
  * - navArrow/icon/color - chevron stroke color
24
- * - navArrow/icon/width - icon width
25
- * - navArrow/icon/height - icon height
26
- * - navArrow/icon/strokeWeight - stroke width
25
+ * - navArrow/icon/width - chevron arm width (horizontal spread)
26
+ * - navArrow/icon/height - chevron arm height (vertical spread)
27
+ * - navArrow/icon/strokeWeight - stroke thickness
27
28
  * - navArrow/width - container width
28
29
  * - navArrow/height - container height
29
30
  * - navArrow/radius - border radius
30
31
  * - navArrow/background - background color
31
- *
32
- * @component
33
- * @param {Object} props
34
- * @param {'Back'|'Forward'|'Down'} [props.direction='Back'] - Arrow direction
35
- * @param {Object} [props.modes={}] - Modes for design token resolution
36
- * @param {Object} [props.style] - Additional container styles
37
32
  */
38
33
  export default function NavArrow({
39
34
  direction = 'Back',
@@ -42,11 +37,9 @@ export default function NavArrow({
42
37
  accessibilityLabel,
43
38
  ...rest
44
39
  }: NavArrowProps) {
45
- // Resolve design tokens
46
40
  const iconColor =
47
41
  (getVariableByName('navArrow/icon/color', modes) as string) || '#24262b'
48
42
 
49
- // Dimensions from tokens
50
43
  const widthToken = Number(getVariableByName('navArrow/width', modes)) || 6
51
44
  const heightToken = Number(getVariableByName('navArrow/height', modes)) || 10
52
45
  const borderRadius =
@@ -54,14 +47,18 @@ export default function NavArrow({
54
47
  const backgroundColor =
55
48
  (getVariableByName('navArrow/background', modes) as string) || 'transparent'
56
49
 
57
- // Swap dimensions if direction is Down
50
+ const iconWidth = Number(getVariableByName('navArrow/icon/width', modes)) || 4
51
+ const iconHeight = Number(getVariableByName('navArrow/icon/height', modes)) || 8
52
+ const strokeWeight =
53
+ Number(getVariableByName('navArrow/icon/strokeWeight', modes)) || 2
54
+
58
55
  const isDown = direction === 'Down'
59
- const width = isDown ? heightToken : widthToken
60
- const height = isDown ? widthToken : heightToken
56
+ const containerWidth = isDown ? heightToken : widthToken
57
+ const containerHeight = isDown ? widthToken : heightToken
61
58
 
62
59
  const containerStyle: ViewStyle = {
63
- width,
64
- height,
60
+ width: containerWidth,
61
+ height: containerHeight,
65
62
  borderRadius,
66
63
  backgroundColor,
67
64
  alignItems: 'center',
@@ -77,38 +74,44 @@ export default function NavArrow({
77
74
  ? 'Go forward'
78
75
  : 'Go down')
79
76
 
80
- // Map direction to icon name
81
- let iconName = 'ic_chevron_left' // Default for Back
82
- if (direction === 'Forward') {
83
- iconName = 'ic_chevron_right'
84
- } else if (direction === 'Down') {
85
- iconName = 'ic_chevron_down'
77
+ const chevronW = isDown ? iconHeight : iconWidth
78
+ const chevronH = isDown ? iconWidth : iconHeight
79
+
80
+ const pad = strokeWeight / 2
81
+ const svgWidth = chevronW + pad * 2
82
+ const svgHeight = chevronH + pad * 2
83
+
84
+ let points: string
85
+ switch (direction) {
86
+ case 'Forward':
87
+ points = `${pad},${pad} ${chevronW + pad},${chevronH / 2 + pad} ${pad},${chevronH + pad}`
88
+ break
89
+ case 'Down':
90
+ points = `${pad},${pad} ${chevronW / 2 + pad},${chevronH + pad} ${chevronW + pad},${pad}`
91
+ break
92
+ case 'Back':
93
+ default:
94
+ points = `${chevronW + pad},${pad} ${pad},${chevronH / 2 + pad} ${chevronW + pad},${chevronH + pad}`
95
+ break
86
96
  }
87
97
 
88
98
  return (
89
99
  <View
90
100
  style={containerStyle}
91
101
  accessibilityRole="image"
92
- accessibilityLabel={undefined}
102
+ accessibilityLabel={defaultAccessibilityLabel}
93
103
  {...rest}
94
104
  >
95
- <Icon
96
- name={iconName}
97
- size={24} // Internal icon size is fixed/clipped by container in design but Icon requires a size
98
- color={iconColor}
99
- style={{
100
- // Center the larger icon within the small container if needed,
101
- // though flex center on container handles this.
102
- // If the container is 6x10 and icon is 24, we might want to ensure it doesn't affect layout
103
- // but Flexbox 'center' centers the content.
104
- // However, if the icon component has its own frame, it might overflow.
105
- // React Native View has overflow: 'hidden' by default if borderRadius is set? No.
106
- // We might want overflow: 'hidden' if strictly following design clip.
107
- // Figma design had "overflow-clip" class.
108
- }}
109
- />
105
+ <Svg width={svgWidth} height={svgHeight} viewBox={`0 0 ${svgWidth} ${svgHeight}`}>
106
+ <Polyline
107
+ points={points}
108
+ stroke={iconColor}
109
+ strokeWidth={strokeWeight}
110
+ strokeLinecap="round"
111
+ strokeLinejoin="round"
112
+ fill="none"
113
+ />
114
+ </Svg>
110
115
  </View>
111
116
  )
112
117
  }
113
-
114
-
@@ -8,7 +8,7 @@ import {
8
8
  type TextStyle,
9
9
  } from 'react-native'
10
10
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
11
- import { IconDeletebackspace } from '../../icons/components/IconDeletebackspace'
11
+ import Icon from '../../icons/Icon'
12
12
 
13
13
  export type NumpadKeyValue =
14
14
  | '0'
@@ -142,10 +142,10 @@ function Numpad({
142
142
  accessibilityLabel={isBackspace ? 'Backspace' : key}
143
143
  >
144
144
  {isBackspace ? (
145
- <IconDeletebackspace
146
- width={fontSize as number}
147
- height={fontSize as number}
148
- fill={foreground as string}
145
+ <Icon
146
+ name="ic_delete_backspace"
147
+ size={fontSize as number}
148
+ color={foreground as string}
149
149
  />
150
150
  ) : (
151
151
  <Text style={[textStyle, keyTextStyle]}>{key}</Text>
@@ -3,7 +3,7 @@ import { View, Text, Pressable, Platform, type StyleProp, type ViewStyle, type P
3
3
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
4
4
  import NavArrow from '../NavArrow/NavArrow'
5
5
  import { usePressableWebSupport, type WebAccessibilityProps } from '../../utils/web-platform-utils'
6
- import { cloneChildrenWithModes } from '../../utils/react-utils'
6
+ import { cloneChildrenWithModes, flattenChildren } from '../../utils/react-utils'
7
7
 
8
8
  type SectionProps = {
9
9
  title?: string;
@@ -69,7 +69,8 @@ function Section({
69
69
  const headerPressedStyle: ViewStyle = isHeaderPressed ? { opacity: 0.85 } : {}
70
70
  // Resolve section container tokens
71
71
  const backgroundColor = getVariableByName('section/background/color', modes) || '#ffffff'
72
- const gap = getVariableByName('slot/gap', modes) || 12
72
+ const sectionGap = getVariableByName('section/gap', modes) || 12
73
+ const slotGap = getVariableByName('slot/gap', modes) || 12
73
74
  const paddingHorizontal = getVariableByName('section/padding/horizontal', modes) || 12
74
75
  const paddingVertical = getVariableByName('section/padding/vertical', modes) || 16
75
76
  const radius = getVariableByName('section/radius', modes) || 12
@@ -106,7 +107,7 @@ function Section({
106
107
  paddingHorizontal,
107
108
  paddingVertical,
108
109
  borderRadius: radius,
109
- gap,
110
+ gap: sectionGap,
110
111
  }
111
112
 
112
113
  const headerStyle = {
@@ -233,8 +234,8 @@ function Section({
233
234
  </View>
234
235
  )}
235
236
  {slot && (
236
- <View style={{ flexDirection: slotDirection, gap }}>
237
- {cloneChildrenWithModes(React.Children.toArray(slot), modes)}
237
+ <View style={{ flexDirection: slotDirection, gap: slotGap }}>
238
+ {cloneChildrenWithModes(flattenChildren(slot), modes)}
238
239
  </View>
239
240
  )}
240
241
  </View>
@@ -302,13 +303,12 @@ function SectionBento({
302
303
 
303
304
 
304
305
 
305
- // Process slots to pass modes to children
306
306
  const processedNavSlot = navSlot
307
- ? cloneChildrenWithModes(React.Children.toArray(navSlot), modes)
307
+ ? cloneChildrenWithModes(flattenChildren(navSlot), modes)
308
308
  : null
309
309
 
310
310
  const processedUpiSlot = upiSlot
311
- ? cloneChildrenWithModes(React.Children.toArray(upiSlot), modes)
311
+ ? cloneChildrenWithModes(flattenChildren(upiSlot), modes)
312
312
  : null
313
313
 
314
314
  return (