jfs-components 0.0.77 → 0.0.79

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 (87) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/lib/commonjs/components/Accordion/Accordion.js +55 -55
  3. package/lib/commonjs/components/ActionFooter/ActionFooter.js +48 -2
  4. package/lib/commonjs/components/Attached/Attached.js +144 -0
  5. package/lib/commonjs/components/Card/Card.js +25 -2
  6. package/lib/commonjs/components/Checkbox/Checkbox.js +21 -9
  7. package/lib/commonjs/components/DropdownInput/DropdownInput.js +30 -16
  8. package/lib/commonjs/components/ExpandableCheckbox/ExpandableCheckbox.js +167 -0
  9. package/lib/commonjs/components/FormField/FormField.js +14 -1
  10. package/lib/commonjs/components/FullscreenModal/FullscreenModal.js +353 -0
  11. package/lib/commonjs/components/ListItem/ListItem.js +46 -24
  12. package/lib/commonjs/components/MessageField/MessageField.js +318 -0
  13. package/lib/commonjs/components/NavArrow/NavArrow.js +58 -17
  14. package/lib/commonjs/components/PlanComparisonCard/PlanComparisonCard.js +328 -0
  15. package/lib/commonjs/components/Slot/Slot.js +73 -0
  16. package/lib/commonjs/components/Stepper/Step.js +47 -60
  17. package/lib/commonjs/components/Stepper/StepLabel.js +40 -10
  18. package/lib/commonjs/components/Stepper/Stepper.js +15 -17
  19. package/lib/commonjs/components/SuggestiveSearch/SuggestiveSearch.js +487 -0
  20. package/lib/commonjs/components/TextInput/TextInput.js +16 -1
  21. package/lib/commonjs/components/Title/Title.js +10 -2
  22. package/lib/commonjs/components/index.js +49 -0
  23. package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
  24. package/lib/commonjs/icons/registry.js +1 -1
  25. package/lib/module/components/Accordion/Accordion.js +56 -56
  26. package/lib/module/components/ActionFooter/ActionFooter.js +50 -4
  27. package/lib/module/components/Attached/Attached.js +139 -0
  28. package/lib/module/components/Card/Card.js +25 -2
  29. package/lib/module/components/Checkbox/Checkbox.js +22 -10
  30. package/lib/module/components/DropdownInput/DropdownInput.js +30 -16
  31. package/lib/module/components/ExpandableCheckbox/ExpandableCheckbox.js +161 -0
  32. package/lib/module/components/FormField/FormField.js +16 -3
  33. package/lib/module/components/FullscreenModal/FullscreenModal.js +348 -0
  34. package/lib/module/components/ListItem/ListItem.js +46 -24
  35. package/lib/module/components/MessageField/MessageField.js +313 -0
  36. package/lib/module/components/NavArrow/NavArrow.js +59 -18
  37. package/lib/module/components/PlanComparisonCard/PlanComparisonCard.js +322 -0
  38. package/lib/module/components/Slot/Slot.js +68 -0
  39. package/lib/module/components/Stepper/Step.js +48 -61
  40. package/lib/module/components/Stepper/StepLabel.js +40 -10
  41. package/lib/module/components/Stepper/Stepper.js +15 -17
  42. package/lib/module/components/SuggestiveSearch/SuggestiveSearch.js +481 -0
  43. package/lib/module/components/TextInput/TextInput.js +17 -2
  44. package/lib/module/components/Title/Title.js +10 -2
  45. package/lib/module/components/index.js +7 -0
  46. package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
  47. package/lib/module/icons/registry.js +1 -1
  48. package/lib/typescript/src/components/Accordion/Accordion.d.ts +14 -20
  49. package/lib/typescript/src/components/Attached/Attached.d.ts +61 -0
  50. package/lib/typescript/src/components/Card/Card.d.ts +9 -2
  51. package/lib/typescript/src/components/ExpandableCheckbox/ExpandableCheckbox.d.ts +63 -0
  52. package/lib/typescript/src/components/FullscreenModal/FullscreenModal.d.ts +99 -0
  53. package/lib/typescript/src/components/ListItem/ListItem.d.ts +15 -5
  54. package/lib/typescript/src/components/MessageField/MessageField.d.ts +81 -0
  55. package/lib/typescript/src/components/NavArrow/NavArrow.d.ts +10 -5
  56. package/lib/typescript/src/components/PlanComparisonCard/PlanComparisonCard.d.ts +64 -0
  57. package/lib/typescript/src/components/Slot/Slot.d.ts +52 -0
  58. package/lib/typescript/src/components/Stepper/Step.d.ts +4 -1
  59. package/lib/typescript/src/components/Stepper/StepLabel.d.ts +4 -1
  60. package/lib/typescript/src/components/Stepper/Stepper.d.ts +3 -1
  61. package/lib/typescript/src/components/SuggestiveSearch/SuggestiveSearch.d.ts +123 -0
  62. package/lib/typescript/src/components/index.d.ts +10 -3
  63. package/lib/typescript/src/icons/registry.d.ts +1 -1
  64. package/package.json +1 -1
  65. package/src/components/Accordion/Accordion.tsx +113 -73
  66. package/src/components/ActionFooter/ActionFooter.tsx +56 -4
  67. package/src/components/Attached/Attached.tsx +181 -0
  68. package/src/components/Card/Card.tsx +28 -1
  69. package/src/components/Checkbox/Checkbox.tsx +22 -9
  70. package/src/components/DropdownInput/DropdownInput.tsx +67 -39
  71. package/src/components/ExpandableCheckbox/ExpandableCheckbox.tsx +237 -0
  72. package/src/components/FormField/FormField.tsx +19 -3
  73. package/src/components/FullscreenModal/FullscreenModal.tsx +414 -0
  74. package/src/components/ListItem/ListItem.tsx +55 -25
  75. package/src/components/MessageField/MessageField.tsx +543 -0
  76. package/src/components/NavArrow/NavArrow.tsx +81 -17
  77. package/src/components/PlanComparisonCard/PlanComparisonCard.tsx +426 -0
  78. package/src/components/Slot/Slot.tsx +91 -0
  79. package/src/components/Stepper/Step.tsx +52 -51
  80. package/src/components/Stepper/StepLabel.tsx +46 -9
  81. package/src/components/Stepper/Stepper.tsx +20 -15
  82. package/src/components/SuggestiveSearch/SuggestiveSearch.tsx +756 -0
  83. package/src/components/TextInput/TextInput.tsx +14 -1
  84. package/src/components/Title/Title.tsx +13 -2
  85. package/src/components/index.ts +10 -3
  86. package/src/design-tokens/Coin Variables-variables-full.json +1 -1
  87. package/src/icons/registry.ts +1 -1
