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.
- package/lib/commonjs/components/Accordion/Accordion.js +2 -34
- package/lib/commonjs/components/AppBar/AppBar.js +4 -36
- package/lib/commonjs/components/FilterBar/FilterBar.js +2 -34
- package/lib/commonjs/components/LazyList/LazyList.js +2 -34
- package/lib/commonjs/components/MoneyValue/MoneyValue.js +1 -1
- package/lib/commonjs/components/NavArrow/NavArrow.js +45 -44
- package/lib/commonjs/components/Numpad/Numpad.js +6 -5
- package/lib/commonjs/components/Section/Section.js +7 -8
- package/lib/commonjs/components/TextInput/TextInput.js +4 -38
- package/lib/commonjs/components/TransactionBubble/TransactionBubble.js +149 -0
- package/lib/commonjs/components/index.js +7 -0
- package/lib/commonjs/design-tokens/JFSThemeProvider.js +38 -3
- package/lib/commonjs/icons/registry.js +1 -1
- package/lib/commonjs/utils/react-utils.js +18 -13
- package/lib/module/components/Accordion/Accordion.js +1 -33
- package/lib/module/components/AppBar/AppBar.js +1 -34
- package/lib/module/components/FilterBar/FilterBar.js +1 -35
- package/lib/module/components/LazyList/LazyList.js +1 -35
- package/lib/module/components/MoneyValue/MoneyValue.js +1 -1
- package/lib/module/components/NavArrow/NavArrow.js +44 -44
- package/lib/module/components/Numpad/Numpad.js +5 -5
- package/lib/module/components/Section/Section.js +8 -9
- package/lib/module/components/TextInput/TextInput.js +2 -36
- package/lib/module/components/TransactionBubble/TransactionBubble.js +144 -0
- package/lib/module/components/index.js +1 -0
- package/lib/module/design-tokens/JFSThemeProvider.js +35 -3
- package/lib/module/icons/registry.js +1 -1
- package/lib/module/utils/react-utils.js +18 -13
- package/lib/typescript/src/components/NavArrow/NavArrow.d.ts +6 -11
- package/lib/typescript/src/components/TransactionBubble/TransactionBubble.d.ts +39 -0
- package/lib/typescript/src/components/index.d.ts +1 -0
- package/lib/typescript/src/design-tokens/JFSThemeProvider.d.ts +15 -0
- package/lib/typescript/src/icons/registry.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/Accordion/Accordion.tsx +1 -44
- package/src/components/AppBar/AppBar.tsx +1 -44
- package/src/components/FilterBar/FilterBar.tsx +1 -44
- package/src/components/LazyList/LazyList.tsx +1 -41
- package/src/components/MoneyValue/MoneyValue.tsx +1 -1
- package/src/components/NavArrow/NavArrow.tsx +46 -43
- package/src/components/Numpad/Numpad.tsx +5 -5
- package/src/components/Section/Section.tsx +8 -8
- package/src/components/TextInput/TextInput.tsx +1 -44
- package/src/components/TransactionBubble/TransactionBubble.tsx +155 -0
- package/src/components/index.ts +1 -0
- package/src/design-tokens/JFSThemeProvider.tsx +37 -2
- package/src/icons/registry.ts +1 -1
- 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
|
-
|
|
10
|
+
const result = [];
|
|
11
|
+
React.Children.forEach(children, child => {
|
|
11
12
|
if (! /*#__PURE__*/React.isValidElement(child)) {
|
|
12
|
-
|
|
13
|
+
if (child !== null && child !== undefined) {
|
|
14
|
+
result.push(child);
|
|
15
|
+
}
|
|
16
|
+
return;
|
|
13
17
|
}
|
|
14
18
|
|
|
15
|
-
//
|
|
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
|
-
|
|
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
|
-
})
|
|
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
|
|
15
|
+
* NavArrow component that displays a chevron arrow for navigation.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
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 -
|
|
20
|
-
* - navArrow/icon/height -
|
|
21
|
-
* - navArrow/icon/strokeWeight - stroke
|
|
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-
|
|
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
|
@@ -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
|
-
|
|
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)
|
|
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
|
|
20
|
+
* NavArrow component that displays a chevron arrow for navigation.
|
|
21
21
|
*
|
|
22
|
-
*
|
|
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 -
|
|
25
|
-
* - navArrow/icon/height -
|
|
26
|
-
* - navArrow/icon/strokeWeight - stroke
|
|
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
|
-
|
|
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
|
|
60
|
-
const
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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={
|
|
102
|
+
accessibilityLabel={defaultAccessibilityLabel}
|
|
93
103
|
{...rest}
|
|
94
104
|
>
|
|
95
|
-
<
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
|
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
|
-
<
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
|
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(
|
|
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(
|
|
307
|
+
? cloneChildrenWithModes(flattenChildren(navSlot), modes)
|
|
308
308
|
: null
|
|
309
309
|
|
|
310
310
|
const processedUpiSlot = upiSlot
|
|
311
|
-
? cloneChildrenWithModes(
|
|
311
|
+
? cloneChildrenWithModes(flattenChildren(upiSlot), modes)
|
|
312
312
|
: null
|
|
313
313
|
|
|
314
314
|
return (
|