jfs-components 0.0.1 → 0.0.3

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 (101) hide show
  1. package/lib/commonjs/components/ActionFooter/ActionFooter.js +124 -0
  2. package/lib/commonjs/components/ActionFooter/ActionFooter.js.map +1 -0
  3. package/lib/commonjs/components/ActionFooter/ActionFooter.mdx +101 -0
  4. package/lib/commonjs/components/Button/Button.js +1 -1
  5. package/lib/commonjs/components/Button/Button.js.map +1 -1
  6. package/lib/commonjs/components/Button/Button.mdx +2 -2
  7. package/lib/commonjs/components/CardFeedback/CardFeedback.js +47 -11
  8. package/lib/commonjs/components/CardFeedback/CardFeedback.js.map +1 -1
  9. package/lib/commonjs/components/CardFeedback/CardFeedback.mdx +1 -0
  10. package/lib/commonjs/components/Divider/Divider.js +63 -0
  11. package/lib/commonjs/components/Divider/Divider.js.map +1 -0
  12. package/lib/commonjs/components/Divider/Divider.mdx +91 -0
  13. package/lib/commonjs/components/ListItem/ListItem.js +24 -13
  14. package/lib/commonjs/components/ListItem/ListItem.js.map +1 -1
  15. package/lib/commonjs/components/ListItem/ListItem.mdx +46 -5
  16. package/lib/commonjs/components/MerchantProfile/MerchantProfile.js +133 -0
  17. package/lib/commonjs/components/MerchantProfile/MerchantProfile.js.map +1 -0
  18. package/lib/commonjs/components/MerchantProfile/MerchantProfile.mdx +139 -0
  19. package/lib/commonjs/components/MoneyValue/MoneyValue.js +36 -4
  20. package/lib/commonjs/components/MoneyValue/MoneyValue.js.map +1 -1
  21. package/lib/commonjs/components/MoneyValue/MoneyValue.mdx +4 -0
  22. package/lib/commonjs/components/NavArrow/NavArrow.js +90 -0
  23. package/lib/commonjs/components/NavArrow/NavArrow.js.map +1 -0
  24. package/lib/commonjs/components/NavArrow/NavArrow.mdx +123 -0
  25. package/lib/commonjs/components/Section/Section.mdx +4 -4
  26. package/lib/commonjs/components/Stepper/Step.mdx +1 -1
  27. package/lib/commonjs/components/index.js +28 -0
  28. package/lib/commonjs/components/index.js.map +1 -1
  29. package/lib/commonjs/design-tokens/JFS Variables-variables-full.json +18633 -1
  30. package/lib/commonjs/design-tokens/figma-variables-resolver.js.map +1 -2
  31. package/lib/commonjs/icons/registry.js +1 -1
  32. package/lib/module/components/ActionFooter/ActionFooter.js +119 -0
  33. package/lib/module/components/ActionFooter/ActionFooter.js.map +1 -0
  34. package/lib/module/components/ActionFooter/ActionFooter.mdx +101 -0
  35. package/lib/module/components/Button/Button.js +1 -1
  36. package/lib/module/components/Button/Button.js.map +1 -1
  37. package/lib/module/components/Button/Button.mdx +2 -2
  38. package/lib/module/components/CardFeedback/CardFeedback.js +46 -11
  39. package/lib/module/components/CardFeedback/CardFeedback.js.map +1 -1
  40. package/lib/module/components/CardFeedback/CardFeedback.mdx +1 -0
  41. package/lib/module/components/Divider/Divider.js +58 -0
  42. package/lib/module/components/Divider/Divider.js.map +1 -0
  43. package/lib/module/components/Divider/Divider.mdx +91 -0
  44. package/lib/module/components/ListItem/ListItem.js +24 -13
  45. package/lib/module/components/ListItem/ListItem.js.map +1 -1
  46. package/lib/module/components/ListItem/ListItem.mdx +46 -5
  47. package/lib/module/components/MerchantProfile/MerchantProfile.js +128 -0
  48. package/lib/module/components/MerchantProfile/MerchantProfile.js.map +1 -0
  49. package/lib/module/components/MerchantProfile/MerchantProfile.mdx +139 -0
  50. package/lib/module/components/MoneyValue/MoneyValue.js +36 -4
  51. package/lib/module/components/MoneyValue/MoneyValue.js.map +1 -1
  52. package/lib/module/components/MoneyValue/MoneyValue.mdx +4 -0
  53. package/lib/module/components/NavArrow/NavArrow.js +84 -0
  54. package/lib/module/components/NavArrow/NavArrow.js.map +1 -0
  55. package/lib/module/components/NavArrow/NavArrow.mdx +123 -0
  56. package/lib/module/components/Section/Section.mdx +4 -4
  57. package/lib/module/components/Stepper/Step.mdx +1 -1
  58. package/lib/module/components/index.js +4 -0
  59. package/lib/module/components/index.js.map +1 -1
  60. package/lib/module/design-tokens/JFS Variables-variables-full.json +18633 -1
  61. package/lib/module/icons/registry.js +1 -1
  62. package/lib/typescript/components/ActionFooter/ActionFooter.d.ts +58 -0
  63. package/lib/typescript/components/ActionFooter/ActionFooter.d.ts.map +1 -0
  64. package/lib/typescript/components/CardFeedback/CardFeedback.d.ts +4 -3
  65. package/lib/typescript/components/CardFeedback/CardFeedback.d.ts.map +1 -1
  66. package/lib/typescript/components/Divider/Divider.d.ts +50 -0
  67. package/lib/typescript/components/Divider/Divider.d.ts.map +1 -0
  68. package/lib/typescript/components/ListItem/ListItem.d.ts +4 -3
  69. package/lib/typescript/components/ListItem/ListItem.d.ts.map +1 -1
  70. package/lib/typescript/components/MerchantProfile/MerchantProfile.d.ts +68 -0
  71. package/lib/typescript/components/MerchantProfile/MerchantProfile.d.ts.map +1 -0
  72. package/lib/typescript/components/MoneyValue/MoneyValue.d.ts +9 -2
  73. package/lib/typescript/components/MoneyValue/MoneyValue.d.ts.map +1 -1
  74. package/lib/typescript/components/NavArrow/NavArrow.d.ts +35 -0
  75. package/lib/typescript/components/NavArrow/NavArrow.d.ts.map +1 -0
  76. package/lib/typescript/components/index.d.ts +4 -0
  77. package/lib/typescript/components/index.d.ts.map +1 -1
  78. package/lib/typescript/icons/registry.d.ts +1 -1
  79. package/package.json +2 -2
  80. package/src/components/.token-metadata.json +99 -11
  81. package/src/components/ActionFooter/ActionFooter.mdx +101 -0
  82. package/src/components/ActionFooter/ActionFooter.tsx +142 -0
  83. package/src/components/Button/Button.mdx +2 -2
  84. package/src/components/Button/Button.tsx +1 -1
  85. package/src/components/CardFeedback/CardFeedback.mdx +1 -0
  86. package/src/components/CardFeedback/CardFeedback.tsx +37 -12
  87. package/src/components/Divider/Divider.mdx +91 -0
  88. package/src/components/Divider/Divider.tsx +91 -0
  89. package/src/components/ListItem/ListItem.mdx +46 -5
  90. package/src/components/ListItem/ListItem.tsx +22 -11
  91. package/src/components/MerchantProfile/MerchantProfile.mdx +139 -0
  92. package/src/components/MerchantProfile/MerchantProfile.tsx +174 -0
  93. package/src/components/MoneyValue/MoneyValue.mdx +4 -0
  94. package/src/components/MoneyValue/MoneyValue.tsx +39 -3
  95. package/src/components/NavArrow/NavArrow.mdx +123 -0
  96. package/src/components/NavArrow/NavArrow.tsx +108 -0
  97. package/src/components/Section/Section.mdx +4 -4
  98. package/src/components/Stepper/Step.mdx +1 -1
  99. package/src/components/index.ts +4 -0
  100. package/src/design-tokens/JFS Variables-variables-full.json +18633 -1
  101. package/src/icons/registry.ts +1 -1