@@ -3,7 +3,7 @@ import { View, Text, type ViewStyle, type TextStyle } from 'react-native'
3
3
  import Svg, { Path } from 'react-native-svg'
4
4
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
5
5
  import { StepLabel } from './StepLabel'
6
- import { EMPTY_MODES } from '../../utils/react-utils'
6
+ import { EMPTY_MODES, cloneChildrenWithModes } from '../../utils/react-utils'
7
7
 
8
8
  export type StepStatus = 'number' | 'complete' | 'error' | 'warning'
9
9
 
@@ -14,14 +14,21 @@ export type StepProps = {
14
14
  // Injected by Stepper, or provided manually
15
15
  index?: number
16
16
 
17
- // Custom style for the connecting line, allowing Stepper to hide it for the last item
17
+ // Connector line visibility explicit prop (Figma `showLine`).
18
+ // Stepper sets this to false on the last item.
19
+ showLine?: boolean
20
+
21
+ // Custom style for the connecting line. Kept for backwards compatibility;
22
+ // when provided, it is merged on top of the default line style.
18
23
  connectorStyle?: ViewStyle
19
24
 
20
- // Props matching Figma component interface directly
25
+ // Content props matching Figma component interface
21
26
  title?: string
22
27
  supportingText?: string
23
- subtitle?: boolean // Toggle for subtitle visibility if passed via props
24
- status?: StepStatus // 'number' | 'complete' | 'error' | 'warning'
28
+ metaText?: string
29
+ subtitle?: boolean
30
+ meta?: boolean
31
+ status?: StepStatus
25
32
  }