@@ -0,0 +1,101 @@
1
+ import { Meta, Story, Canvas, PureArgsTable as ArgsTable } from '@storybook/addon-docs/blocks';
2
+ import * as ActionFooterStories from './ActionFooter.stories';
3
+ import ActionFooter from './ActionFooter';
4
+
5
+ <Meta of={ActionFooterStories} />
6
+
7
+ # ActionFooter
8
+
9
+ A fixed footer container for action buttons. Typically used at the bottom of screens to hold primary actions like `IconButton` and `Button` components.
10
+
11
+ The ActionFooter provides consistent spacing, padding, and shadow styling for action areas at the bottom of your UI.
12
+
13
+ ## Props
14
+
15
+ <ArgsTable of={ActionFooter} />
16
+
17
+
18
+ ## Available Collections and Modes
19
+
20
+ This component does not use any design token collections with multiple modes.
21
+ ## Usage
22
+
23
+ The default configuration shows the typical use case with an IconButton and two Button components:
24
+
25
+ <Canvas>
26
+ <Story of={ActionFooterStories.Default} />
27
+ </Canvas>
28
+
29
+ ## Examples
30
+
31
+ ### Single Button
32
+
33
+ For simple confirmation flows, use a single full-width button:
34
+
35
+ <Canvas>
36
+ <Story of={ActionFooterStories.SingleButton} />
37
+ </Canvas>
38
+
39
+ ### Two Buttons
40
+
41
+ Common pattern for cancel/confirm actions:
42
+
43
+ <Canvas>
44
+ <Story of={ActionFooterStories.TwoButtons} />
45
+ </Canvas>
46
+
47
+ ### With Multiple Icon Buttons
48
+
49
+ For screens requiring multiple secondary actions alongside a primary button:
50
+
51
+ <Canvas>
52
+ <Story of={ActionFooterStories.WithMultipleIconButtons} />
53
+ </Canvas>
54
+
55
+ ## Component Usage
56
+
57
+ ```tsx
58
+ import { ActionFooter, IconButton, Button } from 'jsf-components';
59
+
60
+ function PaymentScreen() {
61
+ const modes = {};
62
+ const secondaryModes = { Appearance: 'secondary' };
63
+ const primaryModes = { Appearance: 'primary' };
64
+
65
+ return (
66
+ <View style={{ flex: 1 }}>
67
+ {/* Screen content */}
68
+
69
+ <ActionFooter modes={modes}>
70
+ <IconButton iconName="ic_split" modes={modes} />
71
+ <Button
72
+ label="Request"
73
+ modes={secondaryModes}
74
+ style={{ flex: 1 }}
75
+ />
76
+ <Button
77
+ label="Pay"
78
+ modes={primaryModes}
79
+ style={{ flex: 1 }}
80
+ />
81
+ </ActionFooter>
82
+ </View>
83
+ );
84
+ }
85
+ ```
86
+
87
+ ## Design Tokens
88
+
89
+ This component uses the following design tokens, resolved through `getVariableByName`:
90
+
91
+ - **`actionFooter/background`**
92
+ - **`actionFooter/gap`**
93
+ - **`actionFooter/padding/bottom`**
94
+ - **`actionFooter/padding/horizontal`**
95
+ - **`actionFooter/padding/top`**
96
+
97
+ All tokens support mode-based theming through the `modes` prop.
98
+ ## Accessibility
99
+
100
+ The ActionFooter uses `accessibilityRole="toolbar"` to indicate it contains a group of action controls. Provide a meaningful `accessibilityLabel` to describe the footer's purpose to screen reader users.
101
+
@@ -0,0 +1,142 @@
1
+ import React from 'react'
2
+ import {
3
+ View,
4
+ type ViewStyle,
5
+ type StyleProp,
6
+ Platform,
7
+ } from 'react-native'
8
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
9
+
10
+ export type ActionFooterProps = {
11
+ /**
12
+ * Content to render inside the action footer slot.
13
+ * Typically includes IconButton and Button components.
14
+ */
15
+ children?: React.ReactNode
16
+ /**
17
+ * Mode configuration passed to the token resolver.
18
+ * Pass the same modes to children components for consistent theming.
19
+ */
20
+ modes?: Record<string, any>
21
+ /**
22
+ * Optional style overrides for the container
23
+ */
24
+ style?: StyleProp<ViewStyle>
25
+ /**
26
+ * Accessibility label for the footer region
27
+ */
28
+ accessibilityLabel?: string
29
+ }
30
+
31
+ /**
32
+ * ActionFooter component that provides a fixed footer container for action buttons.
33
+ *
34
+ * This component is designed to hold action items like IconButton and Button components
35
+ * at the bottom of a screen. It includes a shadow for visual separation from content above.
36
+ *
37
+ * The `modes` prop is automatically passed to all slot children. If a child has its own
38
+ * `modes` prop, it will be merged with the parent's modes (child modes take precedence).
39
+ *
40
+ * @component
41
+ * @param {Object} props - Component props
42
+ * @param {React.ReactNode} [props.children] - Action elements to display (e.g., IconButton, Button)
43
+ * @param {Object} [props.modes={}] - Mode configuration for design tokens (automatically passed to children)
44
+ * @param {Object} [props.style] - Optional style overrides
45
+ * @param {string} [props.accessibilityLabel] - Accessibility label for the footer region
46
+ *
47
+ * @example
48
+ * ```tsx
49
+ * // Basic usage - modes are automatically passed to all children
50
+ * <ActionFooter modes={modes}>
51
+ * <IconButton iconName="ic_split" />
52
+ * <Button label="Request" style={{ flex: 1 }} />
53
+ * <Button label="Pay" style={{ flex: 1 }} />
54
+ * </ActionFooter>
55
+ *
56
+ * // Children can override with their own modes (merged with parent)
57
+ * <ActionFooter modes={modes}>
58
+ * <IconButton iconName="ic_split" />
59
+ * <Button label="Request" modes={{ Appearance: 'secondary' }} style={{ flex: 1 }} />
60
+ * <Button label="Pay" modes={{ Appearance: 'primary' }} style={{ flex: 1 }} />
61
+ * </ActionFooter>
62
+ * ```
63
+ */
64
+ function ActionFooter({
65
+ children,
66
+ modes = {},
67
+ style,
68
+ accessibilityLabel = 'Action footer',
69
+ }: ActionFooterProps) {
70
+ // Resolve design tokens
71
+ const backgroundColor = getVariableByName('actionFooter/background', modes) ?? '#ffffff'
72
+ const gap = getVariableByName('actionFooter/gap', modes) ?? 8
73
+ const paddingHorizontal = getVariableByName('actionFooter/padding/horizontal', modes) ?? 16
74
+ const paddingTop = getVariableByName('actionFooter/padding/top', modes) ?? 10
75
+ const paddingBottom = getVariableByName('actionFooter/padding/bottom', modes) ?? 41
76
+
77
+ // Shadow styles - cross-platform
78
+ const shadowStyle: ViewStyle = Platform.select({
79
+ ios: {
80
+ shadowColor: 'rgba(12, 13, 16, 1)',
81
+ shadowOffset: { width: 0, height: -12 },
82
+ shadowOpacity: 0.16,
83
+ shadowRadius: 24,
84
+ },
85
+ android: {
86
+ elevation: 16,
87
+ },
88
+ default: {
89
+ // Web shadow using boxShadow (RNW supports this)
90
+ },
91
+ }) as ViewStyle
92
+
93
+ const containerStyle: ViewStyle = {
94
+ backgroundColor,
95
+ paddingLeft: paddingHorizontal,
96
+ paddingRight: paddingHorizontal,
97
+ paddingTop,
98
+ paddingBottom,
99
+ ...shadowStyle,
100
+ }
101
+
102
+ // Slot container style for horizontal layout of action items
103
+ const slotStyle: ViewStyle = {
104
+ flexDirection: 'row',
105
+ alignItems: 'flex-start',
106
+ gap,
107
+ flex: 1,
108
+ }
109
+
110
+ // Web-specific box-shadow
111
+ const webShadow = Platform.OS === 'web'
112
+ ? { boxShadow: '0px -12px 24px 0px rgba(12, 13, 16, 0.12), 0px -16px 48px 0px rgba(12, 13, 16, 0.16)' } as any
113
+ : {}
114
+
115
+ // Pass modes prop to all slot children
116
+ const childrenWithModes = React.Children.map(children, (child) => {
117
+ if (React.isValidElement(child)) {
118
+ // Merge modes: child's modes take precedence over parent's modes
119
+ const childModes = (child.props as any).modes
120
+ const mergedModes = childModes ? { ...modes, ...childModes } : modes
121
+ return React.cloneElement(child as React.ReactElement<any>, {
122
+ modes: mergedModes,
123
+ })
124
+ }
125
+ return child
126
+ })
127
+
128
+ return (
129
+ <View
130
+ style={[containerStyle, webShadow, style]}
131
+ accessibilityRole="toolbar"
132
+ accessibilityLabel={accessibilityLabel}
133
+ >
134
+ <View style={slotStyle}>
135
+ {childrenWithModes}
136
+ </View>
137
+ </View>
138
+ )
139
+ }
140
+
141
+ export default ActionFooter
142
+
@@ -34,7 +34,7 @@ This component uses the following design token collections. Each collection supp
34
34
  - **Default:** positive
35
35
 
36
36
  ### Context
37
- - **Modes:** Default | Nudge&Alert
37
+ - **Modes:** Default | Nudge&Alert | CTACard | ListItem
38
38
  - **Default:** Default
39
39
 
40
40
  ### Button / Size
@@ -90,7 +90,7 @@ This component uses the following design tokens, resolved through `getVariableBy
90
90
  - **`button/fontFamily`**
91
91
  - **`button/fontSize`**
92
92
  - **`button/fontWeight`**
93
- - **`button/forground`**
93
+ - **`button/foreground`**
94
94
  - **`button/gap`**
95
95
  - **`button/lineHeight`**
96
96
  - **`button/padding/horizontal`**
@@ -89,7 +89,7 @@ function Button({
89
89
  const fontWeight = typeof fontWeightValue === 'number' ? fontWeightValue.toString() : fontWeightValue
90
90
  const lineHeight = getVariableByName('button/lineHeight', modes) || 19
91
91
  const fontSize = getVariableByName('button/fontSize', modes) || 16
92
- const textColor = getVariableByName('button/forground', modes) || '#0f0d0a'
92
+ const textColor = getVariableByName('button/foreground', modes) || '#0f0d0a'
93
93
 
94
94
  const baseLabelTextStyle: TextStyle = {
95
95
  color: textColor,
@@ -62,6 +62,7 @@ This component uses the following design token collections. Each collection supp
62
62
 
63
63
  This component uses the following design tokens, resolved through `getVariableByName`:
64
64
 
65
+ - **`appearanceFeedback/cardFeedback/icon/color`**
65
66
  - **`cardFeedback/actionSlot/gap`**
66
67
  - **`cardFeedback/background`**
67
68
  - **`cardFeedback/body/color`**
@@ -1,6 +1,7 @@
1
1
  import React, { createContext, useContext, isValidElement, cloneElement } from 'react';
2
2
  import { View, Text, StyleSheet, type ViewStyle, type TextStyle, type StyleProp, Image } from 'react-native';
3
3
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
4
+ import IconComponent from '../../icons/Icon';
4
5
 
5
6
  /**
6
7
  * Context to share 'modes' with child components.
@@ -29,9 +30,15 @@ export interface CardFeedbackProps {
29
30
  */
30
31
  export function CardFeedback({
31
32
  children,
32
- modes = {},
33
+ modes: propModes,
33
34
  style,
34
35
  }: CardFeedbackProps) {
36
+ const modes = {
37
+ 'Appearance.System': 'positive',
38
+ 'Context': 'Nudge&Alert',
39
+ 'Semantic Intent': 'System',
40
+ ...propModes,
41
+ };
35
42
  // Container Tokens
36
43
  const backgroundColor = getVariableByName('cardFeedback/background', modes) || '#dbf0d9';
37
44
  const radius = parseFloat(getVariableByName('cardFeedback/radius', modes) || '12');
@@ -66,16 +73,16 @@ export function CardFeedback({
66
73
 
67
74
  /**
68
75
  * Icon Wrapper
69
- * Tokens: cardFeedback/icon/size, cardFeedback/icon/color
76
+ * Tokens: cardFeedback/icon/size, appearanceFeedback/cardFeedback/icon/color
70
77
  */
71
- export function Icon({ children, style, modes: propModes }: { children?: React.ReactNode; style?: StyleProp<ViewStyle>; modes?: Record<string, any> }) {
78
+ export function Icon({ children, style, modes: propModes, icon }: { children?: React.ReactNode; style?: StyleProp<ViewStyle>; modes?: Record<string, any>; icon?: string }) {
72
79
  const context = useContext(CardFeedbackContext);
73
80
  const modes = propModes || context.modes || {};
74
81
 
75
82
  const size = parseFloat(getVariableByName('cardFeedback/icon/size', modes) || '20');
76
- // Color is usually applied to the SVG/Icon itself, but we can access it here if needed
77
- // const color = getVariableByName('cardFeedback/icon/color', modes);
78
-
83
+ // Color for the icon itself
84
+ const color = getVariableByName('appearanceFeedback/cardFeedback/icon/color', modes);
85
+ console.log(color);
79
86
  const containerStyle: ViewStyle = {
80
87
  width: size,
81
88
  height: size,
@@ -84,11 +91,21 @@ export function Icon({ children, style, modes: propModes }: { children?: React.R
84
91
  overflow: 'hidden',
85
92
  };
86
93
 
87
- // If children is an SVG or Icon component, we might need to clone it to pass color?
88
- // For now, just render children in the sized box.
94
+ // Pass modes to children (e.g., icon components that accept modes)
95
+ const childrenWithModes = React.Children.map(children, child => {
96
+ if (isValidElement(child)) {
97
+ return cloneElement(child as React.ReactElement<{ modes?: Record<string, any> }>, { modes: { ...(child.props as any).modes, ...modes } });
98
+ }
99
+ return child;
100
+ });
101
+
89
102
  return (
90
103
  <View style={[containerStyle, style]}>
91
- {children}
104
+ {icon ? (
105
+ <IconComponent name={icon} size={size} color={color} />
106
+ ) : (
107
+ childrenWithModes
108
+ )}
92
109
  </View>
93
110
  );
94
111
  }
@@ -104,9 +121,17 @@ export function Content({ children, style, modes: propModes }: { children?: Reac
104
121
 
105
122
  const gap = parseFloat(getVariableByName('cardFeedback/text/gap', modes) || '8');
106
123
 
124
+ // Pass modes to children (Title, Body, etc.)
125
+ const childrenWithModes = React.Children.map(children, child => {
126
+ if (isValidElement(child)) {
127
+ return cloneElement(child as React.ReactElement<{ modes?: Record<string, any> }>, { modes: { ...(child.props as any).modes, ...modes } });
128
+ }
129
+ return child;
130
+ });
131
+
107
132
  return (
108
133
  <View style={[{ gap, width: '100%' }, style]}>
109
- {children}
134
+ {childrenWithModes}
110
135
  </View>
111
136
  );
112
137
  }
@@ -169,12 +194,12 @@ export function Action({ children, style, modes: propModes }: { children?: React
169
194
  const context = useContext(CardFeedbackContext);
170
195
  const modes = propModes || context.modes || {};
171
196
 
172
- const gap = parseFloat(getVariableByName('cardFeedback/actionSlot/gap', modes) || '4');
197
+ const gap = parseFloat(getVariableByName('cardFeedback/actionSlot/gap', modes) || '0');
173
198
 
174
199
  // "Maximise existing component usage" -> Pass modes to children (Buttons)
175
200
  const childrenWithModes = React.Children.map(children, child => {
176
201
  if (isValidElement(child)) {
177
- return cloneElement(child as any, { modes: { ...(child.props as any).modes, ...modes } });
202
+ return cloneElement(child as React.ReactElement<{ modes?: Record<string, any> }>, { modes: { ...(child.props as any).modes, ...modes } });
178
203
  }
179
204
  return child;
180
205
  });
@@ -0,0 +1,91 @@
1
+ import { Meta, Story, Canvas, PureArgsTable as ArgsTable } from '@storybook/addon-docs/blocks';
2
+ import * as DividerStories from './Divider.stories';
3
+ import Divider from './Divider';
4
+
5
+ <Meta of={DividerStories} />
6
+
7
+ # Divider
8
+
9
+ A simple divider component that renders a horizontal or vertical separator line. Uses design tokens for consistent sizing and color.
10
+
11
+ ## Props
12
+
13
+ <ArgsTable of={Divider} />
14
+
15
+ ## Available Collections and Modes
16
+
17
+ This component uses the following design token collections. Each collection supports multiple modes that can be configured via the `modes` prop.
18
+
19
+ ### Color Mode
20
+ - **Modes:** Light | Dark
21
+ - **Default:** Light
22
+ ## Usage
23
+
24
+ ### Horizontal Divider
25
+
26
+ The default horizontal divider stretches to fill its container width:
27
+
28
+ <Canvas>
29
+ <Story of={DividerStories.Horizontal} />
30
+ </Canvas>
31
+
32
+ ### Vertical Divider
33
+
34
+ Vertical dividers stretch to fill their container height:
35
+
36
+ <Canvas>
37
+ <Story of={DividerStories.Vertical} />
38
+ </Canvas>
39
+
40
+ ### In Content Layout
41
+
42
+ Use horizontal dividers to separate content sections:
43
+
44
+ <Canvas>
45
+ <Story of={DividerStories.InContentLayout} />
46
+ </Canvas>
47
+
48
+ ### In Row Layout
49
+
50
+ Use vertical dividers to separate items in a horizontal row:
51
+
52
+ <Canvas>
53
+ <Story of={DividerStories.InRowLayout} />
54
+ </Canvas>
55
+
56
+ ## Component Usage
57
+
58
+ ```tsx
59
+ import { Divider } from 'jsf-components';
60
+
61
+ // Horizontal divider (default)
62
+ <Divider />
63
+
64
+ // Vertical divider
65
+ <Divider direction="vertical" />
66
+
67
+ // In a vertical layout
68
+ <View>
69
+ <Text>Section 1</Text>
70
+ <Divider />
71
+ <Text>Section 2</Text>
72
+ </View>
73
+
74
+ // In a horizontal layout
75
+ <View style={{ flexDirection: 'row', alignItems: 'center' }}>
76
+ <Text>Item 1</Text>
77
+ <View style={{ marginHorizontal: 8 }}>
78
+ <Divider direction="vertical" />
79
+ </View>
80
+ <Text>Item 2</Text>
81
+ </View>
82
+ ```
83
+
84
+ ## Design Tokens
85
+
86
+ This component uses the following design tokens, resolved through `getVariableByName`:
87
+
88
+ - **`divider/color`**
89
+ - **`divider/size`**
90
+
91
+ All tokens support mode-based theming through the `modes` prop.
@@ -0,0 +1,91 @@
1
+ import React from 'react'
2
+ import {
3
+ View,
4
+ type ViewStyle,
5
+ type StyleProp,
6
+ } from 'react-native'
7
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
8
+
9
+ export type DividerDirection = 'horizontal' | 'vertical'
10
+
11
+ export type DividerProps = {
12
+ /**
13
+ * Direction of the divider line.
14
+ * - 'horizontal': renders a horizontal line (default)
15
+ * - 'vertical': renders a vertical line
16
+ */
17
+ direction?: DividerDirection
18
+ /**
19
+ * Mode configuration passed to the token resolver.
20
+ */
21
+ modes?: Record<string, any>
22
+ /**
23
+ * Optional style overrides for the divider
24
+ */
25
+ style?: StyleProp<ViewStyle>
26
+ /**
27
+ * Accessibility label for the divider
28
+ */
29
+ accessibilityLabel?: string
30
+ }
31
+
32
+ /**
33
+ * Divider component that renders a horizontal or vertical separator line.
34
+ *
35
+ * This component is used to visually separate content sections. It supports
36
+ * both horizontal and vertical orientations based on the `direction` prop.
37
+ *
38
+ * @component
39
+ * @param {Object} props - Component props
40
+ * @param {'horizontal' | 'vertical'} [props.direction='horizontal'] - Direction of the divider
41
+ * @param {Object} [props.modes={}] - Mode configuration for design tokens
42
+ * @param {Object} [props.style] - Optional style overrides
43
+ * @param {string} [props.accessibilityLabel] - Accessibility label for the divider
44
+ *
45
+ * @example
46
+ * ```tsx
47
+ * // Horizontal divider (default)
48
+ * <Divider />
49
+ *
50
+ * // Vertical divider
51
+ * <Divider direction="vertical" />
52
+ *
53
+ * // With custom modes
54
+ * <Divider modes={{ Appearance: 'dark' }} />
55
+ * ```
56
+ */
57
+ function Divider({
58
+ direction = 'horizontal',
59
+ modes = {},
60
+ style,
61
+ accessibilityLabel = 'Divider',
62
+ }: DividerProps) {
63
+ // Resolve design tokens
64
+ const size = getVariableByName('divider/size', modes) ?? 1
65
+ const color = getVariableByName('divider/color', modes) ?? '#1a1c1f'
66
+
67
+ const isVertical = direction === 'vertical'
68
+
69
+ const dividerStyle: ViewStyle = isVertical
70
+ ? {
71
+ width: size,
72
+ backgroundColor: color,
73
+ alignSelf: 'stretch',
74
+ }
75
+ : {
76
+ height: size,
77
+ backgroundColor: color,
78
+ alignSelf: 'stretch',
79
+ }
80
+
81
+ return (
82
+ <View
83
+ style={[dividerStyle, style]}
84
+ accessibilityRole="none"
85
+ accessibilityLabel={accessibilityLabel}
86
+ />
87
+ )
88
+ }
89
+
90
+ export default Divider
91
+
@@ -7,7 +7,9 @@ import { AccessibilitySection, AnatomySection, UsageConstraintsSection } from '.
7
7
 
8
8
  # ListItem
9
9
 
10
- Helper function to recursively clone children and pass modes prop to components that accept it.
10
+ A token-driven list item component supporting vertical and horizontal layouts, with optional navigation behaviour and slots for leading, support text and trailing content.
11
+
12
+ The horizontal layout includes a **NavArrow** on the far right by default, which can be hidden via the `navArrow` prop.
11
13
 
12
14
  ## Available Collections and Modes
13
15
 
@@ -26,9 +28,47 @@ This component uses the following design token collections. Each collection supp
26
28
  - **Default:** Light
27
29
  ## Usage
28
30
 
29
- <Canvas>
30
- <Story of={ListItemStories.Default} />
31
- </Canvas>
31
+ ### Horizontal Layout with NavArrow
32
+
33
+ <Canvas of={ListItemStories.HorizontalNavigation} />
34
+
35
+ ### Horizontal Layout (NavArrow only, no endSlot)
36
+
37
+ <Canvas of={ListItemStories.HorizontalWithNavArrowOnly} />
38
+
39
+ ### Vertical Layout
40
+
41
+ <Canvas of={ListItemStories.VerticalStatic} />
42
+
43
+ ### Usage Example
44
+
45
+ ```tsx
46
+ import ListItem from './ListItem';
47
+ import Button from '../Button/Button';
48
+
49
+ // Horizontal with NavArrow (default)
50
+ <ListItem
51
+ layout="Horizontal"
52
+ title="Navigate to Details"
53
+ supportText="Tap to view more"
54
+ navArrow={true}
55
+ />
56
+
57
+ // Horizontal without NavArrow
58
+ <ListItem
59
+ layout="Horizontal"
60
+ title="Balance"
61
+ supportText="₹500"
62
+ navArrow={false}
63
+ endSlot={<Button label="Add Money" />}
64
+ />
65
+
66
+ // Vertical layout (NavArrow not applicable)
67
+ <ListItem
68
+ layout="Vertical"
69
+ supportText="Payments"
70
+ />
71
+ ```
32
72
 
33
73
 
34
74
  <AccessibilitySection
@@ -43,7 +83,8 @@ This component uses the following design token collections. Each collection supp
43
83
  <ul>
44
84
  <li><strong>Leading slot</strong> — optional icon/avatar.</li>
45
85
  <li><strong>Title & support</strong> — primary and secondary text.</li>
46
- <li><strong>Trailing slot</strong> — optional meta info or action affordance.</li>
86
+ <li><strong>Trailing slot (endSlot)</strong> — optional meta info or action affordance. <strong>Note:</strong> This slot strictly enforces <code>Context: 'ListItem'</code> for its children, overriding any conflicting context passed via the <code>modes</code> prop.</li>
87
+ <li><strong>NavArrow</strong> — navigation chevron on the far right (Horizontal layout only). Shown by default, can be hidden via <code>navArrow=&#123;false&#125;</code>.</li>
47
88
  </ul>
48
89
  </AnatomySection>
49
90