26
33
 
27
34
  export function Step({
@@ -29,35 +36,37 @@ export function Step({
29
36
  modes = EMPTY_MODES,
30
37
  style,
31
38
  index = 0,
39
+ showLine = true,
32
40
  connectorStyle,
33
41
  title,
34
42
  supportingText,
43
+ metaText,
35
44
  subtitle = true,
45
+ meta = true,
36
46
  status = 'number',
37
47
  }: StepProps) {
38
- // Container styles
39
48
  const minHeight =
40
49
  Number(getVariableByName('steperItem/minHeight', modes) as unknown) || 52
41
50
  const gap =
42
- Number(getVariableByName('steperItem/gap', modes) as unknown) || 8
51
+ Number(getVariableByName('steperItem/gap', modes) as unknown) || 16
43
52
 
44
- // Indicator dimensions and styles
45
53
  const indicatorSize =
46
- Number(getVariableByName('stepIndicator/size', modes) as unknown) || 24
54
+ Number(getVariableByName('stepIndicator/size', modes) as unknown) || 36
47
55
  const indicatorRadius =
48
56
  Number(getVariableByName('stepIndicator/radius', modes) as unknown) || 9999
49
57
  const indicatorBg =
50
58
  (getVariableByName('stepIndicator/background', modes) as string) ||
51
- '#5c00b5'
59
+ '#5d00b5'
52
60
  const indicatorBorderColor =
53
61
  (getVariableByName('stepIndicator/border/color', modes) as string) ||
54
- '#5c00b5'
62
+ '#5d00b5'
55
63
  const indicatorBorderSize =
56
64
  Number(getVariableByName('stepIndicator/border/size', modes) as unknown) || 1
57
65
  const iconColor =
58
66
  (getVariableByName('stepIndicator/icon/color', modes) as string) || '#ffffff'
67
+ const stepStatusSize =
68
+ Number(getVariableByName('stepStatus/size', modes) as unknown) || 18
59
69
 
60
- // Label styles (for number)
61
70
  const labelFontSize =
62
71
  Number(getVariableByName('stepIndicator/label/fontSize', modes) as unknown) || 12
63
72
  const labelFontFamily =
@@ -67,28 +76,28 @@ export function Step({
67
76
  const labelFontWeight =
68
77
  (getVariableByName('stepIndicator/label/fontWeight', modes) as string) || '500'
69
78
 
70
- // Vertical line styles
71
79
  const lineSize =
72
80
  Number(getVariableByName('steperItem/lineSize', modes) as unknown) || 2
73
81
  const lineColor =
74
- (getVariableByName('steperItem/line', modes) as string) || '#5c00b5'
82
+ (getVariableByName('steperItem/line', modes) as string) || '#5d00b5'
75
83
  const badgeWrapGap =
76
84
  Number(getVariableByName('steperItem/badgeWrap/gap', modes) as unknown) || 2
77
85
 
78
86
  const containerStyle: ViewStyle = {
79
87
  flexDirection: 'row',
80
88
  minHeight,
89
+ gap,
81
90
  ...style,
82
91
  }
83
92
 
84
- // FIX: This wrapper should NOT expand. It should be exact width of the indicator.
85
93
  const indicatorWrapperStyle: ViewStyle = {
86
94
  flexDirection: 'column',
87
95
  alignItems: 'center',
88
96
  width: indicatorSize,
89
- flexGrow: 0, // Do NOT grow
97
+ flexGrow: 0,
90
98
  flexShrink: 0,
91
99
  gap: badgeWrapGap,
100
+ alignSelf: 'stretch',
92
101
  }
93
102
 
94
103
  const indicatorStyle: ViewStyle = {
@@ -103,6 +112,13 @@ export function Step({
103
112
  overflow: 'hidden',
104
113
  }
105
114
 
115
+ const stepStatusContainerStyle: ViewStyle = {
116
+ width: stepStatusSize,
117
+ height: stepStatusSize,
118
+ alignItems: 'center',
119
+ justifyContent: 'center',
120
+ }
121
+
106
122
  const labelStyle: TextStyle = {
107
123
  color: iconColor,
108
124
  fontSize: labelFontSize,
@@ -112,35 +128,31 @@ export function Step({
112
128
  textAlign: 'center',
113
129
  }
114
130
 
115
- // Combine base line style with injected connectorStyle
116
131
  const lineStyle: ViewStyle = {
117
132
  width: lineSize,
118
133
  backgroundColor: lineColor,
119
- flexGrow: 1, // Line should take up remaining vertical space in this column
120
- ...connectorStyle, // Allow overriding display, color, etc.
134
+ flexGrow: 1,
135
+ minHeight: 1,
136
+ ...connectorStyle,
121
137
  }
122
138
 
123
- // Helper for icons
124
139
  const renderIcon = () => {
125
140
  switch (status) {
126
141
  case 'complete':
127
- // Checkmark
128
142
  return (
129
- <Svg width={12} height={12} viewBox="0 0 24 24" fill="none">
143
+ <Svg width={stepStatusSize} height={stepStatusSize} viewBox="0 0 24 24" fill="none">
130
144
  <Path d="M20 6L9 17L4 12" stroke={iconColor} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
131
145
  </Svg>
132
146
  )
133
147
  case 'error':
134
- // X mark
135
148
  return (
136
- <Svg width={12} height={12} viewBox="0 0 24 24" fill="none">
149
+ <Svg width={stepStatusSize} height={stepStatusSize} viewBox="0 0 24 24" fill="none">
137
150
  <Path d="M18 6L6 18M6 6l12 12" stroke={iconColor} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
138
151
  </Svg>
139
152
  )
140
153
  case 'warning':
141
- // Exclamation / Triangle
142
154
  return (
143
- <Svg width={12} height={12} viewBox="0 0 24 24" fill="none">
155
+ <Svg width={stepStatusSize} height={stepStatusSize} viewBox="0 0 24 24" fill="none">
144
156
  <Path d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" stroke={iconColor} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" />
145
157
  </Svg>
146
158
  )
@@ -150,42 +162,31 @@ export function Step({
150
162
  }
151
163
  }
152
164
 
153
- // Clone children to pass modes if they are StepLabel
154
- const childrenWithProps = React.Children.map(children, (child) => {
155
- if (React.isValidElement(child)) {
156
- return React.cloneElement(child, { modes } as any)
157
- }
158
- return child
159
- })
160
-
161
- // Determine if we have content to pad
162
- // Default padding bottom to 16 if line is shown, but also respect connectorStyle display
163
- // If display is none, we probably don't want the padding bottom either.
164
- const isLineHidden = connectorStyle?.display === 'none'
165
- const contentPaddingBottom = isLineHidden ? 0 : 16
165
+ const hasSlotChildren = React.Children.count(children) > 0
166
166
 
167
167
  return (
168
168
  <View style={containerStyle}>
169
169
  <View style={indicatorWrapperStyle}>
170
170
  <View style={indicatorStyle}>
171
- {renderIcon()}
171
+ <View style={stepStatusContainerStyle}>{renderIcon()}</View>
172
172
  </View>
173
- <View style={lineStyle} />
173
+ {showLine ? <View style={lineStyle} /> : null}
174
174
  </View>
175
175
 
176
- {/* Spacer gap */}
177
- <View style={{ width: gap }} />
178
-
179
- {/* Content Area */}
180
- <View style={{ flex: 1, paddingBottom: contentPaddingBottom }}>
181
- {title ? (
176
+ <View style={{ flex: 1 }}>
177
+ {hasSlotChildren ? (
178
+ cloneChildrenWithModes(children, modes)
179
+ ) : (
182
180
  <StepLabel
183
- title={title}
184
- supportingText={subtitle ? (supportingText || undefined) : undefined}
181
+ {...(title !== undefined ? { title } : {})}
182
+ {...(supportingText !== undefined
183
+ ? { supportingText }
184
+ : {})}
185
+ {...(metaText !== undefined ? { metaText } : {})}
186
+ subtitle={subtitle}
187
+ meta={meta}
185
188
  modes={modes}
186
189
  />
187
- ) : (
188
- childrenWithProps
189
190
  )}
190
191
  </View>
191
192
  </View>
@@ -6,6 +6,9 @@ import { EMPTY_MODES } from '../../utils/react-utils'
6
6
  export type StepLabelProps = {
7
7
  title?: string
8
8
  supportingText?: string
9
+ metaText?: string
10
+ subtitle?: boolean
11
+ meta?: boolean
9
12
  modes?: Record<string, any>
10
13
  style?: ViewStyle
11
14
  }
@@ -13,10 +16,12 @@ export type StepLabelProps = {
13
16
  export function StepLabel({
14
17
  title = 'Stepper Item',
15
18
  supportingText,
19
+ metaText,
20
+ subtitle = true,
21
+ meta = true,
16
22
  modes = EMPTY_MODES,
17
23
  style,
18
24
  }: StepLabelProps) {
19
- // Title styles
20
25
  const titleColor =
21
26
  (getVariableByName('steperItem/title/color', modes) as string) || '#0d0d0f'
22
27
  const titleFontSize =
@@ -30,26 +35,46 @@ export function StepLabel({
30
35
  const titleFontWeight =
31
36
  (getVariableByName('steperItem/title/fontWeight', modes) as string) || '700'
32
37
 
33
- // Subtitle styles
38
+ // The Subtitle (supportingText) and Meta both default to the "Neutral"
39
+ // AppearanceBrand. A caller-supplied `AppearanceBrand` still wins (it is
40
+ // spread after the default), so each remains overridable. The Title keeps
41
+ // its own appearance resolution.
42
+ const subtitleModes = { AppearanceBrand: 'Neutral', ...modes }
43
+ const metaModes = { AppearanceBrand: 'Neutral', ...modes }
44
+
34
45
  const subtitleColor =
35
- (getVariableByName('steperItem/subtitle/color', modes) as string) ||
46
+ (getVariableByName('steperItem/subtitle/color', subtitleModes) as string) ||
36
47
  '#3d4047'
37
48
  const subtitleFontSize =
38
49
  Number(
39
- getVariableByName('steperItem/subtitle/fontSize', modes) as unknown
50
+ getVariableByName('steperItem/subtitle/fontSize', subtitleModes) as unknown
40
51
  ) || 12
41
52
  const subtitleFontFamily =
42
- (getVariableByName('steperItem/subtitle/fontFamily', modes) as string) ||
53
+ (getVariableByName('steperItem/subtitle/fontFamily', subtitleModes) as string) ||
43
54
  undefined
44
55
  const subtitleLineHeight =
45
56
  Number(
46
- getVariableByName('steperItem/subtitle/lineHeight', modes) as unknown
57
+ getVariableByName('steperItem/subtitle/lineHeight', subtitleModes) as unknown
47
58
  ) || 16
48
59
  const subtitleFontWeight =
49
- (getVariableByName('steperItem/subtitle/fontWeight', modes) as string) ||
60
+ (getVariableByName('steperItem/subtitle/fontWeight', subtitleModes) as string) ||
50
61
  '400'
51
62
 
52
- // Layout gap
63
+ const metaColor =
64
+ (getVariableByName('steperItem/meta/color', metaModes) as string) || '#f7ab21'
65
+ const metaFontSize =
66
+ Number(getVariableByName('steperItem/meta/fontSize', metaModes) as unknown) || 10
67
+ // The Figma variable is authored as "fontFamily Copy" (with a space + suffix).
68
+ // Match the literal Figma name to avoid a missing-variable warning.
69
+ const metaFontFamily =
70
+ (getVariableByName('steperItem/meta/fontFamily Copy', metaModes) as string) ||
71
+ undefined
72
+ const metaLineHeight =
73
+ Number(getVariableByName('steperItem/meta/lineHeight', metaModes) as unknown) ||
74
+ 12
75
+ const metaFontWeight =
76
+ (getVariableByName('steperItem/meta/fontWeight', metaModes) as string) || '700'
77
+
53
78
  const textGap =
54
79
  Number(getVariableByName('steperItem/textWrap/gap', modes) as unknown) || 2
55
80
 
@@ -69,12 +94,24 @@ export function StepLabel({
69
94
  lineHeight: subtitleLineHeight,
70
95
  }
71
96
 
97
+ const metaStyle: TextStyle = {
98
+ color: metaColor,
99
+ fontSize: metaFontSize,
100
+ fontFamily: metaFontFamily,
101
+ fontWeight: metaFontWeight as TextStyle['fontWeight'],
102
+ lineHeight: metaLineHeight,
103
+ }
104
+
105
+ const showSubtitle = subtitle && !!supportingText
106
+ const showMeta = meta && !!metaText
107
+
72
108
  return (
73
109
  <View style={[{ gap: textGap, flex: 1 }, style]}>
74
110
  <Text style={titleStyle}>{title}</Text>
75
- {supportingText ? (
111
+ {showSubtitle ? (
76
112
  <Text style={subtitleStyle}>{supportingText}</Text>
77
113
  ) : null}
114
+ {showMeta ? <Text style={metaStyle}>{metaText}</Text> : null}
78
115
  </View>
79
116
  )
80
117
  }
@@ -6,8 +6,10 @@ import { StepLabel } from './StepLabel'
6
6
  import { EMPTY_MODES } from '../../utils/react-utils'
7
7
 
8
8
  export { Step, StepLabel }
9
+ export type { StepProps, StepStatus } from './Step'
10
+ export type { StepLabelProps } from './StepLabel'
9
11
 
10
- type StepperProps = {
12
+ export type StepperProps = {
11
13
  children?: React.ReactNode
12
14
  modes?: Record<string, any>
13
15
  style?: ViewStyle
@@ -18,7 +20,6 @@ export default function Stepper({
18
20
  modes = EMPTY_MODES,
19
21
  style,
20
22
  }: StepperProps) {
21
- // Stepper container styles
22
23
  const paddingHorizontal =
23
24
  Number(getVariableByName('stepper/padding/horizontal', modes) as unknown) ||
24
25
  8
@@ -33,20 +34,24 @@ export default function Stepper({
33
34
  ...style,
34
35
  }
35
36
 
36
- // Inject index and connectorStyle logic into Step children
37
37
  const steps = React.Children.toArray(children)
38
- const childrenWithProps = steps.map((child, index) => {
39
- if (React.isValidElement(child)) {
40
- const isLast = index === steps.length - 1
41
-
42
- return React.cloneElement(child, {
43
- index,
44
- modes, // Pass modes down
45
- connectorStyle: isLast ? { display: 'none' } : undefined,
46
- } as any)
47
- }
48
- return child
38
+ const stepsWithProps = steps.map((child, stepIndex) => {
39
+ if (!React.isValidElement(child)) return child
40
+
41
+ const isLast = stepIndex === steps.length - 1
42
+ const childProps = (child.props as any) || {}
43
+ const childModes = childProps.modes
44
+ ? { ...modes, ...childProps.modes }
45
+ : modes
46
+
47
+ return React.cloneElement(child, {
48
+ ...childProps,
49
+ index: childProps.index ?? stepIndex,
50
+ modes: childModes,
51
+ showLine:
52
+ childProps.showLine !== undefined ? childProps.showLine : !isLast,
53
+ } as any)
49
54
  })
50
55
 
51
- return <View style={containerStyle}>{childrenWithProps}</View>
56
+ return <View style={containerStyle}>{stepsWithProps}</View>
52
57
  }